diff options
author | egraether@chromium.org <egraether@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-05 21:48:15 +0000 |
---|---|---|
committer | egraether@chromium.org <egraether@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-05 21:48:15 +0000 |
commit | af97816e82e643e37c69656f55b9cfd12ba72eec (patch) | |
tree | f5157391530df0862bde3481fbc1775179784da8 /cc | |
parent | 89e711aa9c8dc7e38e7e1712c9598cf9391ad800 (diff) | |
download | chromium_src-af97816e82e643e37c69656f55b9cfd12ba72eec.zip chromium_src-af97816e82e643e37c69656f55b9cfd12ba72eec.tar.gz chromium_src-af97816e82e643e37c69656f55b9cfd12ba72eec.tar.bz2 |
this change improves the following points of the FPS counter:
-cleaner design: less colors, text arranged above the graph, deviation number right aligned
-added transparency: FPS counter does not completely cover the webpage
-less frequent number updates: makes the numbers easier to read
-indicator line at 60fps
comparison images: https://docs.google.com/folder/d/0B8Y78t3tjy1XZk1xdWx6VjN5aFE/edit
Please download the patch and provide a screenshot from your system to test the layout.
Review URL: https://chromiumcodereview.appspot.com/11272042
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@166041 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc')
-rw-r--r-- | cc/font_atlas.cc | 19 | ||||
-rw-r--r-- | cc/font_atlas.h | 6 | ||||
-rw-r--r-- | cc/frame_rate_counter.cc | 46 | ||||
-rw-r--r-- | cc/frame_rate_counter.h | 5 | ||||
-rw-r--r-- | cc/heads_up_display_layer.cc | 4 | ||||
-rw-r--r-- | cc/heads_up_display_layer_impl.cc | 149 | ||||
-rw-r--r-- | cc/heads_up_display_layer_impl.h | 13 |
7 files changed, 152 insertions, 90 deletions
diff --git a/cc/font_atlas.cc b/cc/font_atlas.cc index 2d15766..099e7f0 100644 --- a/cc/font_atlas.cc +++ b/cc/font_atlas.cc @@ -57,6 +57,25 @@ void FontAtlas::drawOneLineOfTextInternal(SkCanvas* canvas, const SkPaint& paint } } +gfx::Size FontAtlas::textSize(const std::string& text) +{ + int maxWidth = 0; + std::vector<std::string> lines; + base::SplitString(text, '\n', &lines); + + for (size_t i = 0; i < lines.size(); ++i) { + int lineWidth = 0; + for (size_t j = 0; j < lines[i].size(); ++j) { + int asciiIndex = (lines[i][j] < 128) ? lines[i][j] : 0; + lineWidth += m_asciiToRectTable[asciiIndex].width(); + } + if (lineWidth > maxWidth) + maxWidth = lineWidth; + } + + return gfx::Size(maxWidth, m_fontHeight * lines.size()); +} + void FontAtlas::drawDebugAtlas(SkCanvas* canvas, const gfx::Point& destPosition) const { DCHECK(Proxy::isImplThread()); diff --git a/cc/font_atlas.h b/cc/font_atlas.h index 24592e4..d18483f 100644 --- a/cc/font_atlas.h +++ b/cc/font_atlas.h @@ -31,6 +31,9 @@ public: } ~FontAtlas(); + // Current font height. + int fontHeight() const { return m_fontHeight; } + // Draws multiple lines of text where each line of text is separated by '\n'. // - Correct glyphs will be drawn for ASCII codes in the range 32-127; any characters // outside that range will be displayed as a default rectangle glyph. @@ -39,6 +42,9 @@ public: // - Should only be called only on the impl thread. void drawText(SkCanvas*, const SkPaint&, const std::string& text, const gfx::Point& destPosition, const gfx::Size& clip) const; + // Gives a text's width and height on the canvas. + gfx::Size textSize(const std::string& text); + // Draws the entire atlas at the specified position, just for debugging purposes. void drawDebugAtlas(SkCanvas*, const gfx::Point& destPosition) const; diff --git a/cc/frame_rate_counter.cc b/cc/frame_rate_counter.cc index 585dee7..fca42a5 100644 --- a/cc/frame_rate_counter.cc +++ b/cc/frame_rate_counter.cc @@ -70,9 +70,10 @@ void FrameRateCounter::markEndOfFrame() bool FrameRateCounter::isBadFrameInterval(base::TimeDelta intervalBetweenConsecutiveFrames) const { + double delta = intervalBetweenConsecutiveFrames.InSecondsF(); bool schedulerAllowsDoubleFrames = !Proxy::hasImplThread(); - bool intervalTooFast = schedulerAllowsDoubleFrames && intervalBetweenConsecutiveFrames.InSecondsF() < kFrameTooFast; - bool intervalTooSlow = intervalBetweenConsecutiveFrames.InSecondsF() > kFrameTooSlow; + bool intervalTooFast = schedulerAllowsDoubleFrames ? delta < kFrameTooFast : delta <= 0.0; + bool intervalTooSlow = delta > kFrameTooSlow; return intervalTooFast || intervalTooSlow; } @@ -83,11 +84,13 @@ bool FrameRateCounter::isBadFrame(int frameNumber) const void FrameRateCounter::getAverageFPSAndStandardDeviation(double& averageFPS, double& standardDeviation) const { - int frame = m_currentFrameNumber - 1; - averageFPS = 0; - int averageFPSCount = 0; + int frameNumber = m_currentFrameNumber - 1; + int frameCount = 0; double fpsVarianceNumerator = 0; + averageFPS = 0; + standardDeviation = 0; + // Walk backwards through the samples looking for a run of good frame // timings from which to compute the mean and standard deviation. // @@ -98,32 +101,29 @@ void FrameRateCounter::getAverageFPSAndStandardDeviation(double& averageFPS, dou // too much for short lived animations. // // isBadFrame encapsulates the frame too slow/frame too fast logic. - while (1) { - if (!isBadFrame(frame)) { - averageFPSCount++; - base::TimeDelta secForLastFrame = m_timeStampHistory[frameIndex(frame)] - - m_timeStampHistory[frameIndex(frame - 1)]; - double x = 1.0 / secForLastFrame.InSecondsF(); + + // Go through all available historical data. + while (frameIndex(frameNumber) != frameIndex(m_currentFrameNumber) && frameNumber >= 0) { + base::TimeDelta delta = frameInterval(frameNumber); + + if (!isBadFrameInterval(delta)) { + frameCount++; + double x = 1.0 / delta.InSecondsF(); double deltaFromAverage = x - averageFPS; // Change with caution - numerics. http://en.wikipedia.org/wiki/Standard_deviation - averageFPS = averageFPS + deltaFromAverage / averageFPSCount; - fpsVarianceNumerator = fpsVarianceNumerator + deltaFromAverage * (x - averageFPS); - } - if (averageFPSCount && isBadFrame(frame)) { + averageFPS += deltaFromAverage / frameCount; + fpsVarianceNumerator += deltaFromAverage * (x - averageFPS); + } else if (frameCount) // We've gathered a run of good samples, so stop. break; - } - --frame; - if (frameIndex(frame) == frameIndex(m_currentFrameNumber) || frame < 0) { - // We've gone through all available historical data, so stop. - break; - } + frameNumber--; } - standardDeviation = sqrt(fpsVarianceNumerator / averageFPSCount); + if (frameCount) + standardDeviation = sqrt(fpsVarianceNumerator / frameCount); } -base::TimeTicks FrameRateCounter::timeStampOfRecentFrame(int n) +base::TimeTicks FrameRateCounter::timeStampOfRecentFrame(int n) const { DCHECK(n >= 0); DCHECK(n < kTimeStampHistorySize); diff --git a/cc/frame_rate_counter.h b/cc/frame_rate_counter.h index f9b770a..80697da 100644 --- a/cc/frame_rate_counter.h +++ b/cc/frame_rate_counter.h @@ -25,7 +25,8 @@ public: // n = 0 returns the oldest frame retained in the history, // while n = timeStampHistorySize() - 1 returns the timestamp most recent frame. - base::TimeTicks timeStampOfRecentFrame(int n); + // FIXME: Returns most recent timestamp for n = 0 when called between markBeginningOfFrame and markEndOfFrame calls. + base::TimeTicks timeStampOfRecentFrame(int n) const; // This is a heuristic that can be used to ignore frames in a reasonable way. Returns // true if the given frame interval is too fast or too slow, based on constant thresholds. @@ -51,7 +52,7 @@ private: // FIXME: Determine this threshold based on monitor refresh rate, crbug.com/138642. static const double kDroppedFrameTime; - static const int kTimeStampHistorySize = 120; + static const int kTimeStampHistorySize = 170; int m_currentFrameNumber; base::TimeTicks m_timeStampHistory[kTimeStampHistorySize]; diff --git a/cc/heads_up_display_layer.cc b/cc/heads_up_display_layer.cc index 0a9d47e..355c94d 100644 --- a/cc/heads_up_display_layer.cc +++ b/cc/heads_up_display_layer.cc @@ -21,7 +21,7 @@ HeadsUpDisplayLayer::HeadsUpDisplayLayer() : Layer() { - setBounds(gfx::Size(512, 128)); + setBounds(gfx::Size(256, 128)); } HeadsUpDisplayLayer::~HeadsUpDisplayLayer() @@ -39,7 +39,7 @@ void HeadsUpDisplayLayer::update(ResourceUpdateQueue&, const OcclusionTracker*, int height = std::min(maxTextureSize, layerTreeHost()->deviceViewportSize().height()); bounds = gfx::Size(width, height); } else { - bounds = gfx::Size(512, 128); + bounds = gfx::Size(256, 128); } setBounds(bounds); diff --git a/cc/heads_up_display_layer_impl.cc b/cc/heads_up_display_layer_impl.cc index a30cfc5..4444c9b 100644 --- a/cc/heads_up_display_layer_impl.cc +++ b/cc/heads_up_display_layer_impl.cc @@ -21,6 +21,7 @@ #include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/effects/SkColorMatrixFilter.h" #include "ui/gfx/point.h" +#include "ui/gfx/size.h" namespace cc { @@ -43,6 +44,8 @@ static inline SkPaint createPaint() HeadsUpDisplayLayerImpl::HeadsUpDisplayLayerImpl(int id) : LayerImpl(id) + , m_averageFPS(0) + , m_stdDeviation(0) { } @@ -143,17 +146,10 @@ void HeadsUpDisplayLayerImpl::drawHudContents(SkCanvas* canvas) canvas->drawRect(SkRect::MakeXYWH(0, 0, bounds().width(), bounds().height()), paint); } - int fpsCounterHeight = 40; - int fpsCounterTop = 2; - int platformLayerTreeTop; + int platformLayerTreeTop = 0; if (settings.showFPSCounter) - platformLayerTreeTop = fpsCounterTop + fpsCounterHeight; - else - platformLayerTreeTop = 0; - - if (settings.showFPSCounter) - drawFPSCounter(canvas, layerTreeHostImpl()->fpsCounter(), fpsCounterTop, fpsCounterHeight); + platformLayerTreeTop = drawFPSCounter(canvas, layerTreeHostImpl()->fpsCounter()); if (settings.showPlatformLayerTree && m_fontAtlas.get()) { std::string layerTree = layerTreeHostImpl()->layerTreeAsText(); @@ -164,77 +160,108 @@ void HeadsUpDisplayLayerImpl::drawHudContents(SkCanvas* canvas) drawDebugRects(canvas, layerTreeHostImpl()->debugRectHistory()); } -void HeadsUpDisplayLayerImpl::drawFPSCounter(SkCanvas* canvas, FrameRateCounter* fpsCounter, int top, int height) +int HeadsUpDisplayLayerImpl::drawFPSCounter(SkCanvas* canvas, FrameRateCounter* fpsCounter) { - float textWidth = 170; // so text fits on linux. - float graphWidth = fpsCounter->timeStampHistorySize(); + const int left = 2; + const int top = 2; - // Draw the FPS text. - drawFPSCounterText(canvas, fpsCounter, top, textWidth, height); + const int padding = 4; - // Draw FPS graph. + const int fontHeight = m_fontAtlas.get() ? m_fontAtlas->fontHeight() : 0; + const int graphWidth = fpsCounter->timeStampHistorySize() - 3; + const int graphHeight = 40; + + const int width = graphWidth + 2 * padding; + const int height = fontHeight + graphHeight + 4 * padding + 2; + + SkPaint paint = createPaint(); + + // Draw background. + paint.setColor(SkColorSetARGB(215, 17, 17, 17)); + canvas->drawRect(SkRect::MakeXYWH(left, top, width, height), paint); + + SkRect textBounds = SkRect::MakeXYWH(left + padding, top + padding, graphWidth, fontHeight); + SkRect graphBounds = SkRect::MakeXYWH(left + padding, textBounds.bottom() + 2 * padding, graphWidth, graphHeight); + + drawFPSCounterText(canvas, paint, fpsCounter, textBounds); + drawFPSCounterGraph(canvas, paint, fpsCounter, graphBounds); + + return top + height; +} + +void HeadsUpDisplayLayerImpl::drawFPSCounterText(SkCanvas* canvas, SkPaint& paint, FrameRateCounter* fpsCounter, SkRect bounds) +{ + // Update FPS text - not every frame so text is readable + if (base::TimeDelta(fpsCounter->timeStampOfRecentFrame(0) - textUpdateTime).InSecondsF() > 0.25) { + fpsCounter->getAverageFPSAndStandardDeviation(m_averageFPS, m_stdDeviation); + textUpdateTime = fpsCounter->timeStampOfRecentFrame(0); + } + + // Draw FPS text. + if (m_fontAtlas.get()) { + std::string fpsText = base::StringPrintf("FPS:%5.1f", m_averageFPS); + std::string deviationText = base::StringPrintf("+/-%4.1f", m_stdDeviation); + + int deviationWidth = m_fontAtlas->textSize(deviationText).width(); + gfx::Size textArea(bounds.width(), bounds.height()); + + paint.setColor(SK_ColorRED); + m_fontAtlas->drawText(canvas, paint, fpsText, gfx::Point(bounds.left(), bounds.top()), textArea); + m_fontAtlas->drawText(canvas, paint, deviationText, gfx::Point(bounds.right() - deviationWidth, bounds.top()), textArea); + } +} + +void HeadsUpDisplayLayerImpl::drawFPSCounterGraph(SkCanvas* canvas, SkPaint& paint, FrameRateCounter* fpsCounter, SkRect bounds) +{ const double loFPS = 0; const double hiFPS = 80; - SkPaint paint = createPaint(); - paint.setColor(SkColorSetRGB(154, 205, 50)); - canvas->drawRect(SkRect::MakeXYWH(2 + textWidth, top, graphWidth, height / 2), paint); - paint.setColor(SkColorSetRGB(255, 250, 205)); - canvas->drawRect(SkRect::MakeXYWH(2 + textWidth, top + height / 2, graphWidth, height / 2), paint); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(1); + + // Draw top and bottom line. + paint.setColor(SkColorSetRGB(150, 150, 150)); + canvas->drawLine(bounds.left(), bounds.top() - 1, bounds.right(), bounds.top() - 1, paint); + canvas->drawLine(bounds.left(), bounds.bottom(), bounds.right(), bounds.bottom(), paint); - int graphLeft = static_cast<int>(textWidth + 3); + // Draw 60fps line. + paint.setColor(SkColorSetRGB(100, 100, 100)); + canvas->drawLine(bounds.left(), bounds.top() + bounds.height() / 4, bounds.right(), bounds.top() + bounds.height() / 4, paint); + + // Draw FPS graph. int x = 0; - double h = static_cast<double>(height - 2); SkPath path; - for (int i = 0; i < fpsCounter->timeStampHistorySize() - 1; ++i) { - int j = i + 1; - base::TimeDelta delta = fpsCounter->timeStampOfRecentFrame(j) - fpsCounter->timeStampOfRecentFrame(i); + + for (int i = 1; i < fpsCounter->timeStampHistorySize() - 1; ++i) { + base::TimeDelta delta = fpsCounter->timeStampOfRecentFrame(i + 1) - fpsCounter->timeStampOfRecentFrame(i); // Skip plotting this particular instantaneous frame rate if it is not likely to have been valid. - if (fpsCounter->isBadFrameInterval(delta)) { - x += 1; - continue; + if (!fpsCounter->isBadFrameInterval(delta)) { + double fps = 1.0 / delta.InSecondsF(); + + // Clamp the FPS to the range we want to plot visually. + double p = 1 - ((fps - loFPS) / (hiFPS - loFPS)); + if (p < 0) + p = 0; + if (p > 1) + p = 1; + + // Plot this data point. + SkPoint cur = SkPoint::Make(bounds.left() + x, bounds.top() + p * bounds.height()); + if (path.isEmpty()) + path.moveTo(cur); + else + path.lineTo(cur); } - double fps = 1.0 / delta.InSecondsF(); - - // Clamp the FPS to the range we want to plot visually. - double p = 1 - ((fps - loFPS) / (hiFPS - loFPS)); - if (p < 0) - p = 0; - if (p > 1) - p = 1; - - // Plot this data point. - SkPoint cur = SkPoint::Make(graphLeft + x, 1 + top + p*h); - if (path.isEmpty()) - path.moveTo(cur); - else - path.lineTo(cur); x += 1; } - paint.setColor(SK_ColorRED); - paint.setStyle(SkPaint::kStroke_Style); - paint.setStrokeWidth(1); + paint.setAntiAlias(true); + paint.setColor(SK_ColorRED); canvas->drawPath(path, paint); } -void HeadsUpDisplayLayerImpl::drawFPSCounterText(SkCanvas* canvas, FrameRateCounter* fpsCounter, int top, int width, int height) -{ - double averageFPS, stdDeviation; - fpsCounter->getAverageFPSAndStandardDeviation(averageFPS, stdDeviation); - - // Draw background. - SkPaint paint = createPaint(); - paint.setColor(SK_ColorBLACK); - canvas->drawRect(SkRect::MakeXYWH(2, top, width, height), paint); - - // Draw FPS text. - if (m_fontAtlas.get()) - m_fontAtlas->drawText(canvas, createPaint(), base::StringPrintf("FPS: %4.1f +/- %3.1f", averageFPS, stdDeviation), gfx::Point(10, height / 3), gfx::Size(width, height)); -} - void HeadsUpDisplayLayerImpl::drawDebugRects(SkCanvas* canvas, DebugRectHistory* debugRectHistory) { const std::vector<DebugRect>& debugRects = debugRectHistory->debugRects(); diff --git a/cc/heads_up_display_layer_impl.h b/cc/heads_up_display_layer_impl.h index bcca767..3276293 100644 --- a/cc/heads_up_display_layer_impl.h +++ b/cc/heads_up_display_layer_impl.h @@ -6,12 +6,15 @@ #define CC_HEADS_UP_DISPLAY_LAYER_IMPL_H_ #include "base/memory/scoped_ptr.h" +#include "base/time.h" #include "cc/cc_export.h" #include "cc/font_atlas.h" #include "cc/layer_impl.h" #include "cc/scoped_texture.h" class SkCanvas; +class SkPaint; +struct SkRect; namespace cc { @@ -44,13 +47,19 @@ private: virtual const char* layerTypeAsString() const OVERRIDE; void drawHudContents(SkCanvas*); - void drawFPSCounter(SkCanvas*, FrameRateCounter*, int top, int height); - void drawFPSCounterText(SkCanvas*, FrameRateCounter*, int top, int width, int height); + int drawFPSCounter(SkCanvas*, FrameRateCounter*); + void drawFPSCounterText(SkCanvas*, SkPaint&, FrameRateCounter*, SkRect); + void drawFPSCounterGraph(SkCanvas*, SkPaint&, FrameRateCounter*, SkRect); void drawDebugRects(SkCanvas*, DebugRectHistory*); scoped_ptr<FontAtlas> m_fontAtlas; scoped_ptr<ScopedTexture> m_hudTexture; scoped_ptr<SkCanvas> m_hudCanvas; + + double m_averageFPS; + double m_stdDeviation; + + base::TimeTicks textUpdateTime; }; } // namespace cc |