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();
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 class TestSoftwareOutputDevice
: public SoftwareOutputDevice
{
83 TestSoftwareOutputDevice();
84 virtual ~TestSoftwareOutputDevice();
86 // Overriden from cc:SoftwareOutputDevice
87 virtual void DiscardBackbuffer() OVERRIDE
;
88 virtual void EnsureBackbuffer() OVERRIDE
;
90 int discard_backbuffer_count() { return discard_backbuffer_count_
; }
91 int ensure_backbuffer_count() { return ensure_backbuffer_count_
; }
94 int discard_backbuffer_count_
;
95 int ensure_backbuffer_count_
;
98 TestSoftwareOutputDevice::TestSoftwareOutputDevice()
99 : discard_backbuffer_count_(0), ensure_backbuffer_count_(0) {}
101 TestSoftwareOutputDevice::~TestSoftwareOutputDevice() {}
103 void TestSoftwareOutputDevice::DiscardBackbuffer() {
104 SoftwareOutputDevice::DiscardBackbuffer();
105 discard_backbuffer_count_
++;
108 void TestSoftwareOutputDevice::EnsureBackbuffer() {
109 SoftwareOutputDevice::EnsureBackbuffer();
110 ensure_backbuffer_count_
++;
113 TEST(OutputSurfaceTest
, ClientPointerIndicatesBindToClientSuccess
) {
114 TestOutputSurface
output_surface(TestContextProvider::Create());
115 EXPECT_FALSE(output_surface
.HasClient());
117 FakeOutputSurfaceClient client
;
118 EXPECT_TRUE(output_surface
.BindToClient(&client
));
119 EXPECT_TRUE(output_surface
.HasClient());
120 EXPECT_FALSE(client
.deferred_initialize_called());
122 // Verify DidLoseOutputSurface callback is hooked up correctly.
123 EXPECT_FALSE(client
.did_lose_output_surface_called());
124 output_surface
.context_provider()->Context3d()->loseContextCHROMIUM(
125 GL_GUILTY_CONTEXT_RESET_ARB
, GL_INNOCENT_CONTEXT_RESET_ARB
);
126 EXPECT_TRUE(client
.did_lose_output_surface_called());
129 TEST(OutputSurfaceTest
, ClientPointerIndicatesBindToClientFailure
) {
130 scoped_refptr
<TestContextProvider
> context_provider
=
131 TestContextProvider::Create();
133 // Lose the context so BindToClient fails.
134 context_provider
->UnboundTestContext3d()->set_times_make_current_succeeds(0);
136 TestOutputSurface
output_surface(context_provider
);
137 EXPECT_FALSE(output_surface
.HasClient());
139 FakeOutputSurfaceClient client
;
140 EXPECT_FALSE(output_surface
.BindToClient(&client
));
141 EXPECT_FALSE(output_surface
.HasClient());
144 class OutputSurfaceTestInitializeNewContext3d
: public ::testing::Test
{
146 OutputSurfaceTestInitializeNewContext3d()
147 : context_provider_(TestContextProvider::Create()),
149 scoped_ptr
<SoftwareOutputDevice
>(new SoftwareOutputDevice
)) {}
152 void BindOutputSurface() {
153 EXPECT_TRUE(output_surface_
.BindToClient(&client_
));
154 EXPECT_TRUE(output_surface_
.HasClient());
157 void InitializeNewContextExpectFail() {
158 EXPECT_FALSE(output_surface_
.InitializeNewContext3d(context_provider_
));
159 EXPECT_TRUE(output_surface_
.HasClient());
161 EXPECT_FALSE(output_surface_
.context_provider());
162 EXPECT_TRUE(output_surface_
.software_device());
165 scoped_refptr
<TestContextProvider
> context_provider_
;
166 TestOutputSurface output_surface_
;
167 FakeOutputSurfaceClient client_
;
170 TEST_F(OutputSurfaceTestInitializeNewContext3d
, Success
) {
172 EXPECT_FALSE(client_
.deferred_initialize_called());
174 EXPECT_TRUE(output_surface_
.InitializeNewContext3d(context_provider_
));
175 EXPECT_TRUE(client_
.deferred_initialize_called());
176 EXPECT_EQ(context_provider_
, output_surface_
.context_provider());
178 EXPECT_FALSE(client_
.did_lose_output_surface_called());
179 context_provider_
->Context3d()->loseContextCHROMIUM(
180 GL_GUILTY_CONTEXT_RESET_ARB
, GL_INNOCENT_CONTEXT_RESET_ARB
);
181 EXPECT_TRUE(client_
.did_lose_output_surface_called());
183 output_surface_
.ReleaseGL();
184 EXPECT_FALSE(output_surface_
.context_provider());
187 TEST_F(OutputSurfaceTestInitializeNewContext3d
, Context3dMakeCurrentFails
) {
190 context_provider_
->UnboundTestContext3d()
191 ->set_times_make_current_succeeds(0);
192 InitializeNewContextExpectFail();
195 TEST_F(OutputSurfaceTestInitializeNewContext3d
, ClientDeferredInitializeFails
) {
197 client_
.set_deferred_initialize_result(false);
198 InitializeNewContextExpectFail();
201 TEST(OutputSurfaceTest
, BeginFrameEmulation
) {
202 TestOutputSurface
output_surface(TestContextProvider::Create());
203 EXPECT_FALSE(output_surface
.HasClient());
205 FakeOutputSurfaceClient client
;
206 EXPECT_TRUE(output_surface
.BindToClient(&client
));
207 EXPECT_TRUE(output_surface
.HasClient());
208 EXPECT_FALSE(client
.deferred_initialize_called());
210 // Initialize BeginFrame emulation
211 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
212 new base::TestSimpleTaskRunner
;
213 bool throttle_frame_production
= true;
214 const base::TimeDelta display_refresh_interval
=
215 BeginFrameArgs::DefaultInterval();
217 output_surface
.InitializeBeginFrameEmulation(
219 throttle_frame_production
,
220 display_refresh_interval
);
222 output_surface
.SetMaxFramesPending(2);
223 output_surface
.SetAlternateRetroactiveBeginFramePeriod(
224 base::TimeDelta::FromSeconds(-1));
226 // We should start off with 0 BeginFrames
227 EXPECT_EQ(client
.begin_frame_count(), 0);
228 EXPECT_EQ(output_surface
.pending_swap_buffers(), 0);
230 // We should not have a pending task until a BeginFrame has been requested.
231 EXPECT_FALSE(task_runner
->HasPendingTask());
232 output_surface
.SetNeedsBeginFrame(true);
233 EXPECT_TRUE(task_runner
->HasPendingTask());
235 // BeginFrame should be called on the first tick.
236 task_runner
->RunPendingTasks();
237 EXPECT_EQ(client
.begin_frame_count(), 1);
238 EXPECT_EQ(output_surface
.pending_swap_buffers(), 0);
240 // BeginFrame should not be called when there is a pending BeginFrame.
241 task_runner
->RunPendingTasks();
242 EXPECT_EQ(client
.begin_frame_count(), 1);
243 EXPECT_EQ(output_surface
.pending_swap_buffers(), 0);
245 // SetNeedsBeginFrame should clear the pending BeginFrame after
247 output_surface
.DidSwapBuffersForTesting();
248 output_surface
.SetNeedsBeginFrame(true);
249 EXPECT_EQ(client
.begin_frame_count(), 1);
250 EXPECT_EQ(output_surface
.pending_swap_buffers(), 1);
251 task_runner
->RunPendingTasks();
252 EXPECT_EQ(client
.begin_frame_count(), 2);
253 EXPECT_EQ(output_surface
.pending_swap_buffers(), 1);
255 // BeginFrame should be throttled by pending swap buffers.
256 output_surface
.DidSwapBuffersForTesting();
257 output_surface
.SetNeedsBeginFrame(true);
258 EXPECT_EQ(client
.begin_frame_count(), 2);
259 EXPECT_EQ(output_surface
.pending_swap_buffers(), 2);
260 task_runner
->RunPendingTasks();
261 EXPECT_EQ(client
.begin_frame_count(), 2);
262 EXPECT_EQ(output_surface
.pending_swap_buffers(), 2);
264 // SwapAck should decrement pending swap buffers and unblock BeginFrame again.
265 output_surface
.OnSwapBuffersCompleteForTesting();
266 EXPECT_EQ(client
.begin_frame_count(), 2);
267 EXPECT_EQ(output_surface
.pending_swap_buffers(), 1);
268 task_runner
->RunPendingTasks();
269 EXPECT_EQ(client
.begin_frame_count(), 3);
270 EXPECT_EQ(output_surface
.pending_swap_buffers(), 1);
272 // Calling SetNeedsBeginFrame again indicates a swap did not occur but
273 // the client still wants another BeginFrame.
274 output_surface
.SetNeedsBeginFrame(true);
275 task_runner
->RunPendingTasks();
276 EXPECT_EQ(client
.begin_frame_count(), 4);
277 EXPECT_EQ(output_surface
.pending_swap_buffers(), 1);
279 // Disabling SetNeedsBeginFrame should prevent further BeginFrames.
280 output_surface
.SetNeedsBeginFrame(false);
281 task_runner
->RunPendingTasks();
282 EXPECT_FALSE(task_runner
->HasPendingTask());
283 EXPECT_EQ(client
.begin_frame_count(), 4);
284 EXPECT_EQ(output_surface
.pending_swap_buffers(), 1);
287 TEST(OutputSurfaceTest
, OptimisticAndRetroactiveBeginFrames
) {
288 TestOutputSurface
output_surface(TestContextProvider::Create());
289 EXPECT_FALSE(output_surface
.HasClient());
291 FakeOutputSurfaceClient client
;
292 EXPECT_TRUE(output_surface
.BindToClient(&client
));
293 EXPECT_TRUE(output_surface
.HasClient());
294 EXPECT_FALSE(client
.deferred_initialize_called());
296 output_surface
.SetMaxFramesPending(2);
298 // Enable retroactive BeginFrames.
299 output_surface
.SetAlternateRetroactiveBeginFramePeriod(
300 base::TimeDelta::FromSeconds(100000));
302 // Optimistically injected BeginFrames should be throttled if
303 // SetNeedsBeginFrame is false...
304 output_surface
.SetNeedsBeginFrame(false);
305 output_surface
.BeginFrameForTesting();
306 EXPECT_EQ(client
.begin_frame_count(), 0);
307 // ...and retroactively triggered by a SetNeedsBeginFrame.
308 output_surface
.SetNeedsBeginFrame(true);
309 EXPECT_EQ(client
.begin_frame_count(), 1);
311 // Optimistically injected BeginFrames should be throttled by pending
313 output_surface
.BeginFrameForTesting();
314 EXPECT_EQ(client
.begin_frame_count(), 1);
315 // ...and retroactively triggered by a SetNeedsBeginFrame.
316 output_surface
.SetNeedsBeginFrame(true);
317 EXPECT_EQ(client
.begin_frame_count(), 2);
318 // ...or retroactively triggered by a Swap.
319 output_surface
.BeginFrameForTesting();
320 EXPECT_EQ(client
.begin_frame_count(), 2);
321 output_surface
.DidSwapBuffersForTesting();
322 output_surface
.SetNeedsBeginFrame(true);
323 EXPECT_EQ(client
.begin_frame_count(), 3);
324 EXPECT_EQ(output_surface
.pending_swap_buffers(), 1);
326 // Optimistically injected BeginFrames should be by throttled by pending
328 output_surface
.DidSwapBuffersForTesting();
329 output_surface
.SetNeedsBeginFrame(true);
330 EXPECT_EQ(client
.begin_frame_count(), 3);
331 EXPECT_EQ(output_surface
.pending_swap_buffers(), 2);
332 output_surface
.BeginFrameForTesting();
333 EXPECT_EQ(client
.begin_frame_count(), 3);
334 // ...and retroactively triggered by OnSwapBuffersComplete
335 output_surface
.OnSwapBuffersCompleteForTesting();
336 EXPECT_EQ(client
.begin_frame_count(), 4);
339 TEST(OutputSurfaceTest
, RetroactiveBeginFrameDoesNotDoubleTickWhenEmulating
) {
340 scoped_refptr
<TestContextProvider
> context_provider
=
341 TestContextProvider::Create();
343 TestOutputSurface
output_surface(context_provider
);
344 EXPECT_FALSE(output_surface
.HasClient());
346 FakeOutputSurfaceClient client
;
347 EXPECT_TRUE(output_surface
.BindToClient(&client
));
348 EXPECT_TRUE(output_surface
.HasClient());
349 EXPECT_FALSE(client
.deferred_initialize_called());
351 base::TimeDelta big_interval
= base::TimeDelta::FromSeconds(1000);
353 // Initialize BeginFrame emulation
354 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
355 new base::TestSimpleTaskRunner
;
356 bool throttle_frame_production
= true;
357 const base::TimeDelta display_refresh_interval
= big_interval
;
359 output_surface
.InitializeBeginFrameEmulation(
361 throttle_frame_production
,
362 display_refresh_interval
);
364 // We need to subtract an epsilon from Now() because some platforms have
366 output_surface
.OnVSyncParametersChangedForTesting(
367 base::TimeTicks::Now() - base::TimeDelta::FromMilliseconds(1),
368 display_refresh_interval
);
370 output_surface
.SetMaxFramesPending(2);
371 output_surface
.SetAlternateRetroactiveBeginFramePeriod(
372 base::TimeDelta::FromSeconds(-1));
374 // We should start off with 0 BeginFrames
375 EXPECT_EQ(client
.begin_frame_count(), 0);
376 EXPECT_EQ(output_surface
.pending_swap_buffers(), 0);
378 // The first SetNeedsBeginFrame(true) should start a retroactive BeginFrame.
379 output_surface
.SetNeedsBeginFrame(true);
380 EXPECT_TRUE(task_runner
->HasPendingTask());
381 EXPECT_GT(task_runner
->NextPendingTaskDelay(), big_interval
/ 2);
382 EXPECT_EQ(client
.begin_frame_count(), 1);
384 output_surface
.SetNeedsBeginFrame(false);
385 EXPECT_TRUE(task_runner
->HasPendingTask());
386 EXPECT_EQ(client
.begin_frame_count(), 1);
388 // The second SetNeedBeginFrame(true) should not retroactively start a
389 // BeginFrame if the timestamp would be the same as the previous BeginFrame.
390 output_surface
.SetNeedsBeginFrame(true);
391 EXPECT_TRUE(task_runner
->HasPendingTask());
392 EXPECT_EQ(client
.begin_frame_count(), 1);
395 TEST(OutputSurfaceTest
, MemoryAllocation
) {
396 scoped_refptr
<TestContextProvider
> context_provider
=
397 TestContextProvider::Create();
399 TestOutputSurface
output_surface(context_provider
);
401 FakeOutputSurfaceClient client
;
402 EXPECT_TRUE(output_surface
.BindToClient(&client
));
404 ManagedMemoryPolicy
policy(0);
405 policy
.bytes_limit_when_visible
= 1234;
406 policy
.priority_cutoff_when_visible
=
407 ManagedMemoryPolicy::CUTOFF_ALLOW_REQUIRED_ONLY
;
408 policy
.bytes_limit_when_not_visible
= 4567;
409 policy
.priority_cutoff_when_not_visible
=
410 ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING
;
412 bool discard_backbuffer_when_not_visible
= false;
414 context_provider
->SetMemoryAllocation(policy
,
415 discard_backbuffer_when_not_visible
);
416 EXPECT_EQ(1234u, client
.memory_policy().bytes_limit_when_visible
);
417 EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_REQUIRED_ONLY
,
418 client
.memory_policy().priority_cutoff_when_visible
);
419 EXPECT_EQ(4567u, client
.memory_policy().bytes_limit_when_not_visible
);
420 EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING
,
421 client
.memory_policy().priority_cutoff_when_not_visible
);
422 EXPECT_FALSE(client
.discard_backbuffer_when_not_visible());
424 discard_backbuffer_when_not_visible
= true;
425 context_provider
->SetMemoryAllocation(policy
,
426 discard_backbuffer_when_not_visible
);
427 EXPECT_TRUE(client
.discard_backbuffer_when_not_visible());
429 policy
.priority_cutoff_when_visible
=
430 ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING
;
431 policy
.priority_cutoff_when_not_visible
=
432 ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE
;
433 context_provider
->SetMemoryAllocation(policy
,
434 discard_backbuffer_when_not_visible
);
435 EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING
,
436 client
.memory_policy().priority_cutoff_when_visible
);
437 EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE
,
438 client
.memory_policy().priority_cutoff_when_not_visible
);
440 // 0 bytes limit should be ignored.
441 policy
.bytes_limit_when_visible
= 0;
442 context_provider
->SetMemoryAllocation(policy
,
443 discard_backbuffer_when_not_visible
);
444 EXPECT_EQ(1234u, client
.memory_policy().bytes_limit_when_visible
);
447 TEST(OutputSurfaceTest
, SoftwareOutputDeviceBackbufferManagement
) {
448 TestSoftwareOutputDevice
* software_output_device
=
449 new TestSoftwareOutputDevice();
451 // TestOutputSurface now owns software_output_device and has responsibility to
453 scoped_ptr
<TestSoftwareOutputDevice
> p(software_output_device
);
454 TestOutputSurface
output_surface(p
.PassAs
<SoftwareOutputDevice
>());
456 EXPECT_EQ(0, software_output_device
->ensure_backbuffer_count());
457 EXPECT_EQ(0, software_output_device
->discard_backbuffer_count());
459 output_surface
.EnsureBackbuffer();
460 EXPECT_EQ(1, software_output_device
->ensure_backbuffer_count());
461 EXPECT_EQ(0, software_output_device
->discard_backbuffer_count());
462 output_surface
.DiscardBackbuffer();
464 EXPECT_EQ(1, software_output_device
->ensure_backbuffer_count());
465 EXPECT_EQ(1, software_output_device
->discard_backbuffer_count());