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/output/managed_memory_policy.h"
9 #include "cc/output/output_surface_client.h"
10 #include "cc/output/software_output_device.h"
11 #include "cc/test/fake_output_surface.h"
12 #include "cc/test/fake_output_surface_client.h"
13 #include "cc/test/scheduler_test_common.h"
14 #include "cc/test/test_context_provider.h"
15 #include "cc/test/test_web_graphics_context_3d.h"
16 #include "gpu/GLES2/gl2extchromium.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "ui/gfx/frame_time.h"
23 class TestOutputSurface : public OutputSurface {
25 explicit TestOutputSurface(scoped_refptr<ContextProvider> context_provider)
26 : OutputSurface(context_provider),
27 retroactive_begin_impl_frame_deadline_enabled_(false),
28 override_retroactive_period_(false) {}
30 explicit TestOutputSurface(
31 scoped_ptr<cc::SoftwareOutputDevice> software_device)
32 : OutputSurface(software_device.Pass()),
33 retroactive_begin_impl_frame_deadline_enabled_(false),
34 override_retroactive_period_(false) {}
36 TestOutputSurface(scoped_refptr<ContextProvider> context_provider,
37 scoped_ptr<cc::SoftwareOutputDevice> software_device)
38 : OutputSurface(context_provider, software_device.Pass()),
39 retroactive_begin_impl_frame_deadline_enabled_(false),
40 override_retroactive_period_(false) {}
42 bool InitializeNewContext3d(
43 scoped_refptr<ContextProvider> new_context_provider) {
44 return InitializeAndSetContext3d(new_context_provider,
45 scoped_refptr<ContextProvider>());
48 using OutputSurface::ReleaseGL;
50 void OnVSyncParametersChangedForTesting(base::TimeTicks timebase,
51 base::TimeDelta interval) {
52 OnVSyncParametersChanged(timebase, interval);
55 void BeginImplFrameForTesting() {
56 OutputSurface::BeginImplFrame(BeginFrameArgs::CreateExpiredForTesting());
59 void DidSwapBuffersForTesting() {
63 int pending_swap_buffers() {
64 return pending_swap_buffers_;
67 void OnSwapBuffersCompleteForTesting() {
68 OnSwapBuffersComplete();
71 void EnableRetroactiveBeginImplFrameDeadline(
73 bool override_retroactive_period,
74 base::TimeDelta period_override) {
75 retroactive_begin_impl_frame_deadline_enabled_ = enable;
76 override_retroactive_period_ = override_retroactive_period;
77 retroactive_period_override_ = period_override;
81 virtual void PostCheckForRetroactiveBeginImplFrame() OVERRIDE {
82 // For testing purposes, we check immediately rather than posting a task.
83 CheckForRetroactiveBeginImplFrame();
86 virtual base::TimeTicks RetroactiveBeginImplFrameDeadline() OVERRIDE {
87 if (retroactive_begin_impl_frame_deadline_enabled_) {
88 if (override_retroactive_period_) {
89 return skipped_begin_impl_frame_args_.frame_time +
90 retroactive_period_override_;
92 return OutputSurface::RetroactiveBeginImplFrameDeadline();
95 return base::TimeTicks();
98 bool retroactive_begin_impl_frame_deadline_enabled_;
99 bool override_retroactive_period_;
100 base::TimeDelta retroactive_period_override_;
103 class TestSoftwareOutputDevice : public SoftwareOutputDevice {
105 TestSoftwareOutputDevice();
106 virtual ~TestSoftwareOutputDevice();
108 // Overriden from cc:SoftwareOutputDevice
109 virtual void DiscardBackbuffer() OVERRIDE;
110 virtual void EnsureBackbuffer() OVERRIDE;
112 int discard_backbuffer_count() { return discard_backbuffer_count_; }
113 int ensure_backbuffer_count() { return ensure_backbuffer_count_; }
116 int discard_backbuffer_count_;
117 int ensure_backbuffer_count_;
120 TestSoftwareOutputDevice::TestSoftwareOutputDevice()
121 : discard_backbuffer_count_(0), ensure_backbuffer_count_(0) {}
123 TestSoftwareOutputDevice::~TestSoftwareOutputDevice() {}
125 void TestSoftwareOutputDevice::DiscardBackbuffer() {
126 SoftwareOutputDevice::DiscardBackbuffer();
127 discard_backbuffer_count_++;
130 void TestSoftwareOutputDevice::EnsureBackbuffer() {
131 SoftwareOutputDevice::EnsureBackbuffer();
132 ensure_backbuffer_count_++;
135 TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientSuccess) {
136 TestOutputSurface output_surface(TestContextProvider::Create());
137 EXPECT_FALSE(output_surface.HasClient());
139 FakeOutputSurfaceClient client;
140 EXPECT_TRUE(output_surface.BindToClient(&client));
141 EXPECT_TRUE(output_surface.HasClient());
142 EXPECT_FALSE(client.deferred_initialize_called());
144 // Verify DidLoseOutputSurface callback is hooked up correctly.
145 EXPECT_FALSE(client.did_lose_output_surface_called());
146 output_surface.context_provider()->Context3d()->loseContextCHROMIUM(
147 GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
148 EXPECT_TRUE(client.did_lose_output_surface_called());
151 TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientFailure) {
152 scoped_refptr<TestContextProvider> context_provider =
153 TestContextProvider::Create();
155 // Lose the context so BindToClient fails.
156 context_provider->UnboundTestContext3d()->set_times_make_current_succeeds(0);
158 TestOutputSurface output_surface(context_provider);
159 EXPECT_FALSE(output_surface.HasClient());
161 FakeOutputSurfaceClient client;
162 EXPECT_FALSE(output_surface.BindToClient(&client));
163 EXPECT_FALSE(output_surface.HasClient());
166 class OutputSurfaceTestInitializeNewContext3d : public ::testing::Test {
168 OutputSurfaceTestInitializeNewContext3d()
169 : context_provider_(TestContextProvider::Create()),
171 scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice)) {}
174 void BindOutputSurface() {
175 EXPECT_TRUE(output_surface_.BindToClient(&client_));
176 EXPECT_TRUE(output_surface_.HasClient());
179 void InitializeNewContextExpectFail() {
180 EXPECT_FALSE(output_surface_.InitializeNewContext3d(context_provider_));
181 EXPECT_TRUE(output_surface_.HasClient());
183 EXPECT_FALSE(output_surface_.context_provider());
184 EXPECT_TRUE(output_surface_.software_device());
187 scoped_refptr<TestContextProvider> context_provider_;
188 TestOutputSurface output_surface_;
189 FakeOutputSurfaceClient client_;
192 TEST_F(OutputSurfaceTestInitializeNewContext3d, Success) {
194 EXPECT_FALSE(client_.deferred_initialize_called());
196 EXPECT_TRUE(output_surface_.InitializeNewContext3d(context_provider_));
197 EXPECT_TRUE(client_.deferred_initialize_called());
198 EXPECT_EQ(context_provider_, output_surface_.context_provider());
200 EXPECT_FALSE(client_.did_lose_output_surface_called());
201 context_provider_->Context3d()->loseContextCHROMIUM(
202 GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
203 EXPECT_TRUE(client_.did_lose_output_surface_called());
205 output_surface_.ReleaseGL();
206 EXPECT_FALSE(output_surface_.context_provider());
209 TEST_F(OutputSurfaceTestInitializeNewContext3d, Context3dMakeCurrentFails) {
212 context_provider_->UnboundTestContext3d()
213 ->set_times_make_current_succeeds(0);
214 InitializeNewContextExpectFail();
217 TEST_F(OutputSurfaceTestInitializeNewContext3d, ClientDeferredInitializeFails) {
219 client_.set_deferred_initialize_result(false);
220 InitializeNewContextExpectFail();
223 TEST(OutputSurfaceTest, BeginImplFrameEmulation) {
224 TestOutputSurface output_surface(TestContextProvider::Create());
225 EXPECT_FALSE(output_surface.HasClient());
227 FakeOutputSurfaceClient client;
228 EXPECT_TRUE(output_surface.BindToClient(&client));
229 EXPECT_TRUE(output_surface.HasClient());
230 EXPECT_FALSE(client.deferred_initialize_called());
232 // Initialize BeginImplFrame emulation
233 scoped_refptr<base::TestSimpleTaskRunner> task_runner =
234 new base::TestSimpleTaskRunner;
235 bool throttle_frame_production = true;
236 const base::TimeDelta display_refresh_interval =
237 BeginFrameArgs::DefaultInterval();
239 output_surface.InitializeBeginImplFrameEmulation(
241 throttle_frame_production,
242 display_refresh_interval);
244 output_surface.SetMaxFramesPending(2);
245 output_surface.EnableRetroactiveBeginImplFrameDeadline(
246 false, false, base::TimeDelta());
248 // We should start off with 0 BeginImplFrames
249 EXPECT_EQ(client.begin_impl_frame_count(), 0);
250 EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
252 // We should not have a pending task until a BeginImplFrame has been
254 EXPECT_FALSE(task_runner->HasPendingTask());
255 output_surface.SetNeedsBeginImplFrame(true);
256 EXPECT_TRUE(task_runner->HasPendingTask());
258 // BeginImplFrame should be called on the first tick.
259 task_runner->RunPendingTasks();
260 EXPECT_EQ(client.begin_impl_frame_count(), 1);
261 EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
263 // BeginImplFrame should not be called when there is a pending BeginImplFrame.
264 task_runner->RunPendingTasks();
265 EXPECT_EQ(client.begin_impl_frame_count(), 1);
266 EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
268 // SetNeedsBeginImplFrame should clear the pending BeginImplFrame after
270 output_surface.DidSwapBuffersForTesting();
271 output_surface.SetNeedsBeginImplFrame(true);
272 EXPECT_EQ(client.begin_impl_frame_count(), 1);
273 EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
274 task_runner->RunPendingTasks();
275 EXPECT_EQ(client.begin_impl_frame_count(), 2);
276 EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
278 // BeginImplFrame should be throttled by pending swap buffers.
279 output_surface.DidSwapBuffersForTesting();
280 output_surface.SetNeedsBeginImplFrame(true);
281 EXPECT_EQ(client.begin_impl_frame_count(), 2);
282 EXPECT_EQ(output_surface.pending_swap_buffers(), 2);
283 task_runner->RunPendingTasks();
284 EXPECT_EQ(client.begin_impl_frame_count(), 2);
285 EXPECT_EQ(output_surface.pending_swap_buffers(), 2);
287 // SwapAck should decrement pending swap buffers and unblock BeginImplFrame
289 output_surface.OnSwapBuffersCompleteForTesting();
290 EXPECT_EQ(client.begin_impl_frame_count(), 2);
291 EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
292 task_runner->RunPendingTasks();
293 EXPECT_EQ(client.begin_impl_frame_count(), 3);
294 EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
296 // Calling SetNeedsBeginImplFrame again indicates a swap did not occur but
297 // the client still wants another BeginImplFrame.
298 output_surface.SetNeedsBeginImplFrame(true);
299 task_runner->RunPendingTasks();
300 EXPECT_EQ(client.begin_impl_frame_count(), 4);
301 EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
303 // Disabling SetNeedsBeginImplFrame should prevent further BeginImplFrames.
304 output_surface.SetNeedsBeginImplFrame(false);
305 task_runner->RunPendingTasks();
306 EXPECT_FALSE(task_runner->HasPendingTask());
307 EXPECT_EQ(client.begin_impl_frame_count(), 4);
308 EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
311 TEST(OutputSurfaceTest, OptimisticAndRetroactiveBeginImplFrames) {
312 TestOutputSurface output_surface(TestContextProvider::Create());
313 EXPECT_FALSE(output_surface.HasClient());
315 FakeOutputSurfaceClient client;
316 EXPECT_TRUE(output_surface.BindToClient(&client));
317 EXPECT_TRUE(output_surface.HasClient());
318 EXPECT_FALSE(client.deferred_initialize_called());
320 output_surface.SetMaxFramesPending(2);
321 output_surface.EnableRetroactiveBeginImplFrameDeadline(
322 true, false, base::TimeDelta());
324 // Optimistically injected BeginImplFrames should be throttled if
325 // SetNeedsBeginImplFrame is false...
326 output_surface.SetNeedsBeginImplFrame(false);
327 output_surface.BeginImplFrameForTesting();
328 EXPECT_EQ(client.begin_impl_frame_count(), 0);
329 // ...and retroactively triggered by a SetNeedsBeginImplFrame.
330 output_surface.SetNeedsBeginImplFrame(true);
331 EXPECT_EQ(client.begin_impl_frame_count(), 1);
333 // Optimistically injected BeginImplFrames should be throttled by pending
334 // BeginImplFrames...
335 output_surface.BeginImplFrameForTesting();
336 EXPECT_EQ(client.begin_impl_frame_count(), 1);
337 // ...and retroactively triggered by a SetNeedsBeginImplFrame.
338 output_surface.SetNeedsBeginImplFrame(true);
339 EXPECT_EQ(client.begin_impl_frame_count(), 2);
340 // ...or retroactively triggered by a Swap.
341 output_surface.BeginImplFrameForTesting();
342 EXPECT_EQ(client.begin_impl_frame_count(), 2);
343 output_surface.DidSwapBuffersForTesting();
344 output_surface.SetNeedsBeginImplFrame(true);
345 EXPECT_EQ(client.begin_impl_frame_count(), 3);
346 EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
348 // Optimistically injected BeginImplFrames should be by throttled by pending
350 output_surface.DidSwapBuffersForTesting();
351 output_surface.SetNeedsBeginImplFrame(true);
352 EXPECT_EQ(client.begin_impl_frame_count(), 3);
353 EXPECT_EQ(output_surface.pending_swap_buffers(), 2);
354 output_surface.BeginImplFrameForTesting();
355 EXPECT_EQ(client.begin_impl_frame_count(), 3);
356 // ...and retroactively triggered by OnSwapBuffersComplete
357 output_surface.OnSwapBuffersCompleteForTesting();
358 EXPECT_EQ(client.begin_impl_frame_count(), 4);
361 TEST(OutputSurfaceTest,
362 RetroactiveBeginImplFrameDoesNotDoubleTickWhenEmulating) {
363 scoped_refptr<TestContextProvider> context_provider =
364 TestContextProvider::Create();
366 TestOutputSurface output_surface(context_provider);
367 EXPECT_FALSE(output_surface.HasClient());
369 FakeOutputSurfaceClient client;
370 EXPECT_TRUE(output_surface.BindToClient(&client));
371 EXPECT_TRUE(output_surface.HasClient());
372 EXPECT_FALSE(client.deferred_initialize_called());
374 base::TimeDelta big_interval = base::TimeDelta::FromSeconds(10);
376 // Initialize BeginImplFrame emulation
377 scoped_refptr<base::TestSimpleTaskRunner> task_runner =
378 new base::TestSimpleTaskRunner;
379 bool throttle_frame_production = true;
380 const base::TimeDelta display_refresh_interval = big_interval;
382 output_surface.InitializeBeginImplFrameEmulation(
384 throttle_frame_production,
385 display_refresh_interval);
387 // We need to subtract an epsilon from Now() because some platforms have
389 output_surface.OnVSyncParametersChangedForTesting(
390 gfx::FrameTime::Now() - base::TimeDelta::FromSeconds(1), big_interval);
392 output_surface.SetMaxFramesPending(2);
393 output_surface.EnableRetroactiveBeginImplFrameDeadline(
394 true, true, big_interval);
396 // We should start off with 0 BeginImplFrames
397 EXPECT_EQ(client.begin_impl_frame_count(), 0);
398 EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
400 // The first SetNeedsBeginImplFrame(true) should start a retroactive
402 EXPECT_FALSE(task_runner->HasPendingTask());
403 output_surface.SetNeedsBeginImplFrame(true);
404 EXPECT_TRUE(task_runner->HasPendingTask());
405 EXPECT_GT(task_runner->NextPendingTaskDelay(), big_interval / 2);
406 EXPECT_EQ(client.begin_impl_frame_count(), 1);
408 output_surface.SetNeedsBeginImplFrame(false);
409 EXPECT_TRUE(task_runner->HasPendingTask());
410 EXPECT_EQ(client.begin_impl_frame_count(), 1);
412 // The second SetNeedBeginImplFrame(true) should not retroactively start a
413 // BeginImplFrame if the timestamp would be the same as the previous
415 output_surface.SetNeedsBeginImplFrame(true);
416 EXPECT_TRUE(task_runner->HasPendingTask());
417 EXPECT_EQ(client.begin_impl_frame_count(), 1);
420 TEST(OutputSurfaceTest, MemoryAllocation) {
421 scoped_refptr<TestContextProvider> context_provider =
422 TestContextProvider::Create();
424 TestOutputSurface output_surface(context_provider);
426 FakeOutputSurfaceClient client;
427 EXPECT_TRUE(output_surface.BindToClient(&client));
429 ManagedMemoryPolicy policy(0);
430 policy.bytes_limit_when_visible = 1234;
431 policy.priority_cutoff_when_visible =
432 gpu::MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY;
434 context_provider->SetMemoryAllocation(policy);
435 EXPECT_EQ(1234u, client.memory_policy().bytes_limit_when_visible);
436 EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY,
437 client.memory_policy().priority_cutoff_when_visible);
439 policy.priority_cutoff_when_visible =
440 gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING;
441 context_provider->SetMemoryAllocation(policy);
442 EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING,
443 client.memory_policy().priority_cutoff_when_visible);
445 // 0 bytes limit should be ignored.
446 policy.bytes_limit_when_visible = 0;
447 context_provider->SetMemoryAllocation(policy);
448 EXPECT_EQ(1234u, client.memory_policy().bytes_limit_when_visible);
451 TEST(OutputSurfaceTest, SoftwareOutputDeviceBackbufferManagement) {
452 TestSoftwareOutputDevice* software_output_device =
453 new TestSoftwareOutputDevice();
455 // TestOutputSurface now owns software_output_device and has responsibility to
457 scoped_ptr<TestSoftwareOutputDevice> p(software_output_device);
458 TestOutputSurface output_surface(p.PassAs<SoftwareOutputDevice>());
460 EXPECT_EQ(0, software_output_device->ensure_backbuffer_count());
461 EXPECT_EQ(0, software_output_device->discard_backbuffer_count());
463 output_surface.EnsureBackbuffer();
464 EXPECT_EQ(1, software_output_device->ensure_backbuffer_count());
465 EXPECT_EQ(0, software_output_device->discard_backbuffer_count());
466 output_surface.DiscardBackbuffer();
468 EXPECT_EQ(1, software_output_device->ensure_backbuffer_count());
469 EXPECT_EQ(1, software_output_device->discard_backbuffer_count());