1 | /* |
2 | * Copyright (C) 2018 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #pragma once |
27 | |
28 | namespace WebCore { |
29 | |
30 | // This class is used to detect when we are painting frequently so that - even in a painting model |
31 | // without display lists - we can build and cache portions of display lists and reuse them only when |
32 | // animating. Once we transition fully to display lists, we can probably just pull from the previous |
33 | // paint's display list if it is still around and get rid of this code. |
34 | class PaintFrequencyTracker { |
35 | WTF_MAKE_FAST_ALLOCATED; |
36 | |
37 | public: |
38 | PaintFrequencyTracker() = default; |
39 | |
40 | void begin() |
41 | { |
42 | static unsigned paintFrequencyPaintCountThreshold = 30; |
43 | static Seconds paintFrequencyTimePerFrameThreshold = 32_ms; |
44 | static Seconds paintFrequencySecondsIdleThreshold = 5_s; |
45 | |
46 | // Start by assuming the paint frequency is low |
47 | m_paintFrequency = PaintFrequency::Low; |
48 | |
49 | MonotonicTime now = MonotonicTime::now(); |
50 | if (!m_firstPaintTime) { |
51 | // Handle the first time this method is called. |
52 | m_firstPaintTime = now; |
53 | } else if (now - m_lastPaintTime > paintFrequencySecondsIdleThreshold) { |
54 | // It has been 5 seconds since last time we draw this renderer. Reset the state |
55 | // of this object as if, we've just started tracking the paint frequency. |
56 | m_firstPaintTime = now; |
57 | m_totalPaints = 0; |
58 | } else if (m_totalPaints >= paintFrequencyPaintCountThreshold && ((m_lastPaintTime - m_firstPaintTime) / m_totalPaints) <= paintFrequencyTimePerFrameThreshold) { |
59 | // Change the paint frequency to be high only if: |
60 | // - This renderer has been painted at least 30 times. |
61 | // - The frame rate to paint this renderer has been at least 31.25 FPS. |
62 | m_paintFrequency = PaintFrequency::High; |
63 | } |
64 | } |
65 | |
66 | void end() |
67 | { |
68 | m_lastPaintTime = MonotonicTime::now(); |
69 | ASSERT(m_firstPaintTime); |
70 | ASSERT(m_firstPaintTime <= m_lastPaintTime); |
71 | ++m_totalPaints; |
72 | } |
73 | |
74 | bool paintingFrequently() const { return m_paintFrequency == PaintFrequency::High; } |
75 | |
76 | private: |
77 | MonotonicTime m_firstPaintTime; |
78 | MonotonicTime m_lastPaintTime; |
79 | unsigned m_totalPaints { 0 }; |
80 | |
81 | enum class PaintFrequency { Low, High }; |
82 | PaintFrequency m_paintFrequency { PaintFrequency::Low }; |
83 | }; |
84 | |
85 | class SinglePaintFrequencyTracking { |
86 | WTF_MAKE_FAST_ALLOCATED; |
87 | public: |
88 | SinglePaintFrequencyTracking(PaintFrequencyTracker& paintFrequencyTracker, bool track = true) |
89 | : m_paintFrequencyTracker(paintFrequencyTracker) |
90 | , m_track(track) |
91 | { |
92 | if (m_track) |
93 | m_paintFrequencyTracker.begin(); |
94 | } |
95 | |
96 | ~SinglePaintFrequencyTracking() |
97 | { |
98 | if (m_track) |
99 | m_paintFrequencyTracker.end(); |
100 | } |
101 | |
102 | private: |
103 | PaintFrequencyTracker& m_paintFrequencyTracker; |
104 | bool m_track; |
105 | }; |
106 | |
107 | } |
108 | |