867d56ea87d228b949d112118b21fa37278c872d
[WebKit-https.git] / Source / WebKit / chromium / tests / CCDelayBasedTimeSourceTest.cpp
1 /*
2  * Copyright (C) 2011 Google 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. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26
27 #include "cc/CCDelayBasedTimeSource.h"
28
29 #include "CCSchedulerTestCommon.h"
30 #include "cc/CCThread.h"
31 #include <gtest/gtest.h>
32 #include <wtf/RefPtr.h>
33
34 using namespace WTF;
35 using namespace WebCore;
36 using namespace WebKitTests;
37
38 namespace {
39
40 TEST(CCDelayBasedTimeSourceTest, TaskPostedAndTickCalled)
41 {
42     FakeCCThread thread;
43     FakeCCTimeSourceClient client;
44     RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(1000.0 / 60.0, &thread);
45     timer->setClient(&client);
46
47     timer->setMonotonicallyIncreasingTimeMs(0);
48     timer->setActive(true);
49     EXPECT_TRUE(timer->active());
50     EXPECT_TRUE(thread.hasPendingTask());
51
52     timer->setMonotonicallyIncreasingTimeMs(16);
53     thread.runPendingTask();
54     EXPECT_TRUE(timer->active());
55     EXPECT_TRUE(client.tickCalled());
56 }
57
58 TEST(CCDelayBasedTimeSource, TickNotCalledWithTaskPosted)
59 {
60     FakeCCThread thread;
61     FakeCCTimeSourceClient client;
62     RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(1000.0 / 60.0, &thread);
63     timer->setClient(&client);
64     timer->setActive(true);
65     EXPECT_TRUE(thread.hasPendingTask());
66     timer->setActive(false);
67     thread.runPendingTask();
68     EXPECT_FALSE(client.tickCalled());
69 }
70
71 TEST(CCDelayBasedTimeSource, StartTwiceEnqueuesOneTask)
72 {
73     FakeCCThread thread;
74     FakeCCTimeSourceClient client;
75     RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(1000.0 / 60.0, &thread);
76     timer->setClient(&client);
77     timer->setActive(true);
78     EXPECT_TRUE(thread.hasPendingTask());
79     thread.reset();
80     timer->setActive(true);
81     EXPECT_FALSE(thread.hasPendingTask());
82 }
83
84 TEST(CCDelayBasedTimeSource, StartWhenRunningDoesntTick)
85 {
86     FakeCCThread thread;
87     FakeCCTimeSourceClient client;
88     RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(1000.0 / 60.0, &thread);
89     timer->setClient(&client);
90     timer->setActive(true);
91     thread.runPendingTask();
92     thread.reset();
93     timer->setActive(true);
94     EXPECT_FALSE(thread.hasPendingTask());
95 }
96
97 // At 60Hz, when the tick returns at exactly the requested next time, make sure
98 // a 16ms next delay is posted.
99 TEST(CCDelayBasedTimeSource, NextDelaySaneWhenExactlyOnRequestedTime)
100 {
101     FakeCCThread thread;
102     FakeCCTimeSourceClient client;
103     double interval = 1000.0 / 60.0;
104     RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(interval, &thread);
105     timer->setClient(&client);
106     timer->setActive(true);
107     // Run the first task, as that activates the timer and picks up a timebase.
108     thread.runPendingTask();
109
110     EXPECT_EQ(16, thread.pendingDelay());
111
112     timer->setMonotonicallyIncreasingTimeMs(interval);
113     thread.runPendingTask();
114
115     EXPECT_EQ(16, thread.pendingDelay());
116 }
117
118 // At 60Hz, when the tick returns at slightly after the requested next time, make sure
119 // a 16ms next delay is posted.
120 TEST(CCDelayBasedTimeSource, NextDelaySaneWhenSlightlyAfterRequestedTime)
121 {
122     FakeCCThread thread;
123     FakeCCTimeSourceClient client;
124     double interval = 1000.0 / 60.0;
125     RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(interval, &thread);
126     timer->setClient(&client);
127     timer->setActive(true);
128     // Run the first task, as that activates the timer and picks up a timebase.
129     thread.runPendingTask();
130
131     EXPECT_EQ(16, thread.pendingDelay());
132
133     timer->setMonotonicallyIncreasingTimeMs(interval + 0.0001);
134     thread.runPendingTask();
135
136     EXPECT_EQ(16, thread.pendingDelay());
137 }
138
139 // At 60Hz, when the tick returns at exactly 2*interval after the requested next time, make sure
140 // a 16ms next delay is posted.
141 TEST(CCDelayBasedTimeSource, NextDelaySaneWhenExactlyTwiceAfterRequestedTime)
142 {
143     FakeCCThread thread;
144     FakeCCTimeSourceClient client;
145     double interval = 1000.0 / 60.0;
146     RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(interval, &thread);
147     timer->setClient(&client);
148     timer->setActive(true);
149     // Run the first task, as that activates the timer and picks up a timebase.
150     thread.runPendingTask();
151
152     EXPECT_EQ(16, thread.pendingDelay());
153
154     timer->setMonotonicallyIncreasingTimeMs(2*interval);
155     thread.runPendingTask();
156
157     EXPECT_EQ(16, thread.pendingDelay());
158 }
159
160 // At 60Hz, when the tick returns at 2*interval and a bit after the requested next time, make sure
161 // a 16ms next delay is posted.
162 TEST(CCDelayBasedTimeSource, NextDelaySaneWhenSlightlyAfterTwiceRequestedTime)
163 {
164     FakeCCThread thread;
165     FakeCCTimeSourceClient client;
166     double interval = 1000.0 / 60.0;
167     RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(interval, &thread);
168     timer->setClient(&client);
169     timer->setActive(true);
170     // Run the first task, as that activates the timer and picks up a timebase.
171     thread.runPendingTask();
172
173     EXPECT_EQ(16, thread.pendingDelay());
174
175     timer->setMonotonicallyIncreasingTimeMs(2*interval + 0.0001);
176     thread.runPendingTask();
177
178     EXPECT_EQ(16, thread.pendingDelay());
179 }
180
181 // At 60Hz, when the tick returns halfway to the next frame time, make sure
182 // a correct next delay value is posted.
183 TEST(CCDelayBasedTimeSource, NextDelaySaneWhenHalfAfterRequestedTime)
184 {
185     FakeCCThread thread;
186     FakeCCTimeSourceClient client;
187     double interval = 1000.0 / 60.0;
188     RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(interval, &thread);
189     timer->setClient(&client);
190     timer->setActive(true);
191     // Run the first task, as that activates the timer and picks up a timebase.
192     thread.runPendingTask();
193
194     EXPECT_EQ(16, thread.pendingDelay());
195
196     timer->setMonotonicallyIncreasingTimeMs(interval + interval * 0.5);
197     thread.runPendingTask();
198
199     EXPECT_EQ(8, thread.pendingDelay());
200 }
201
202
203 TEST(CCDelayBasedTimeSourceTest, AchievesTargetRateWithNoNoise)
204 {
205     int numIterations = 1000;
206
207     FakeCCThread thread;
208     FakeCCTimeSourceClient client;
209     RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(1000.0 / 60.0, &thread);
210     timer->setClient(&client);
211     timer->setActive(true);
212
213     double totalFrameTime = 0;
214     for (int i = 0; i < numIterations; ++i) {
215         long long delay = thread.pendingDelay();
216
217         // accumulate the "delay"
218         totalFrameTime += delay;
219
220         // Run the callback exactly when asked
221         double now = timer->monotonicallyIncreasingTimeMs() + delay;
222         timer->setMonotonicallyIncreasingTimeMs(now);
223         thread.runPendingTask();
224     }
225     double averageInterval = totalFrameTime / static_cast<double>(numIterations);
226     EXPECT_NEAR(1000.0 / 60.0, averageInterval, 0.1);
227 }
228
229 TEST(CCDelayBasedTimeSource, TestDeactivateWhilePending)
230 {
231     FakeCCThread thread;
232     FakeCCTimeSourceClient client;
233     RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(1000.0 / 60.0, &thread);
234     timer->setClient(&client);
235     timer->setActive(true); // Should post a task.
236     timer->setActive(false);
237     timer.clear();
238     thread.runPendingTask(); // Should run the posted task without crashing.
239 }
240
241 TEST(CCDelayBasedTimeSource, TestDeactivateAndReactivateBeforeNextTickTime)
242 {
243     FakeCCThread thread;
244     FakeCCTimeSourceClient client;
245     RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(1000.0 / 60.0, &thread);
246     timer->setClient(&client);
247
248     // Should run the activate task, and pick up a new timebase.
249     timer->setActive(true);
250     timer->setMonotonicallyIncreasingTimeMs(0);
251     thread.runPendingTask();
252
253     // Stop the timer
254     timer->setActive(false);
255
256     // Task will be pending anyway, run it
257     thread.runPendingTask();
258
259     // Start the timer again, but before the next tick time the timer previously
260     // planned on using. That same tick time should still be targeted.
261     timer->setMonotonicallyIncreasingTimeMs(4);
262     timer->setActive(true);
263     EXPECT_EQ(12, thread.pendingDelay());
264 }
265
266 TEST(CCDelayBasedTimeSource, TestDeactivateAndReactivateAfterNextTickTime)
267 {
268     FakeCCThread thread;
269     FakeCCTimeSourceClient client;
270     RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::create(1000.0 / 60.0, &thread);
271     timer->setClient(&client);
272
273     // Should run the activate task, and pick up a new timebase.
274     timer->setActive(true);
275     timer->setMonotonicallyIncreasingTimeMs(0);
276     thread.runPendingTask();
277
278     // Stop the timer
279     timer->setActive(false);
280
281     // Task will be pending anyway, run it
282     thread.runPendingTask();
283
284     // Start the timer again, but before the next tick time the timer previously
285     // planned on using. That same tick time should still be targeted.
286     timer->setMonotonicallyIncreasingTimeMs(20);
287     timer->setActive(true);
288     EXPECT_EQ(13, thread.pendingDelay());
289 }
290
291 }