| Differences between
and this patch
- a/Source/WebCore/ChangeLog +34 lines
Lines 1-3 a/Source/WebCore/ChangeLog_sec1
1
2012-03-07  Alex Nicolaou  <anicolao@chromium.org>
2
3
        [chromium] When rendering goes idle, do not count that time against frame rate
4
        https://bugs.webkit.org/show_bug.cgi?id=73454
5
6
        The FPS counter had a few issues with its reporting. The first
7
        3 swapbuffers are non-blocking and create FPS rates that are
8
        unrealistically high, throwing off the moving averages and
9
        introducing false spikes into the FPS graph. There was also no
10
        way to monitor the smoothness of the animation, or to focus in
11
        on a particular animation or transition.
12
13
        This patch updates the FPS counter code so that bad data points
14
        are trimmed and not graphed; so that the graph itself is taller
15
        and more legible; so that there is a clear boundary between 40FPS
16
        and better; so that outlier data points are labelled with their
17
        frame rate so that you can see how slow the frame is that is
18
        causing the jank; and to keep statistics on frame rate between
19
        pauses in the activity in the UI so that you can trigger a
20
        transition and read off the average and standard deviation for
21
        that transition to judge it smooth enough or not.
22
23
24
        Reviewed by NOBODY (OOPS!).
25
26
        HUD is not testable in webkit.
27
28
        * platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp:
29
        (WebCore::CCHeadsUpDisplay::CCHeadsUpDisplay):
30
        (WebCore::CCHeadsUpDisplay::onFrameBegin):
31
        (WebCore::CCHeadsUpDisplay::drawHudContents):
32
        (WebCore::CCHeadsUpDisplay::drawFPSCounter):
33
        * platform/graphics/chromium/cc/CCHeadsUpDisplay.h:
34
1
2012-03-06  James Robinson  <jamesr@chromium.org>
35
2012-03-06  James Robinson  <jamesr@chromium.org>
2
36
3
        [chromium] Fix threaded compositing issues in WebGLLayerChromium (except for printing)
37
        [chromium] Fix threaded compositing issues in WebGLLayerChromium (except for printing)
- a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp -25 / +73 lines
Lines 50-56 using namespace std; a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp_sec1
50
50
51
CCHeadsUpDisplay::CCHeadsUpDisplay(LayerRendererChromium* owner)
51
CCHeadsUpDisplay::CCHeadsUpDisplay(LayerRendererChromium* owner)
52
    : m_currentFrameNumber(1)
52
    : m_currentFrameNumber(1)
53
    , m_filteredFrameTime(0)
53
    , m_averageFPS(0)
54
    , m_averageFPSCount(0)
55
    , m_fpsVarianceNumerator(0)
54
    , m_layerRenderer(owner)
56
    , m_layerRenderer(owner)
55
    , m_useMapSubForUploads(owner->contextSupportsMapSub())
57
    , m_useMapSubForUploads(owner->contextSupportsMapSub())
