| Index: cc/heads_up_display_layer_impl.cc
|
| diff --git a/cc/heads_up_display_layer_impl.cc b/cc/heads_up_display_layer_impl.cc
|
| index 190229667783378229e0a45590080b10a1e87b2a..fe89e66f83e9dfee3a1e9ba527f8ca88953e3750 100644
|
| --- a/cc/heads_up_display_layer_impl.cc
|
| +++ b/cc/heads_up_display_layer_impl.cc
|
| @@ -4,14 +4,13 @@
|
|
|
| #include "cc/heads_up_display_layer_impl.h"
|
|
|
| -#include <limits>
|
| -
|
| #include "base/stringprintf.h"
|
| #include "cc/debug_colors.h"
|
| #include "cc/debug_rect_history.h"
|
| #include "cc/font_atlas.h"
|
| #include "cc/frame_rate_counter.h"
|
| #include "cc/layer_tree_impl.h"
|
| +#include "cc/paint_time_counter.h"
|
| #include "cc/quad_sink.h"
|
| #include "cc/renderer.h"
|
| #include "cc/texture_draw_quad.h"
|
| @@ -48,11 +47,27 @@ static inline SkPaint createPaint()
|
| return paint;
|
| }
|
|
|
| +HeadsUpDisplayLayerImpl::Graph::Graph(double indicatorValue, double startUpperBound)
|
| + : value(0)
|
| + , min(0)
|
| + , max(0)
|
| + , currentUpperBound(startUpperBound)
|
| + , defaultUpperBound(startUpperBound)
|
| + , indicator(indicatorValue)
|
| +{
|
| +}
|
| +
|
| +double HeadsUpDisplayLayerImpl::Graph::updateUpperBound(Graph* graph)
|
| +{
|
| + double targetUpperBound = std::max(graph->max, graph->defaultUpperBound);
|
| + graph->currentUpperBound += (targetUpperBound - graph->currentUpperBound) * 0.5;
|
| + return graph->currentUpperBound;
|
| +}
|
| +
|
| HeadsUpDisplayLayerImpl::HeadsUpDisplayLayerImpl(LayerTreeImpl* treeImpl, int id)
|
| : LayerImpl(treeImpl, id)
|
| - , m_averageFPS(0)
|
| - , m_minFPS(0)
|
| - , m_maxFPS(0)
|
| + , m_fpsGraph(60.0, 80.0)
|
| + , m_paintTimeGraph(16.0, 48.0)
|
| {
|
| }
|
|
|
| @@ -158,34 +173,98 @@ void HeadsUpDisplayLayerImpl::drawHudContents(SkCanvas* canvas)
|
| {
|
| const LayerTreeDebugState& debugState = layerTreeImpl()->debug_state();
|
|
|
| + FrameRateCounter* fpsCounter = layerTreeImpl()->frame_rate_counter();
|
| + PaintTimeCounter* paintTimeCounter = layerTreeImpl()->paint_time_counter();
|
| +
|
| if (debugState.showPlatformLayerTree) {
|
| SkPaint paint = createPaint();
|
| - paint.setColor(SkColorSetARGB(192, 0, 0, 0));
|
| - canvas->drawRect(SkRect::MakeXYWH(0, 0, bounds().width(), bounds().height()), paint);
|
| + drawGraphBackground(canvas, &paint, SkRect::MakeXYWH(0, 0, bounds().width(), bounds().height()));
|
| }
|
|
|
| - int platformLayerTreeTop = 0;
|
| + int top = 2;
|
| +
|
| + if (debugState.continuousPainting || debugState.showFPSCounter) {
|
| + // Update numbers not every frame so text is readable
|
| + base::TimeTicks now = base::TimeTicks::Now();
|
| + if (base::TimeDelta(now - m_timeOfLastGraphUpdate).InSecondsF() > 0.25) {
|
| + m_fpsGraph.value = fpsCounter->getAverageFPS();
|
| + fpsCounter->getMinAndMaxFPS(m_fpsGraph.min, m_fpsGraph.max);
|
| +
|
| + base::TimeDelta latest, min, max;
|
| + latest = paintTimeCounter->GetPaintTimeOfRecentFrame(paintTimeCounter->HistorySize() - 1);
|
| + paintTimeCounter->GetMinAndMaxPaintTime(&min, &max);
|
|
|
| - if (debugState.showFPSCounter)
|
| - platformLayerTreeTop = drawFPSCounter(canvas, layerTreeImpl()->frame_rate_counter());
|
| + m_paintTimeGraph.value = latest.InMillisecondsF();
|
| + m_paintTimeGraph.min = min.InMillisecondsF();
|
| + m_paintTimeGraph.max = max.InMillisecondsF();
|
| +
|
| + m_timeOfLastGraphUpdate = now;
|
| + }
|
| +
|
| + if (debugState.continuousPainting)
|
| + top = drawPaintTimeDisplay(canvas, paintTimeCounter, top);
|
| + // Don't show the FPS display when continuous painting is enabled, because it would show misleading numbers.
|
| + else if (debugState.showFPSCounter)
|
| + top = drawFPSDisplay(canvas, fpsCounter, top);
|
| + }
|
|
|
| if (debugState.showPlatformLayerTree && m_fontAtlas) {
|
| std::string layerTree = layerTreeImpl()->layer_tree_as_text();
|
| - m_fontAtlas->drawText(canvas, createPaint(), layerTree, gfx::Point(2, platformLayerTreeTop), bounds());
|
| + m_fontAtlas->drawText(canvas, createPaint(), layerTree, gfx::Point(2, top), bounds());
|
| }
|
|
|
| if (debugState.showHudRects())
|
| drawDebugRects(canvas, layerTreeImpl()->debug_rect_history());
|
| }
|
|
|
| -int HeadsUpDisplayLayerImpl::drawFPSCounter(SkCanvas* canvas, FrameRateCounter* fpsCounter)
|
| +void HeadsUpDisplayLayerImpl::drawTextLeftAligned(SkCanvas* canvas, SkPaint* paint, const SkRect& bounds, const std::string& text)
|
| +{
|
| + if (!m_fontAtlas)
|
| + return;
|
| +
|
| + m_fontAtlas->drawText(canvas, *paint, text, gfx::Point(bounds.left(), bounds.top()), gfx::Size(bounds.width(), bounds.height()));
|
| +}
|
| +
|
| +void HeadsUpDisplayLayerImpl::drawTextRightAligned(SkCanvas* canvas, SkPaint* paint, const SkRect& bounds, const std::string& text)
|
| +{
|
| + if (!m_fontAtlas)
|
| + return;
|
| +
|
| + int textWidth = m_fontAtlas->textSize(text).width();
|
| +
|
| + gfx::Point textPosition(bounds.right() - textWidth, bounds.top());
|
| + gfx::Size textArea(bounds.width(), bounds.height());
|
| +
|
| + m_fontAtlas->drawText(canvas, *paint, text, textPosition, textArea);
|
| +}
|
| +
|
| +void HeadsUpDisplayLayerImpl::drawGraphBackground(SkCanvas* canvas, SkPaint* paint, const SkRect& bounds)
|
| +{
|
| + paint->setColor(SkColorSetARGB(215, 17, 17, 17));
|
| + canvas->drawRect(bounds, *paint);
|
| +}
|
| +
|
| +void HeadsUpDisplayLayerImpl::drawGraphLines(SkCanvas* canvas, SkPaint* paint, const SkRect& bounds, const Graph& graph)
|
| +{
|
| + // Draw top and bottom line.
|
| + paint->setColor(SkColorSetRGB(130, 130, 130));
|
| + canvas->drawLine(bounds.left(), bounds.top() - 1, bounds.right(), bounds.top() - 1, *paint);
|
| + canvas->drawLine(bounds.left(), bounds.bottom(), bounds.right(), bounds.bottom(), *paint);
|
| +
|
| + // Draw indicator line.
|
| + paint->setColor(SkColorSetRGB(100, 100, 100));
|
| + const double indicatorTop = bounds.height() * (1 - graph.indicator / graph.currentUpperBound) - 1;
|
| + canvas->drawLine(bounds.left(), bounds.top() + indicatorTop, bounds.right(), bounds.top() + indicatorTop, *paint);
|
| +}
|
| +
|
| +int HeadsUpDisplayLayerImpl::drawFPSDisplay(SkCanvas* canvas, FrameRateCounter* fpsCounter, const int& top)
|
| {
|
| const int padding = 4;
|
| const int gap = 6;
|
|
|
| const int fontHeight = m_fontAtlas.get() ? m_fontAtlas->fontHeight() : 0;
|
|
|
| - const int graphWidth = fpsCounter->timeStampHistorySize() - 3;
|
| + const int graphWidth = fpsCounter->timeStampHistorySize() - 2;
|
| const int graphHeight = 40;
|
|
|
| const int histogramWidth = 37;
|
| @@ -194,74 +273,29 @@ int HeadsUpDisplayLayerImpl::drawFPSCounter(SkCanvas* canvas, FrameRateCounter*
|
| const int height = fontHeight + graphHeight + 4 * padding + 2;
|
|
|
| const int left = bounds().width() - width - 2;
|
| - const int top = 2;
|
|
|
| SkPaint paint = createPaint();
|
| -
|
| - // Draw background.
|
| - paint.setColor(SkColorSetARGB(215, 17, 17, 17));
|
| - canvas->drawRect(SkRect::MakeXYWH(left, top, width, height), paint);
|
| + drawGraphBackground(canvas, &paint, SkRect::MakeXYWH(left, top, width, height));
|
|
|
| SkRect textBounds = SkRect::MakeXYWH(left + padding, top + padding, graphWidth + histogramWidth + gap + 2, fontHeight);
|
| SkRect graphBounds = SkRect::MakeXYWH(left + padding, textBounds.bottom() + 2 * padding, graphWidth, graphHeight);
|
| SkRect histogramBounds = SkRect::MakeXYWH(graphBounds.right() + gap, graphBounds.top(), histogramWidth, graphHeight);
|
|
|
| - drawFPSCounterText(canvas, paint, fpsCounter, textBounds);
|
| - drawFPSCounterGraphAndHistogram(canvas, paint, fpsCounter, graphBounds, histogramBounds);
|
| + drawTextLeftAligned(canvas, &paint, textBounds, base::StringPrintf("FPS:%5.1f", m_fpsGraph.value));
|
| + drawTextRightAligned(canvas, &paint, textBounds, base::StringPrintf("%.0f-%.0f", m_fpsGraph.min, m_fpsGraph.max));
|
|
|
| - return top + height;
|
| -}
|
| -
|
| -void HeadsUpDisplayLayerImpl::drawFPSCounterText(SkCanvas* canvas, SkPaint& paint, FrameRateCounter* fpsCounter, SkRect bounds)
|
| -{
|
| - // Update FPS text - not every frame so text is readable
|
| - base::TimeTicks now = base::TimeTicks::Now();
|
| - if (base::TimeDelta(now - textUpdateTime).InSecondsF() > 0.25) {
|
| - m_averageFPS = fpsCounter->getAverageFPS();
|
| - textUpdateTime = now;
|
| - }
|
| -
|
| - // Draw FPS text.
|
| - if (m_fontAtlas.get()) {
|
| - std::string fpsText = base::StringPrintf("FPS:%5.1f", m_averageFPS);
|
| - std::string minMaxText = base::StringPrintf("%.0f-%.0f", std::min( m_minFPS, m_maxFPS), m_maxFPS);
|
| -
|
| - int minMaxWidth = m_fontAtlas->textSize(minMaxText).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, minMaxText, gfx::Point(bounds.right() - minMaxWidth, bounds.top()), textArea);
|
| - }
|
| -}
|
| -
|
| -void HeadsUpDisplayLayerImpl::drawFPSCounterGraphAndHistogram(SkCanvas* canvas, SkPaint& paint, FrameRateCounter* fpsCounter, SkRect graphBounds, SkRect histogramBounds)
|
| -{
|
| - const double loFPS = 0;
|
| - const double hiFPS = std::max(m_maxFPS + 10.0, 80.0);
|
| -
|
| - // Draw top and bottom line.
|
| - paint.setColor(SkColorSetRGB(130, 130, 130));
|
| - canvas->drawLine(graphBounds.left(), graphBounds.top() - 1, graphBounds.right(), graphBounds.top() - 1, paint);
|
| - canvas->drawLine(graphBounds.left(), graphBounds.bottom(), graphBounds.right(), graphBounds.bottom(), paint);
|
| -
|
| - // Draw 60fps line.
|
| - const double top60 = graphBounds.top() + graphBounds.height() * (1 - ((60 - loFPS) / (hiFPS - loFPS))) - 1;
|
| - paint.setColor(SkColorSetRGB(100, 100, 100));
|
| - canvas->drawLine(graphBounds.left(), top60, graphBounds.right(), top60, paint);
|
| + const double upperBound = Graph::updateUpperBound(&m_fpsGraph);
|
| + drawGraphLines(canvas, &paint, graphBounds, m_fpsGraph);
|
|
|
| // Collect graph and histogram data.
|
| int x = 0;
|
| SkPath path;
|
|
|
| - m_minFPS = std::numeric_limits<double>::max();
|
| - m_maxFPS = 0;
|
| -
|
| const int histogramSize = 20;
|
| double histogram[histogramSize] = {0};
|
| double maxBucketValue = 0;
|
|
|
| - for (size_t i = 1; i < fpsCounter->timeStampHistorySize() - 1; ++i) {
|
| + for (size_t i = 0; i < fpsCounter->timeStampHistorySize() - 1; ++i) {
|
| base::TimeDelta delta = fpsCounter->timeStampOfRecentFrame(i + 1) - fpsCounter->timeStampOfRecentFrame(i);
|
|
|
| // Skip this particular instantaneous frame rate if it is not likely to have been valid.
|
| @@ -269,13 +303,8 @@ void HeadsUpDisplayLayerImpl::drawFPSCounterGraphAndHistogram(SkCanvas* canvas,
|
|
|
| double fps = 1.0 / delta.InSecondsF();
|
|
|
| - m_minFPS = std::min(fps, m_minFPS);
|
| - m_maxFPS = std::max(fps, m_maxFPS);
|
| -
|
| // Clamp the FPS to the range we want to plot visually.
|
| - double p = (fps - loFPS) / (hiFPS - loFPS);
|
| - if (p < 0)
|
| - p = 0;
|
| + double p = fps / upperBound;
|
| if (p > 1)
|
| p = 1;
|
|
|
| @@ -318,6 +347,53 @@ void HeadsUpDisplayLayerImpl::drawFPSCounterGraphAndHistogram(SkCanvas* canvas,
|
| paint.setStrokeWidth(1);
|
|
|
| canvas->drawPath(path, paint);
|
| +
|
| + return top + height + 2;
|
| +}
|
| +
|
| +int HeadsUpDisplayLayerImpl::drawPaintTimeDisplay(SkCanvas* canvas, PaintTimeCounter* paintTimeCounter, const int& top)
|
| +{
|
| + const int padding = 4;
|
| + const int fontHeight = m_fontAtlas.get() ? m_fontAtlas->fontHeight() : 0;
|
| +
|
| + const int graphWidth = paintTimeCounter->HistorySize() * 2 - 1;
|
| + const int graphHeight = 40;
|
| +
|
| + const int width = graphWidth + 2 * padding;
|
| + const int height = fontHeight + graphHeight + 4 * padding + 2 + fontHeight + padding;
|
| +
|
| + const int left = bounds().width() - width - 2;
|
| +
|
| + SkPaint paint = createPaint();
|
| + drawGraphBackground(canvas, &paint, SkRect::MakeXYWH(left, top, width, height));
|
| +
|
| + SkRect textBounds = SkRect::MakeXYWH(left + padding, top + padding, graphWidth, fontHeight);
|
| + SkRect textBounds2 = SkRect::MakeXYWH(left + padding, textBounds.bottom() + padding, graphWidth, fontHeight);
|
| + SkRect graphBounds = SkRect::MakeXYWH(left + padding, textBounds2.bottom() + 2 * padding, graphWidth, graphHeight);
|
| +
|
| + drawTextLeftAligned(canvas, &paint, textBounds, "Page paint time (ms)");
|
| + drawTextLeftAligned(canvas, &paint, textBounds2, base::StringPrintf("%5.1f", m_paintTimeGraph.value));
|
| + drawTextRightAligned(canvas, &paint, textBounds2, base::StringPrintf("%.1f-%.1f", m_paintTimeGraph.min, m_paintTimeGraph.max));
|
| +
|
| + const double upperBound = Graph::updateUpperBound(&m_paintTimeGraph);
|
| + drawGraphLines(canvas, &paint, graphBounds, m_paintTimeGraph);
|
| +
|
| + // Same green as used for paint times in the WebInspector Timeline
|
| + paint.setColor(SkColorSetRGB(95, 160, 80));
|
| + for (size_t i = 0; i < paintTimeCounter->HistorySize(); ++i) {
|
| + double pt = paintTimeCounter->GetPaintTimeOfRecentFrame(i).InMillisecondsF();
|
| +
|
| + if (pt == 0.0)
|
| + continue;
|
| +
|
| + double p = pt / upperBound;
|
| + if (p > 1)
|
| + p = 1;
|
| +
|
| + canvas->drawRect(SkRect::MakeXYWH(graphBounds.left() + i * 2, graphBounds.bottom() - p * graphBounds.height(), 1, p * graphBounds.height()), paint);
|
| + }
|
| +
|
| + return top + height + 2;
|
| }
|
|
|
| void HeadsUpDisplayLayerImpl::drawDebugRects(SkCanvas* canvas, DebugRectHistory* debugRectHistory)
|
|
|