1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/output/output_surface.h"
7 #include "base/test/test_simple_task_runner.h"
8 #include "cc/debug/test_context_provider.h"
9 #include "cc/debug/test_web_graphics_context_3d.h"
10 #include "cc/output/managed_memory_policy.h"
11 #include "cc/output/output_surface_client.h"
12 #include "cc/output/software_output_device.h"
13 #include "cc/test/fake_output_surface.h"
14 #include "cc/test/fake_output_surface_client.h"
15 #include "cc/test/scheduler_test_common.h"
16 #include "gpu/GLES2/gl2extchromium.h"
17 #include "testing/gtest/include/gtest/gtest.h"
22 class TestOutputSurface
: public OutputSurface
{
24 explicit TestOutputSurface(scoped_refptr
<ContextProvider
> context_provider
)
25 : OutputSurface(context_provider
) {}
27 explicit TestOutputSurface(
28 scoped_ptr
<cc::SoftwareOutputDevice
> software_device
)
29 : OutputSurface(software_device
.Pass()) {}
31 TestOutputSurface(scoped_refptr
<ContextProvider
> context_provider
,
32 scoped_ptr
<cc::SoftwareOutputDevice
> software_device
)
33 : OutputSurface(context_provider
, software_device
.Pass()) {}
35 bool InitializeNewContext3d(
36 scoped_refptr
<ContextProvider
> new_context_provider
) {
37 return InitializeAndSetContext3d(new_context_provider
,
38 scoped_refptr
<ContextProvider
>());
41 using OutputSurface::ReleaseGL
;
43 void OnVSyncParametersChangedForTesting(base::TimeTicks timebase
,
44 base::TimeDelta interval
) {
45 OnVSyncParametersChanged(timebase
, interval
);
48 void BeginFrameForTesting() {
49 OutputSurface::BeginFrame(BeginFrameArgs::CreateExpiredForTesting());
52 void DidSwapBuffersForTesting() {
56 int pending_swap_buffers() {
57 return pending_swap_buffers_
;
60 void OnSwapBuffersCompleteForTesting() {
61 OnSwapBuffersComplete(NULL
);
64 void SetAlternateRetroactiveBeginFramePeriod(base::TimeDelta period
) {
65 alternate_retroactive_begin_frame_period_
= period
;
69 virtual void PostCheckForRetroactiveBeginFrame() OVERRIDE
{
70 // For testing purposes, we check immediately rather than posting a task.
71 CheckForRetroactiveBeginFrame();
74 virtual base::TimeDelta
AlternateRetroactiveBeginFramePeriod() OVERRIDE
{
75 return alternate_retroactive_begin_frame_period_
;
78 base::TimeDelta alternate_retroactive_begin_frame_period_
;
81 TEST(OutputSurfaceTest
, ClientPointerIndicatesBindToClientSuccess
) {
82 TestOutputSurface
output_surface(TestContextProvider::Create());
83 EXPECT_FALSE(output_surface
.HasClient());
85 FakeOutputSurfaceClient client
;
86 EXPECT_TRUE(output_surface
.BindToClient(&client
));
87 EXPECT_TRUE(output_surface
.HasClient());
88 EXPECT_FALSE(client
.deferred_initialize_called());
90 // Verify DidLoseOutputSurface callback is hooked up correctly.
91 EXPECT_FALSE(client
.did_lose_output_surface_called());
92 output_surface
.context_provider()->Context3d()->loseContextCHROMIUM(
93 GL_GUILTY_CONTEXT_RESET_ARB
, GL_INNOCENT_CONTEXT_RESET_ARB
);
94 EXPECT_TRUE(client
.did_lose_output_surface_called());
97 TEST(OutputSurfaceTest
, ClientPointerIndicatesBindToClientFailure
) {
98 scoped_refptr
<TestContextProvider
> context_provider
=
99 TestContextProvider::Create();
101 // Lose the context so BindToClient fails.
102 context_provider
->TestContext3d()->set_times_make_current_succeeds(0);
104 TestOutputSurface
output_surface(context_provider
);
105 EXPECT_FALSE(output_surface
.HasClient());
107 FakeOutputSurfaceClient client
;
108 EXPECT_FALSE(output_surface
.BindToClient(&client
));
109 EXPECT_FALSE(output_surface
.HasClient());
112 class OutputSurfaceTestInitializeNewContext3d
: public ::testing::Test
{
114 OutputSurfaceTestInitializeNewContext3d()
115 : context_provider_(TestContextProvider::Create()),
117 scoped_ptr
<SoftwareOutputDevice
>(new SoftwareOutputDevice
)) {}
120 void BindOutputSurface() {
121 EXPECT_TRUE(output_surface_
.BindToClient(&client_
));
122 EXPECT_TRUE(output_surface_
.HasClient());
125 void InitializeNewContextExpectFail() {
126 EXPECT_FALSE(output_surface_
.InitializeNewContext3d(context_provider_
));
127 EXPECT_TRUE(output_surface_
.HasClient());
129 EXPECT_FALSE(output_surface_
.context_provider());
130 EXPECT_TRUE(output_surface_
.software_device());
133 scoped_refptr
<TestContextProvider
> context_provider_
;
134 TestOutputSurface output_surface_
;
135 FakeOutputSurfaceClient client_
;
138 TEST_F(OutputSurfaceTestInitializeNewContext3d
, Success
) {
140 EXPECT_FALSE(client_
.deferred_initialize_called());
142 EXPECT_TRUE(output_surface_
.InitializeNewContext3d(context_provider_
));
143 EXPECT_TRUE(client_
.deferred_initialize_called());
144 EXPECT_EQ(context_provider_
, output_surface_
.context_provider());
146 EXPECT_FALSE(client_
.did_lose_output_surface_called());
147 context_provider_
->Context3d()->loseContextCHROMIUM(
148 GL_GUILTY_CONTEXT_RESET_ARB
, GL_INNOCENT_CONTEXT_RESET_ARB
);
149 EXPECT_TRUE(client_
.did_lose_output_surface_called());
151 output_surface_
.ReleaseGL();
152 EXPECT_FALSE(output_surface_
.context_provider());
155 TEST_F(OutputSurfaceTestInitializeNewContext3d
, Context3dMakeCurrentFails
) {
157 context_provider_
->TestContext3d()->set_times_make_current_succeeds(0);
158 InitializeNewContextExpectFail();
161 TEST_F(OutputSurfaceTestInitializeNewContext3d
, ClientDeferredInitializeFails
) {
163 client_
.set_deferred_initialize_result(false);
164 InitializeNewContextExpectFail();
167 TEST(OutputSurfaceTest
, BeginFrameEmulation
) {
168 TestOutputSurface
output_surface(TestContextProvider::Create());
169 EXPECT_FALSE(output_surface
.HasClient());
171 FakeOutputSurfaceClient client
;
172 EXPECT_TRUE(output_surface
.BindToClient(&client
));
173 EXPECT_TRUE(output_surface
.HasClient());
174 EXPECT_FALSE(client
.deferred_initialize_called());
176 // Initialize BeginFrame emulation
177 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
178 new base::TestSimpleTaskRunner
;
179 bool throttle_frame_production
= true;
180 const base::TimeDelta display_refresh_interval
=
181 BeginFrameArgs::DefaultInterval();
183 output_surface
.InitializeBeginFrameEmulation(
185 throttle_frame_production
,
186 display_refresh_interval
);
188 output_surface
.SetMaxFramesPending(2);
189 output_surface
.SetAlternateRetroactiveBeginFramePeriod(
190 base::TimeDelta::FromSeconds(-1));
192 // We should start off with 0 BeginFrames
193 EXPECT_EQ(client
.begin_frame_count(), 0);
194 EXPECT_EQ(output_surface
.pending_swap_buffers(), 0);
196 // We should not have a pending task until a BeginFrame has been requested.
197 EXPECT_FALSE(task_runner
->HasPendingTask());
198 output_surface
.SetNeedsBeginFrame(true);
199 EXPECT_TRUE(task_runner
->HasPendingTask());
201 // BeginFrame should be called on the first tick.
202 task_runner
->RunPendingTasks();
203 EXPECT_EQ(client
.begin_frame_count(), 1);
204 EXPECT_EQ(output_surface
.pending_swap_buffers(), 0);
206 // BeginFrame should not be called when there is a pending BeginFrame.
207 task_runner
->RunPendingTasks();
208 EXPECT_EQ(client
.begin_frame_count(), 1);
209 EXPECT_EQ(output_surface
.pending_swap_buffers(), 0);
211 // DidSwapBuffers should clear the pending BeginFrame.
212 output_surface
.DidSwapBuffersForTesting();
213 EXPECT_EQ(client
.begin_frame_count(), 1);
214 EXPECT_EQ(output_surface
.pending_swap_buffers(), 1);
215 task_runner
->RunPendingTasks();
216 EXPECT_EQ(client
.begin_frame_count(), 2);
217 EXPECT_EQ(output_surface
.pending_swap_buffers(), 1);
219 // BeginFrame should be throttled by pending swap buffers.
220 output_surface
.DidSwapBuffersForTesting();
221 EXPECT_EQ(client
.begin_frame_count(), 2);
222 EXPECT_EQ(output_surface
.pending_swap_buffers(), 2);
223 task_runner
->RunPendingTasks();
224 EXPECT_EQ(client
.begin_frame_count(), 2);
225 EXPECT_EQ(output_surface
.pending_swap_buffers(), 2);
227 // SwapAck should decrement pending swap buffers and unblock BeginFrame again.
228 output_surface
.OnSwapBuffersCompleteForTesting();
229 EXPECT_EQ(client
.begin_frame_count(), 2);
230 EXPECT_EQ(output_surface
.pending_swap_buffers(), 1);
231 task_runner
->RunPendingTasks();
232 EXPECT_EQ(client
.begin_frame_count(), 3);
233 EXPECT_EQ(output_surface
.pending_swap_buffers(), 1);
235 // Calling SetNeedsBeginFrame again indicates a swap did not occur but
236 // the client still wants another BeginFrame.
237 output_surface
.SetNeedsBeginFrame(true);
238 task_runner
->RunPendingTasks();
239 EXPECT_EQ(client
.begin_frame_count(), 4);
240 EXPECT_EQ(output_surface
.pending_swap_buffers(), 1);
242 // Disabling SetNeedsBeginFrame should prevent further BeginFrames.
243 output_surface
.SetNeedsBeginFrame(false);
244 task_runner
->RunPendingTasks();
245 EXPECT_FALSE(task_runner
->HasPendingTask());
246 EXPECT_EQ(client
.begin_frame_count(), 4);
247 EXPECT_EQ(output_surface
.pending_swap_buffers(), 1);
250 TEST(OutputSurfaceTest
, OptimisticAndRetroactiveBeginFrames
) {
251 TestOutputSurface
output_surface(TestContextProvider::Create());
252 EXPECT_FALSE(output_surface
.HasClient());
254 FakeOutputSurfaceClient client
;
255 EXPECT_TRUE(output_surface
.BindToClient(&client
));
256 EXPECT_TRUE(output_surface
.HasClient());
257 EXPECT_FALSE(client
.deferred_initialize_called());
259 output_surface
.SetMaxFramesPending(2);
261 // Enable retroactive BeginFrames.
262 output_surface
.SetAlternateRetroactiveBeginFramePeriod(
263 base::TimeDelta::FromSeconds(100000));
265 // Optimistically injected BeginFrames should be throttled if
266 // SetNeedsBeginFrame is false...
267 output_surface
.SetNeedsBeginFrame(false);
268 output_surface
.BeginFrameForTesting();
269 EXPECT_EQ(client
.begin_frame_count(), 0);
270 // ...and retroactively triggered by a SetNeedsBeginFrame.
271 output_surface
.SetNeedsBeginFrame(true);
272 EXPECT_EQ(client
.begin_frame_count(), 1);
274 // Optimistically injected BeginFrames should be throttled by pending
276 output_surface
.BeginFrameForTesting();
277 EXPECT_EQ(client
.begin_frame_count(), 1);
278 // ...and retroactively triggered by a SetNeedsBeginFrame.
279 output_surface
.SetNeedsBeginFrame(true);
280 EXPECT_EQ(client
.begin_frame_count(), 2);
281 // ...or retroactively triggered by a Swap.
282 output_surface
.BeginFrameForTesting();
283 EXPECT_EQ(client
.begin_frame_count(), 2);
284 output_surface
.DidSwapBuffersForTesting();
285 EXPECT_EQ(client
.begin_frame_count(), 3);
286 EXPECT_EQ(output_surface
.pending_swap_buffers(), 1);
288 // Optimistically injected BeginFrames should be by throttled by pending
290 output_surface
.DidSwapBuffersForTesting();
291 EXPECT_EQ(client
.begin_frame_count(), 3);
292 EXPECT_EQ(output_surface
.pending_swap_buffers(), 2);
293 output_surface
.BeginFrameForTesting();
294 EXPECT_EQ(client
.begin_frame_count(), 3);
295 // ...and retroactively triggered by OnSwapBuffersComplete
296 output_surface
.OnSwapBuffersCompleteForTesting();
297 EXPECT_EQ(client
.begin_frame_count(), 4);
300 TEST(OutputSurfaceTest
, RetroactiveBeginFrameDoesNotDoubleTickWhenEmulating
) {
301 scoped_refptr
<TestContextProvider
> context_provider
=
302 TestContextProvider::Create();
304 TestOutputSurface
output_surface(context_provider
);
305 EXPECT_FALSE(output_surface
.HasClient());
307 FakeOutputSurfaceClient client
;
308 EXPECT_TRUE(output_surface
.BindToClient(&client
));
309 EXPECT_TRUE(output_surface
.HasClient());
310 EXPECT_FALSE(client
.deferred_initialize_called());
312 base::TimeDelta big_interval
= base::TimeDelta::FromSeconds(1000);
314 // Initialize BeginFrame emulation
315 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
316 new base::TestSimpleTaskRunner
;
317 bool throttle_frame_production
= true;
318 const base::TimeDelta display_refresh_interval
= big_interval
;
320 output_surface
.InitializeBeginFrameEmulation(
322 throttle_frame_production
,
323 display_refresh_interval
);
325 // We need to subtract an epsilon from Now() because some platforms have
327 output_surface
.OnVSyncParametersChangedForTesting(
328 base::TimeTicks::Now() - base::TimeDelta::FromMilliseconds(1),
329 display_refresh_interval
);
331 output_surface
.SetMaxFramesPending(2);
332 output_surface
.SetAlternateRetroactiveBeginFramePeriod(
333 base::TimeDelta::FromSeconds(-1));
335 // We should start off with 0 BeginFrames
336 EXPECT_EQ(client
.begin_frame_count(), 0);
337 EXPECT_EQ(output_surface
.pending_swap_buffers(), 0);
339 // The first SetNeedsBeginFrame(true) should start a retroactive BeginFrame.
340 output_surface
.SetNeedsBeginFrame(true);
341 EXPECT_TRUE(task_runner
->HasPendingTask());
342 EXPECT_GT(task_runner
->NextPendingTaskDelay(), big_interval
/ 2);
343 EXPECT_EQ(client
.begin_frame_count(), 1);
345 output_surface
.SetNeedsBeginFrame(false);
346 EXPECT_TRUE(task_runner
->HasPendingTask());
347 EXPECT_EQ(client
.begin_frame_count(), 1);
349 // The second SetNeedBeginFrame(true) should not retroactively start a
350 // BeginFrame if the timestamp would be the same as the previous BeginFrame.
351 output_surface
.SetNeedsBeginFrame(true);
352 EXPECT_TRUE(task_runner
->HasPendingTask());
353 EXPECT_EQ(client
.begin_frame_count(), 1);
356 TEST(OutputSurfaceTest
, MemoryAllocation
) {
357 scoped_refptr
<TestContextProvider
> context_provider
=
358 TestContextProvider::Create();
360 TestOutputSurface
output_surface(context_provider
);
362 FakeOutputSurfaceClient client
;
363 EXPECT_TRUE(output_surface
.BindToClient(&client
));
365 ManagedMemoryPolicy
policy(0);
366 policy
.bytes_limit_when_visible
= 1234;
367 policy
.priority_cutoff_when_visible
=
368 ManagedMemoryPolicy::CUTOFF_ALLOW_REQUIRED_ONLY
;
369 policy
.bytes_limit_when_not_visible
= 4567;
370 policy
.priority_cutoff_when_not_visible
=
371 ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING
;
373 bool discard_backbuffer_when_not_visible
= false;
375 context_provider
->SetMemoryAllocation(policy
,
376 discard_backbuffer_when_not_visible
);
377 EXPECT_EQ(1234u, client
.memory_policy().bytes_limit_when_visible
);
378 EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_REQUIRED_ONLY
,
379 client
.memory_policy().priority_cutoff_when_visible
);
380 EXPECT_EQ(4567u, client
.memory_policy().bytes_limit_when_not_visible
);
381 EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING
,
382 client
.memory_policy().priority_cutoff_when_not_visible
);
383 EXPECT_FALSE(client
.discard_backbuffer_when_not_visible());
385 discard_backbuffer_when_not_visible
= true;
386 context_provider
->SetMemoryAllocation(policy
,
387 discard_backbuffer_when_not_visible
);
388 EXPECT_TRUE(client
.discard_backbuffer_when_not_visible());
390 policy
.priority_cutoff_when_visible
=
391 ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING
;
392 policy
.priority_cutoff_when_not_visible
=
393 ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE
;
394 context_provider
->SetMemoryAllocation(policy
,
395 discard_backbuffer_when_not_visible
);
396 EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING
,
397 client
.memory_policy().priority_cutoff_when_visible
);
398 EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE
,
399 client
.memory_policy().priority_cutoff_when_not_visible
);
401 // 0 bytes limit should be ignored.
402 policy
.bytes_limit_when_visible
= 0;
403 context_provider
->SetMemoryAllocation(policy
,
404 discard_backbuffer_when_not_visible
);
405 EXPECT_EQ(1234u, client
.memory_policy().bytes_limit_when_visible
);