From 572664685b7ccf6c8e1fe2de8817a51c8c64b2c1 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Fri, 9 May 2014 09:50:00 -0400 Subject: [PATCH] Bug 990835 - Change Compositor FPS to be Histogram based. r=benwa --- gfx/layers/composite/FPSCounter.cpp | 449 ++++++++++++++++++ gfx/layers/composite/FPSCounter.h | 114 +++-- .../composite/LayerManagerComposite.cpp | 83 ---- gfx/layers/moz.build | 1 + gfx/thebes/gfxPrefs.h | 2 + 5 files changed, 522 insertions(+), 127 deletions(-) create mode 100644 gfx/layers/composite/FPSCounter.cpp diff --git a/gfx/layers/composite/FPSCounter.cpp b/gfx/layers/composite/FPSCounter.cpp new file mode 100644 index 00000000000..65bce155ec5 --- /dev/null +++ b/gfx/layers/composite/FPSCounter.cpp @@ -0,0 +1,449 @@ +/* -*- 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 // for size_t +#include "Units.h" // for ScreenIntRect +#include "gfxRect.h" // for gfxRect +#include "gfxPrefs.h" // for gfxPrefs +#include "mozilla/gfx/Point.h" // for IntSize, Point +#include "mozilla/gfx/Rect.h" // for Rect +#include "mozilla/gfx/Types.h" // for Color, SurfaceFormat +#include "mozilla/layers/Compositor.h" // for Compositor +#include "mozilla/layers/CompositorTypes.h" +#include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc +#include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration +#include "nsPoint.h" // for nsIntPoint +#include "nsRect.h" // for nsIntRect +#include "nsIFile.h" // for nsIFile +#include "nsDirectoryServiceDefs.h" // for NS_OS_TMP_DIR +#include "prprf.h" // for PR_snprintf +#include "FPSCounter.h" + +namespace mozilla { +namespace layers { + +using namespace mozilla::gfx; +using namespace mozilla::gl; + +FPSCounter::FPSCounter(const char* aName) + : mWriteIndex(0) + , mFPSName(aName) +{ + Init(); +} + +FPSCounter::~FPSCounter() { } + +void +FPSCounter::Init() +{ + for (int i = 0; i < kMaxFrames; i++) { + mFrameTimestamps.AppendElement(TimeStamp()); + } + mLastInterval = TimeStamp::Now(); +} + +// Returns true if we captured a full interval of data +bool +FPSCounter::CapturedFullInterval(TimeStamp aTimestamp) { + TimeDuration duration = aTimestamp - mLastInterval; + return duration.ToSecondsSigDigits() >= kFpsDumpInterval; +} + +void +FPSCounter::AddFrame(TimeStamp aTimestamp) { + NS_ASSERTION(mWriteIndex < kMaxFrames, "We probably have a bug with the circular buffer"); + NS_ASSERTION(mWriteIndex >= 0, "Circular Buffer index should never be negative"); + + int index = mWriteIndex++; + if (mWriteIndex == kMaxFrames) { + mWriteIndex = 0; + } + + mFrameTimestamps[index] = aTimestamp; + + if (CapturedFullInterval(aTimestamp)) { + PrintFPS(); + WriteFrameTimeStamps(); + mLastInterval = aTimestamp; + } +} + +double +FPSCounter::AddFrameAndGetFps(TimeStamp aTimestamp) { + AddFrame(aTimestamp); + return GetFPS(aTimestamp); +} + +int +FPSCounter::GetLatestReadIndex() +{ + if (mWriteIndex == 0) { + return kMaxFrames - 1; + } + + return mWriteIndex - 1; +} + +TimeStamp +FPSCounter::GetLatestTimeStamp() +{ + TimeStamp timestamp = mFrameTimestamps[GetLatestReadIndex()]; + MOZ_ASSERT(!timestamp.IsNull(), "Cannot use null timestamps"); + return timestamp; +} + +// Returns true if we iterated over a full interval of data +bool +FPSCounter::IteratedFullInterval(TimeStamp aTimestamp, double aDuration) { + MOZ_ASSERT(mIteratorIndex >= 0, "Cannot be negative"); + MOZ_ASSERT(mIteratorIndex < kMaxFrames, "Iterator index cannot be greater than kMaxFrames"); + + TimeStamp currentStamp = mFrameTimestamps[mIteratorIndex]; + TimeDuration duration = aTimestamp - currentStamp; + return duration.ToSecondsSigDigits() >= aDuration; +} + +void +FPSCounter::ResetReverseIterator() +{ + mIteratorIndex = GetLatestReadIndex(); +} + +/*** + * Returns true if we have another timestamp that is valid and + * is within the given duration that we're interested in. + * Duration is in seconds + */ +bool FPSCounter::HasNext(TimeStamp aTimestamp, double aDuration) +{ + // Order of evaluation here has to stay the same + // otherwise IteratedFullInterval reads from mFrameTimestamps which cannot + // be null + return (mIteratorIndex != mWriteIndex) // Didn't loop around the buffer + && !mFrameTimestamps[mIteratorIndex].IsNull() // valid data + && !IteratedFullInterval(aTimestamp, aDuration); +} + +TimeStamp +FPSCounter::GetNextTimeStamp() +{ + TimeStamp timestamp = mFrameTimestamps[mIteratorIndex--]; + MOZ_ASSERT(!timestamp.IsNull(), "Reading Invalid Timestamp Data"); + + if (mIteratorIndex == -1) { + mIteratorIndex = kMaxFrames - 1; + } + return timestamp; +} + +/** + * GetFPS calculates how many frames we've already composited from the current + * frame timestamp and we iterate from the latest timestamp we recorded, + * going back in time. When we hit a frame that is longer than the 1 second + * from the current composited frame, we return how many frames we've counted. + * Just a visualization: + * + * aTimestamp + * Frames: 1 2 3 4 5 6 7 8 9 10 11 12 + * Time --------------------------> + * + * GetFPS iterates from aTimestamp, which is the current frame. + * Then starting at frame 12, going back to frame 11, 10, etc, we calculate + * the duration of the recorded frame timestamp from aTimestamp. + * Once duration is greater than 1 second, we return how many frames + * we composited. + */ +double +FPSCounter::GetFPS(TimeStamp aTimestamp) +{ + int frameCount = 0; + int duration = 1.0; // Only care about the last 1s of data + + ResetReverseIterator(); + while (HasNext(aTimestamp, duration)) { + GetNextTimeStamp(); + frameCount++; + } + + return frameCount; +} + +// Iterate the same way we do in GetFPS() +int +FPSCounter::BuildHistogram(std::map& aFpsData) +{ + TimeStamp currentIntervalStart = GetLatestTimeStamp(); + TimeStamp currentTimeStamp = GetLatestTimeStamp(); + TimeStamp startTimeStamp = GetLatestTimeStamp(); + + int frameCount = 0; + int totalFrameCount = 0; + + ResetReverseIterator(); + while (HasNext(startTimeStamp)) { + currentTimeStamp = GetNextTimeStamp(); + TimeDuration interval = currentIntervalStart - currentTimeStamp; + + if (interval.ToSecondsSigDigits() >= 1.0 ) { + currentIntervalStart = currentTimeStamp; + aFpsData[frameCount]++; + frameCount = 0; + } + + frameCount++; + totalFrameCount++; + } + + TimeDuration totalTime = currentIntervalStart - currentTimeStamp; + printf_stderr("Discarded %d frames over %f ms in histogram for %s\n", + frameCount, totalTime.ToMilliseconds(), mFPSName); + return totalFrameCount; +} + +// Iterate the same way we do in GetFPS() +void +FPSCounter::WriteFrameTimeStamps(PRFileDesc* fd) +{ + const int bufferSize = 256; + char buffer[bufferSize]; + int writtenCount = PR_snprintf(buffer, bufferSize, "FPS Data for: %s\n", mFPSName); + MOZ_ASSERT(writtenCount >= 0); + PR_Write(fd, buffer, writtenCount); + + ResetReverseIterator(); + TimeStamp startTimeStamp = GetLatestTimeStamp(); + + MOZ_ASSERT(HasNext(startTimeStamp)); + TimeStamp previousSample = GetNextTimeStamp(); + + MOZ_ASSERT(HasNext(startTimeStamp)); + TimeStamp nextTimeStamp = GetNextTimeStamp(); + + while (HasNext(startTimeStamp)) { + TimeDuration duration = previousSample - nextTimeStamp; + writtenCount = PR_snprintf(buffer, bufferSize, "%f,\n", duration.ToMilliseconds()); + + MOZ_ASSERT(writtenCount >= 0); + PR_Write(fd, buffer, writtenCount); + + previousSample = nextTimeStamp; + nextTimeStamp = GetNextTimeStamp(); + } +} + +double +FPSCounter::GetMean(std::map aHistogram) +{ + double average = 0.0; + double samples = 0.0; + + for (std::map::iterator iter = aHistogram.begin(); + iter != aHistogram.end(); ++iter) + { + int fps = iter->first; + int count = iter->second; + + average += fps * count; + samples += count; + } + + return average / samples; +} + +double +FPSCounter::GetStdDev(std::map aHistogram) +{ + double sumOfDifferences = 0; + double average = GetMean(aHistogram); + double samples = 0.0; + + for (std::map::iterator iter = aHistogram.begin(); + iter != aHistogram.end(); ++iter) + { + int fps = iter->first; + int count = iter->second; + + double diff = ((double) fps) - average; + diff *= diff; + + for (int i = 0; i < count; i++) { + sumOfDifferences += diff; + } + samples += count; + } + + double stdDev = sumOfDifferences / samples; + return sqrt(stdDev); +} + +void +FPSCounter::PrintFPS() +{ + if (!gfxPrefs::FPSPrintHistogram()) { + return; + } + + std::map histogram; + int totalFrames = BuildHistogram(histogram); + + TimeDuration measurementInterval = mFrameTimestamps[GetLatestReadIndex()] - mLastInterval; + printf_stderr("FPS for %s. Total Frames: %d Time Interval: %f seconds\n", + mFPSName, totalFrames, measurementInterval.ToSecondsSigDigits()); + + PrintHistogram(histogram); +} + +void +FPSCounter::PrintHistogram(std::map& aHistogram) +{ + int length = 0; + const int kBufferLength = 512; + char buffer[kBufferLength]; + + for (std::map::iterator iter = aHistogram.begin(); + iter != aHistogram.end(); iter++) + { + int fps = iter->first; + int count = iter->second; + + length += PR_snprintf(buffer + length, kBufferLength - length, + "FPS: %d = %d. ", fps, count); + NS_ASSERTION(length >= kBufferLength, "Buffer overrun while printing FPS histogram."); + } + + printf_stderr("%s\n", buffer); + printf_stderr("Mean: %f , std dev %f\n", GetMean(aHistogram), GetStdDev(aHistogram)); +} + +// Write FPS timestamp data to a file only if +// draw-fps.write-to-file is true +nsresult +FPSCounter::WriteFrameTimeStamps() +{ + if (!gfxPrefs::WriteFPSToFile()) { + return NS_OK; + } + + MOZ_ASSERT(mWriteIndex == 0); + + nsCOMPtr resultFile; + nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(resultFile)); + NS_ENSURE_SUCCESS(rv, rv); + + if (!strncmp(mFPSName, "Compositor", strlen(mFPSName))) { + resultFile->Append(NS_LITERAL_STRING("fps.txt")); + } else { + resultFile->Append(NS_LITERAL_STRING("txn.txt")); + } + + PRFileDesc* fd = nullptr; + int mode = 644; + int openFlags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE; + rv = resultFile->OpenNSPRFileDesc(openFlags, mode, &fd); + NS_ENSURE_SUCCESS(rv, rv); + + WriteFrameTimeStamps(fd); + PR_Close(fd); + + nsAutoCString path; + rv = resultFile->GetNativePath(path); + NS_ENSURE_SUCCESS(rv, rv); + + printf_stderr("Wrote FPS data to file: %s\n", path.get()); + return NS_OK; +} + +FPSState::FPSState() + : mCompositionFps("Compositor") + , mTransactionFps("LayerTransactions") +{ +} + +// Size of the builtin font. +static const float FontHeight = 7.f; +static const float FontWidth = 4.f; +static const float FontStride = 4.f; + +// Scale the font when drawing it to the viewport for better readability. +static const float FontScaleX = 2.f; +static const float FontScaleY = 3.f; + +static void DrawDigits(unsigned int aValue, + int aOffsetX, int aOffsetY, + Compositor* aCompositor, + EffectChain& aEffectChain) +{ + if (aValue > 999) { + aValue = 999; + } + + unsigned int divisor = 100; + float textureWidth = FontWidth * 10; + gfx::Float opacity = 1; + gfx::Matrix4x4 transform; + transform.Scale(FontScaleX, FontScaleY, 1); + + for (size_t n = 0; n < 3; ++n) { + unsigned int digit = aValue % (divisor * 10) / divisor; + divisor /= 10; + + RefPtr texturedEffect = static_cast(aEffectChain.mPrimaryEffect.get()); + texturedEffect->mTextureCoords = Rect(float(digit * FontWidth) / textureWidth, 0, FontWidth / textureWidth, 1.0f); + + Rect drawRect = Rect(aOffsetX + n * FontWidth, aOffsetY, FontWidth, FontHeight); + Rect clipRect = Rect(0, 0, 300, 100); + aCompositor->DrawQuad(drawRect, clipRect, + aEffectChain, opacity, transform); + } +} + +void FPSState::DrawFPS(TimeStamp aNow, + int aOffsetX, int aOffsetY, + unsigned int aFillRatio, + Compositor* aCompositor) +{ + if (!mFPSTextureSource) { + const char *text = + " " + " XXX XX XXX XXX X X XXX XXX XXX XXX XXX" + " X X X X X X X X X X X X X X" + " X X X XXX XXX XXX XXX XXX X XXX XXX" + " X X X X X X X X X X X X X" + " XXX XXX XXX XXX X XXX XXX X XXX X" + " "; + + // Convert the text encoding above to RGBA. + int w = FontWidth * 10; + int h = FontHeight; + uint32_t* buf = (uint32_t *) malloc(w * h * sizeof(uint32_t)); + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + uint32_t purple = 0xfff000ff; + uint32_t white = 0xffffffff; + buf[i * w + j] = (text[i * w + j] == ' ') ? purple : white; + } + } + + int bytesPerPixel = 4; + RefPtr fpsSurface = Factory::CreateWrappingDataSourceSurface( + reinterpret_cast(buf), w * bytesPerPixel, IntSize(w, h), SurfaceFormat::B8G8R8A8); + mFPSTextureSource = aCompositor->CreateDataTextureSource(); + mFPSTextureSource->Update(fpsSurface); + } + + EffectChain effectChain; + effectChain.mPrimaryEffect = CreateTexturedEffect(SurfaceFormat::B8G8R8A8, mFPSTextureSource, Filter::POINT); + + unsigned int fps = unsigned(mCompositionFps.AddFrameAndGetFps(aNow)); + unsigned int txnFps = unsigned(mTransactionFps.GetFPS(aNow)); + + DrawDigits(fps, aOffsetX + 0, aOffsetY, aCompositor, effectChain); + DrawDigits(txnFps, aOffsetX + FontWidth * 4, aOffsetY, aCompositor, effectChain); + DrawDigits(aFillRatio, aOffsetX + FontWidth * 8, aOffsetY, aCompositor, effectChain); +} + +} // end namespace layers +} // end namespace mozilla diff --git a/gfx/layers/composite/FPSCounter.h b/gfx/layers/composite/FPSCounter.h index 7e82b31226d..17a409597c1 100644 --- a/gfx/layers/composite/FPSCounter.h +++ b/gfx/layers/composite/FPSCounter.h @@ -6,12 +6,15 @@ #ifndef mozilla_layers_opengl_FPSCounter_h_ #define mozilla_layers_opengl_FPSCounter_h_ -#include // for size_t #include // for min +#include // for size_t +#include // for std::map #include "GLDefs.h" // for GLuint +#include "mozilla/RefPtr.h" // for TemporaryRef, RefCounted #include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration #include "nsTArray.h" // for nsAutoTArray, nsTArray_Impl, etc #include "VBOArena.h" // for gl::VBOArena +#include "prio.h" // for NSPR file i/o namespace mozilla { namespace gl { @@ -21,68 +24,91 @@ namespace layers { class DataTextureSource; class ShaderProgramOGL; +class Compositor; -const double kFpsWindowMs = 250.0; -const size_t kNumFrameTimeStamps = 16; -struct FPSCounter { - FPSCounter() : mCurrentFrameIndex(0) { - mFrames.SetLength(kNumFrameTimeStamps); - } +// Dump the FPS histogram every 10 seconds or kMaxFrameFPS +const int kFpsDumpInterval = 10; - // We keep a circular buffer of the time points at which the last K - // frames were drawn. To estimate FPS, we count the number of - // frames we've drawn within the last kFPSWindowMs milliseconds and - // divide by the amount time since the first of those frames. - nsAutoTArray mFrames; - size_t mCurrentFrameIndex; +// On desktop, we can have 240 hz monitors, so 10 seconds +// times 240 frames = 2400 +const int kMaxFrames = 2400; - void AddFrame(TimeStamp aNewFrame) { - mFrames[mCurrentFrameIndex] = aNewFrame; - mCurrentFrameIndex = (mCurrentFrameIndex + 1) % kNumFrameTimeStamps; - } +/** + * The FPSCounter tracks how often we composite or have a layer transaction. + * At each composite / layer transaction, we record the timestamp. + * After kFpsDumpInterval number of composites / transactions, we calculate + * the average and standard deviation of frames composited. We dump a histogram, + * which allows for more statistically significant measurements. We also dump + * absolute frame composite times to a file on the device. + * The FPS counters displayed on screen are based on how many frames we + * composited within the last ~1 second. The more accurate measurement is to + * grab the histogram from stderr or grab the FPS timestamp dumps written to file. + * + * To enable dumping to file, enable + * layers.acceleration.draw-fps.write-to-file pref. double AddFrameAndGetFps(TimeStamp aCurrentFrame) { AddFrame(aCurrentFrame); return EstimateFps(aCurrentFrame); } + * To enable printing histogram data to logcat, + * enable layers.acceleration.draw-fps.print-histogram + * + * Use the HasNext(), GetNextTimeStamp() like an iterator to read the data, + * backwards in time. This abstracts away the mechanics of reading the data. + */ +class FPSCounter { +public: + FPSCounter(const char* aName); + ~FPSCounter(); - double GetFpsAt(TimeStamp aNow) { - return EstimateFps(aNow); - } + void AddFrame(TimeStamp aTimestamp); + double AddFrameAndGetFps(TimeStamp aTimestamp); + double GetFPS(TimeStamp aTimestamp); private: - double EstimateFps(TimeStamp aNow) { - TimeStamp beginningOfWindow = - (aNow - TimeDuration::FromMilliseconds(kFpsWindowMs)); - TimeStamp earliestFrameInWindow = aNow; - size_t numFramesDrawnInWindow = 0; - for (size_t i = 0; i < kNumFrameTimeStamps; ++i) { - const TimeStamp& frame = mFrames[i]; - if (!frame.IsNull() && frame > beginningOfWindow) { - ++numFramesDrawnInWindow; - earliestFrameInWindow = std::min(earliestFrameInWindow, frame); - } - } - double realWindowSecs = (aNow - earliestFrameInWindow).ToSeconds(); - if (realWindowSecs == 0.0 || numFramesDrawnInWindow == 1) { - return 0.0; - } - return double(numFramesDrawnInWindow - 1) / realWindowSecs; - } + void Init(); + bool CapturedFullInterval(TimeStamp aTimestamp); + + // Used while iterating backwards over the data + void ResetReverseIterator(); + bool HasNext(TimeStamp aTimestamp, double aDuration = kFpsDumpInterval); + TimeStamp GetNextTimeStamp(); + int GetLatestReadIndex(); + TimeStamp GetLatestTimeStamp(); + void WriteFrameTimeStamps(PRFileDesc* fd); + bool IteratedFullInterval(TimeStamp aTimestamp, double aDuration); + + void PrintFPS(); + int BuildHistogram(std::map& aHistogram); + void PrintHistogram(std::map& aHistogram); + double GetMean(std::map aHistogram); + double GetStdDev(std::map aHistogram); + nsresult WriteFrameTimeStamps(); + + /*** + * mFrameTimestamps is a psuedo circular buffer + * Since we have a constant write time and don't + * read at an offset except our latest write + * we don't need an explicit read pointer. + */ + nsAutoTArray mFrameTimestamps; + int mWriteIndex; // points to next open write slot + int mIteratorIndex; // used only when iterating + const char* mFPSName; + TimeStamp mLastInterval; }; struct FPSState { - FPSCounter mCompositionFps; - FPSCounter mTransactionFps; - - FPSState() {} - + FPSState(); void DrawFPS(TimeStamp, int offsetX, int offsetY, unsigned, Compositor* aCompositor); - void NotifyShadowTreeTransaction() { mTransactionFps.AddFrame(TimeStamp::Now()); } + FPSCounter mCompositionFps; + FPSCounter mTransactionFps; + private: RefPtr mFPSTextureSource; }; diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp index cfffd5dfc34..7a3ee30c525 100644 --- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -311,89 +311,6 @@ LayerManagerComposite::RootLayer() const return ToLayerComposite(mRoot); } -// Size of the builtin font. -static const float FontHeight = 7.f; -static const float FontWidth = 4.f; -static const float FontStride = 4.f; - -// Scale the font when drawing it to the viewport for better readability. -static const float FontScaleX = 2.f; -static const float FontScaleY = 3.f; - -static void DrawDigits(unsigned int aValue, - int aOffsetX, int aOffsetY, - Compositor* aCompositor, - EffectChain& aEffectChain) -{ - if (aValue > 999) { - aValue = 999; - } - - unsigned int divisor = 100; - float textureWidth = FontWidth * 10; - gfx::Float opacity = 1; - gfx::Matrix4x4 transform; - transform.Scale(FontScaleX, FontScaleY, 1); - - for (size_t n = 0; n < 3; ++n) { - unsigned int digit = aValue % (divisor * 10) / divisor; - divisor /= 10; - - RefPtr texturedEffect = static_cast(aEffectChain.mPrimaryEffect.get()); - texturedEffect->mTextureCoords = Rect(float(digit * FontWidth) / textureWidth, 0, FontWidth / textureWidth, 1.0f); - - Rect drawRect = Rect(aOffsetX + n * FontWidth, aOffsetY, FontWidth, FontHeight); - Rect clipRect = Rect(0, 0, 300, 100); - aCompositor->DrawQuad(drawRect, clipRect, - aEffectChain, opacity, transform); - } -} - -void FPSState::DrawFPS(TimeStamp aNow, - int aOffsetX, int aOffsetY, - unsigned int aFillRatio, - Compositor* aCompositor) -{ - if (!mFPSTextureSource) { - const char *text = - " " - " XXX XX XXX XXX X X XXX XXX XXX XXX XXX" - " X X X X X X X X X X X X X X" - " X X X XXX XXX XXX XXX XXX X XXX XXX" - " X X X X X X X X X X X X X" - " XXX XXX XXX XXX X XXX XXX X XXX X" - " "; - - // Convert the text encoding above to RGBA. - int w = FontWidth * 10; - int h = FontHeight; - uint32_t* buf = (uint32_t *) malloc(w * h * sizeof(uint32_t)); - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - uint32_t purple = 0xfff000ff; - uint32_t white = 0xffffffff; - buf[i * w + j] = (text[i * w + j] == ' ') ? purple : white; - } - } - - int bytesPerPixel = 4; - RefPtr fpsSurface = Factory::CreateWrappingDataSourceSurface( - reinterpret_cast(buf), w * bytesPerPixel, IntSize(w, h), SurfaceFormat::B8G8R8A8); - mFPSTextureSource = aCompositor->CreateDataTextureSource(); - mFPSTextureSource->Update(fpsSurface); - } - - EffectChain effectChain; - effectChain.mPrimaryEffect = CreateTexturedEffect(SurfaceFormat::B8G8R8A8, mFPSTextureSource, Filter::POINT); - - unsigned int fps = unsigned(mCompositionFps.AddFrameAndGetFps(aNow)); - unsigned int txnFps = unsigned(mTransactionFps.GetFpsAt(aNow)); - - DrawDigits(fps, aOffsetX + 0, aOffsetY, aCompositor, effectChain); - DrawDigits(txnFps, aOffsetX + FontWidth * 4, aOffsetY, aCompositor, effectChain); - DrawDigits(aFillRatio, aOffsetX + FontWidth * 8, aOffsetY, aCompositor, effectChain); -} - static uint16_t sFrameCount = 0; void LayerManagerComposite::RenderDebugOverlay(const Rect& aBounds) diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index 65482f1cdf0..78c8253dc61 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -262,6 +262,7 @@ UNIFIED_SOURCES += [ 'composite/CompositableHost.cpp', 'composite/ContainerLayerComposite.cpp', 'composite/ContentHost.cpp', + 'composite/FPSCounter.cpp', 'composite/ImageHost.cpp', 'composite/ImageLayerComposite.cpp', 'composite/LayerManagerComposite.cpp', diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index b10aca042fa..d796a1efbe7 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -158,6 +158,8 @@ private: DECL_GFX_PREF(Once, "layers.acceleration.disabled", LayersAccelerationDisabled, bool, false); DECL_GFX_PREF(Live, "layers.acceleration.draw-fps", LayersDrawFPS, bool, false); + DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.print-histogram", FPSPrintHistogram, bool, false); + DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.write-to-file", WriteFPSToFile, bool, false); DECL_GFX_PREF(Once, "layers.acceleration.force-enabled", LayersAccelerationForceEnabled, bool, false); #ifdef XP_WIN // On windows, ignore the preference value, forcing async video to false.