56
{
58
{
Lines 61-67 CCHeadsUpDisplay::CCHeadsUpDisplay(LayerRendererChromium* owner) a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp_sec2
61
63
62
    FontDescription mediumFontDesc;
64
    FontDescription mediumFontDesc;
63
    mediumFontDesc.setGenericFamily(FontDescription::MonospaceFamily);
65
    mediumFontDesc.setGenericFamily(FontDescription::MonospaceFamily);
64
    mediumFontDesc.setComputedSize(20);
66
    mediumFontDesc.setComputedSize(12);
65
67
66
    m_mediumFont = adoptPtr(new Font(mediumFontDesc, 0, 0));
68
    m_mediumFont = adoptPtr(new Font(mediumFontDesc, 0, 0));
67
    m_mediumFont->update(0);
69
    m_mediumFont->update(0);
Lines 78-86 CCHeadsUpDisplay::~CCHeadsUpDisplay() a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp_sec3
78
{
80
{
79
}
81
}
80
82
83
// safeMod works on -1, returning m-1 in that case.
84
static inline int safeMod(int number, int modulus)
85
{
86
    return (number + modulus) % modulus;
87
}
88
89
inline int CCHeadsUpDisplay::frameIndex(int frame) const
90
{
91
    return safeMod(frame, kBeginFrameHistorySize);
92
}
93
81
void CCHeadsUpDisplay::onFrameBegin(double timestamp)
94
void CCHeadsUpDisplay::onFrameBegin(double timestamp)
82
{
95
{
83
    m_beginTimeHistoryInSec[m_currentFrameNumber % kBeginFrameHistorySize] = timestamp;
96
    m_beginTimeHistoryInSec[frameIndex(m_currentFrameNumber)] = timestamp;
84
}
97
}
85
98
86
void CCHeadsUpDisplay::onSwapBuffers()
99
void CCHeadsUpDisplay::onSwapBuffers()
Lines 162-167 void CCHeadsUpDisplay::draw() a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp_sec4
162
    m_hudTexture->unreserve();
175
    m_hudTexture->unreserve();
163
}
176
}
164
177
178
bool CCHeadsUpDisplay::isBadFrame(int frameNumber) const
179
{
180
    double delta = m_beginTimeHistoryInSec[frameIndex(frameNumber)] -
181
                   m_beginTimeHistoryInSec[frameIndex(frameNumber - 1)];
182
    bool tooSlow = delta > (kNumMissedFramesForReset / 60.0);
183
    bool schedulerAllowsDoubleFrames = !CCProxy::hasImplThread();
184
    return (schedulerAllowsDoubleFrames && delta < kFrameTooFast) || tooSlow;
185
}
186
165
void CCHeadsUpDisplay::drawHudContents(GraphicsContext* ctx, const IntSize& hudSize)
187
void CCHeadsUpDisplay::drawHudContents(GraphicsContext* ctx, const IntSize& hudSize)
166
{
188
{
167
    FontCachePurgePreventer fontCachePurgePreventer;
189
    FontCachePurgePreventer fontCachePurgePreventer;
Lines 171-181 void CCHeadsUpDisplay::drawHudContents(GraphicsContext* ctx, const IntSize& hudS a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp_sec5
171
        ctx->fillRect(FloatRect(0, 0, hudSize.width(), hudSize.height()));
193
        ctx->fillRect(FloatRect(0, 0, hudSize.width(), hudSize.height()));
172
    }
194
    }
173
195
174
    int fpsCounterHeight = m_mediumFont->fontMetrics().floatHeight() + 2;
196
    int fpsCounterHeight = m_mediumFont->fontMetrics().floatHeight() + 40;
175
    int fpsCounterTop = 2;
197
    int fpsCounterTop = 2;
176
    int platformLayerTreeTop;
198
    int platformLayerTreeTop;
177
    if (settings().showFPSCounter)
199
    if (settings().showFPSCounter)
178
        platformLayerTreeTop = fpsCounterTop + fpsCounterHeight + 2;
200
        platformLayerTreeTop = fpsCounterTop + fpsCounterHeight;
179
    else
201
    else
180
        platformLayerTreeTop = 0;
202
        platformLayerTreeTop = 0;
181
203
Lines 190-227 void CCHeadsUpDisplay::drawFPSCounter(GraphicsContext* ctx, int top, int height) a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp_sec6
190
{
212
{
191
    // Note that since we haven't finished the current frame, the FPS counter
213
    // Note that since we haven't finished the current frame, the FPS counter
192
    // actually reports the last frame's time.
214
    // actually reports the last frame's time.
193
    double secForLastFrame = m_beginTimeHistoryInSec[(m_currentFrameNumber + kBeginFrameHistorySize - 1) % kBeginFrameHistorySize] -
215
    double secForLastFrame = m_beginTimeHistoryInSec[frameIndex(m_currentFrameNumber - 1)] -
194
                             m_beginTimeHistoryInSec[(m_currentFrameNumber + kBeginFrameHistorySize - 2) % kBeginFrameHistorySize];
216
                             m_beginTimeHistoryInSec[frameIndex(m_currentFrameNumber - 2)];
195
217
    double secForSecondLastFrame = m_beginTimeHistoryInSec[frameIndex(m_currentFrameNumber - 2)] -
196
    // Filter the frame times to avoid spikes.
218
                                  m_beginTimeHistoryInSec[frameIndex(m_currentFrameNumber - 3)];
197
    const float alpha = 0.1;
219
198
    if (!m_filteredFrameTime) {
220
    // Filter the frame times to avoid spikes. Specifically, keep a running
199
        if (m_currentFrameNumber == 2)
221
    // average frame rate and a running variance while ignoring bad frames
200
            m_filteredFrameTime = secForLastFrame;
222
    // which are either too slow or too fast. Slow frames occur just because
201
    } else
223
    // the user is inactive, and should be ignored. Fast frames are ignored if
202
        m_filteredFrameTime = ((1.0 - alpha) * m_filteredFrameTime) + (alpha * secForLastFrame);
224
    // the scheduler is in single-thread mode in order to represent the true
225
    // frame rate in spite of the fact that the first few swapbuffers happen
226
    // instantly which skews the statistics too much for short lived
227
    // animations.
228
    if (secForSecondLastFrame > kIdleSecondsTriggersReset || m_averageFPSCount > kLongAnimationTriggersReset) {
229
        // restart the frame statistics
230
        m_averageFPS = 0;
231
        m_averageFPSCount = 0;
232
        m_fpsVarianceNumerator = 0;
233
    } else if (!isBadFrame(m_currentFrameNumber - 1)) {
234
        m_averageFPSCount++;
235
        double x = 1.0 / secForLastFrame;
236
        double deltaFromAverage = x - m_averageFPS;
237
        // Change with caution - numerics. http://en.wikipedia.org/wiki/Standard_deviation
238
        m_averageFPS = m_averageFPS + deltaFromAverage / m_averageFPSCount;
239
        m_fpsVarianceNumerator = m_fpsVarianceNumerator + deltaFromAverage * (x - m_averageFPS);
240
    }
203
241
204
    // Create & measure FPS text.
242
    // Create & measure FPS text.
205
    String text(String::format("FPS: %5.1f", 1.0 / m_filteredFrameTime));
243
    double stdDeviation = sqrt(m_fpsVarianceNumerator / m_averageFPSCount);
206
    TextRun run(text);
244
    String fps(String::format("FPS: %4.1f +/-%3.1f", m_averageFPS, stdDeviation));
207
    float textWidth = m_mediumFont->width(run) + 2.0f;
245
    TextRun text(fps);
246
    float textWidth = m_mediumFont->width(text) + 2;
208
    float graphWidth = kBeginFrameHistorySize;
247
    float graphWidth = kBeginFrameHistorySize;
209
248
210
    // Draw background.
249
    // Draw background.
211
    ctx->setFillColor(Color(0, 0, 0, 255), ColorSpaceDeviceRGB);
250
    ctx->setFillColor(Color(0, 0, 0, 255), ColorSpaceDeviceRGB);
212
    ctx->fillRect(FloatRect(2, top, textWidth + graphWidth, height));
251
    double fontHeight = m_mediumFont->fontMetrics().floatHeight() + 2;
252
    ctx->fillRect(FloatRect(2, top, textWidth, fontHeight));
253
    ctx->fillRect(FloatRect(2 + textWidth, top, graphWidth, height));
213
254
214
    // Draw FPS text.
255
    // Draw FPS text.
215
    if (m_filteredFrameTime) {
256
    ctx->setFillColor(Color(200, 200, 200), ColorSpaceDeviceRGB);
216
        ctx->setFillColor(Color(255, 0, 0), ColorSpaceDeviceRGB);
257
    ctx->drawText(*m_mediumFont, text, IntPoint(3, top + fontHeight - 4));
217
        ctx->drawText(*m_mediumFont, run, IntPoint(3, top + height - 6));
218
    }
219
258
220
    // Draw FPS graph.
259
    // Draw FPS graph.
221
    const double loFPS = 0.0;
260
    const double loFPS = 0;
222
    const double hiFPS = 120.0;
261
    const double hiFPS = 80;
223
    ctx->setStrokeStyle(SolidStroke);
262
    ctx->setStrokeStyle(SolidStroke);
263
    ctx->setFillColor(Color(154, 205, 50), ColorSpaceDeviceRGB);
264
    ctx->fillRect(FloatRect(2 + textWidth, top, graphWidth, height / 2));
265
    ctx->setFillColor(Color(255, 250, 205), ColorSpaceDeviceRGB);
266
    ctx->fillRect(FloatRect(2 + textWidth, top + height / 2, graphWidth, height / 2));
224
    ctx->setStrokeColor(Color(255, 0, 0), ColorSpaceDeviceRGB);
267
    ctx->setStrokeColor(Color(255, 0, 0), ColorSpaceDeviceRGB);
268
    ctx->setFillColor(Color(255, 0, 0), ColorSpaceDeviceRGB);
225
    int graphLeft = static_cast<int>(textWidth + 3);
269
    int graphLeft = static_cast<int>(textWidth + 3);
226
    IntPoint prev(-1, 0);
270
    IntPoint prev(-1, 0);
227
    int x = 0;
271
    int x = 0;
Lines 229-234 void CCHeadsUpDisplay::drawFPSCounter(GraphicsContext* ctx, int top, int height) a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp_sec7
229
    for (int i = m_currentFrameNumber % kBeginFrameHistorySize; i != (m_currentFrameNumber - 1) % kBeginFrameHistorySize; i = (i + 1) % kBeginFrameHistorySize) {
273
    for (int i = m_currentFrameNumber % kBeginFrameHistorySize; i != (m_currentFrameNumber - 1) % kBeginFrameHistorySize; i = (i + 1) % kBeginFrameHistorySize) {
230
        int j = (i + 1) % kBeginFrameHistorySize;
274
        int j = (i + 1) % kBeginFrameHistorySize;
231
        double fps = 1.0 / (m_beginTimeHistoryInSec[j] - m_beginTimeHistoryInSec[i]);
275
        double fps = 1.0 / (m_beginTimeHistoryInSec[j] - m_beginTimeHistoryInSec[i]);
276
        if (isBadFrame(j)) {
277
            x += 1;
278
            continue;
279
        }
232
        double p = 1 - ((fps - loFPS) / (hiFPS - loFPS));
280
        double p = 1 - ((fps - loFPS) / (hiFPS - loFPS));
233
        if (p < 0)
281
        if (p < 0)
234
            p = 0;
282
            p = 0;
- a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.h -1 / +13 lines
Lines 66-82 private: a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.h_sec1
66
    void drawFPSCounter(GraphicsContext*, int top, int height);
66
    void drawFPSCounter(GraphicsContext*, int top, int height);
67
    void drawPlatformLayerTree(GraphicsContext*, int top);
67
    void drawPlatformLayerTree(GraphicsContext*, int top);
68
    const CCSettings& settings() const;
68
    const CCSettings& settings() const;
69
    bool isBadFrame(int frameNumber) const;
70
    int frameIndex(int frameNumber) const;
69
71
70
    int m_currentFrameNumber;
72
    int m_currentFrameNumber;
71
73
72
    double m_filteredFrameTime;
74
    double m_averageFPS;
75
    int m_averageFPSCount;
76
    double m_fpsVarianceNumerator;
73
77
74
    OwnPtr<ManagedTexture> m_hudTexture;
78
    OwnPtr<ManagedTexture> m_hudTexture;
75
79
76
    LayerRendererChromium* m_layerRenderer;
80
    LayerRendererChromium* m_layerRenderer;
77
81
78
    static const int kBeginFrameHistorySize = 64;
82
    static const int kBeginFrameHistorySize = 64;
83
    // The number of seconds of no frames makes us decide that the previous
84
    // animation is over.
85
    static const double kIdleSecondsTriggersReset = 0.5;
86
    // The number of frames that cause us to reset the FPS statistics so that
87
    // the average of zillions of frames doesn't drown out a momentary jank.
88
    static const int kLongAnimationTriggersReset = 60*2;
79
    double m_beginTimeHistoryInSec[kBeginFrameHistorySize];
89
    double m_beginTimeHistoryInSec[kBeginFrameHistorySize];
90
    static const double kFrameTooFast = 1.0 / 70;
91
    static const int kNumMissedFramesForReset = 5;
80
92
81
    OwnPtr<Font> m_smallFont;
93
    OwnPtr<Font> m_smallFont;
82
    OwnPtr<Font> m_mediumFont;
94
    OwnPtr<Font> m_mediumFont;

Return to Bug 73454