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(scoped_ptr<SoftwareOutputDevice> software_device)
31 : OutputSurface(software_device.Pass()),
32 retroactive_begin_impl_frame_deadline_enabled_(false),
33 override_retroactive_period_(false) {}
35 TestOutputSurface(scoped_refptr<ContextProvider> context_provider,
36 scoped_ptr<SoftwareOutputDevice> software_device)
37 : OutputSurface(context_provider, software_device.Pass()),
38 retroactive_begin_impl_frame_deadline_enabled_(false),
39 override_retroactive_period_(false) {}
41 bool InitializeNewContext3d(
42 scoped_refptr<ContextProvider> new_context_provider) {
43 return InitializeAndSetContext3d(new_context_provider,
44 scoped_refptr<ContextProvider>());
47 using OutputSurface::ReleaseGL;
49 void CommitVSyncParametersForTesting(base::TimeTicks timebase,
50 base::TimeDelta interval) {
51 CommitVSyncParameters(timebase, interval);
54 void BeginImplFrameForTesting() {
55 OutputSurface::BeginImplFrame(BeginFrameArgs::CreateExpiredForTesting());
58 void DidSwapBuffersForTesting() {
62 int pending_swap_buffers() {
63 return pending_swap_buffers_;
66 void OnSwapBuffersCompleteForTesting() {
67 OnSwapBuffersComplete();
70 void EnableRetroactiveBeginImplFrameDeadline(
72 bool override_retroactive_period,
73 base::TimeDelta period_override) {
74 retroactive_begin_impl_frame_deadline_enabled_ = enable;
75 override_retroactive_period_ = override_retroactive_period;
76 retroactive_period_override_ = period_override;
80 virtual void PostCheckForRetroactiveBeginImplFrame() OVERRIDE {
81 // For testing purposes, we check immediately rather than posting a task.
82 CheckForRetroactiveBeginImplFrame();
85 virtual base::TimeTicks RetroactiveBeginImplFrameDeadline() OVERRIDE {
86 if (retroactive_begin_impl_frame_deadline_enabled_) {
87 if (override_retroactive_period_) {
88 return skipped_begin_impl_frame_args_.frame_time +
89 retroactive_period_override_;
91 return OutputSurface::RetroactiveBeginImplFrameDeadline();
94 return base::TimeTicks();
97 bool retroactive_begin_impl_frame_deadline_enabled_;
98 bool override_retroactive_period_;
99 base::TimeDelta retroactive_period_override_;
102 class TestSoftwareOutputDevice : public SoftwareOutputDevice {
104 TestSoftwareOutputDevice();
105 virtual ~TestSoftwareOutputDevice();
107 // Overriden from cc:SoftwareOutputDevice
108 virtual void DiscardBackbuffer() OVERRIDE;
109 virtual void EnsureBackbuffer() OVERRIDE;
111 int discard_backbuffer_count() { return discard_backbuffer_count_; }
112 int ensure_backbuffer_count() { return ensure_backbuffer_count_; }
115 int discard_backbuffer_count_;
116 int ensure_backbuffer_count_;
119 TestSoftwareOutputDevice::TestSoftwareOutputDevice()
120 : discard_backbuffer_count_(0), ensure_backbuffer_count_(0) {}
122 TestSoftwareOutputDevice::~TestSoftwareOutputDevice() {}
124 void TestSoftwareOutputDevice::DiscardBackbuffer() {
125 SoftwareOutputDevice::DiscardBackbuffer();
126 discard_backbuffer_count_++;
129 void TestSoftwareOutputDevice::EnsureBackbuffer() {
130 SoftwareOutputDevice::EnsureBackbuffer();
131 ensure_backbuffer_count_++;
134 TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientSuccess) {
135 scoped_refptr<TestContextProvider> provider = TestContextProvider::Create();
136 TestOutputSurface output_surface(provider);
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()->ContextGL()->LoseContextCHROMIUM(
147 GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
148 output_surface.context_provider()->ContextGL()->Flush();
149 EXPECT_TRUE(client.did_lose_output_surface_called());
152 TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientFailure) {
153 scoped_refptr<TestContextProvider> context_provider =
154 TestContextProvider::Create();
156 // Lose the context so BindToClient fails.
157 context_provider->UnboundTestContext3d()->set_context_lost(true);
159 TestOutputSurface output_surface(context_provider);
160 EXPECT_FALSE(output_surface.HasClient());
162 FakeOutputSurfaceClient client;
163 EXPECT_FALSE(output_surface.BindToClient(&client));
164 EXPECT_FALSE(output_surface.HasClient());
167 class OutputSurfaceTestInitializeNewContext3d : public ::testing::Test {
169 OutputSurfaceTestInitializeNewContext3d()
170 : context_provider_(TestContextProvider::Create()),
172 scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice)) {}
175 void BindOutputSurface() {
176 EXPECT_TRUE(output_surface_.BindToClient(&client_));
177 EXPECT_TRUE(output_surface_.HasClient());
180 void InitializeNewContextExpectFail() {
181 EXPECT_FALSE(output_surface_.InitializeNewContext3d(context_provider_));
182 EXPECT_TRUE(output_surface_.HasClient());
184 EXPECT_FALSE(output_surface_.context_provider());
185 EXPECT_TRUE(output_surface_.software_device());
188 scoped_refptr<TestContextProvider> context_provider_;
189 TestOutputSurface output_surface_;
190 FakeOutputSurfaceClient client_;
193 TEST_F(OutputSurfaceTestInitializeNewContext3d, Success) {
195 EXPECT_FALSE(client_.deferred_initialize_called());
197 EXPECT_TRUE(output_surface_.InitializeNewContext3d(context_provider_));
198 EXPECT_TRUE(client_.deferred_initialize_called());
199 EXPECT_EQ(context_provider_, output_surface_.context_provider());
201 EXPECT_FALSE(client_.did_lose_output_surface_called());
202 context_provider_->ContextGL()->LoseContextCHROMIUM(
203 GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
204 context_provider_->ContextGL()->Flush();
205 EXPECT_TRUE(client_.did_lose_output_surface_called());
207 output_surface_.ReleaseGL();
208 EXPECT_FALSE(output_surface_.context_provider());
211 TEST_F(OutputSurfaceTestInitializeNewContext3d, Context3dMakeCurrentFails) {
214 context_provider_->UnboundTestContext3d()->set_context_lost(true);
215 InitializeNewContextExpectFail();
218 TEST_F(OutputSurfaceTestInitializeNewContext3d, ClientDeferredInitializeFails) {
220 client_.set_deferred_initialize_result(false);
221 InitializeNewContextExpectFail();
224 TEST(OutputSurfaceTest, BeginImplFrameEmulation) {
225 TestOutputSurface output_surface(TestContextProvider::Create());
226 EXPECT_FALSE(output_surface.HasClient());
228 FakeOutputSurfaceClient client;
229 EXPECT_TRUE(output_surface.BindToClient(&client));
230 EXPECT_TRUE(output_surface.HasClient());
231 EXPECT_FALSE(client.deferred_initialize_called());
233 // Initialize BeginImplFrame emulation
234 scoped_refptr<base::TestSimpleTaskRunner> task_runner =
235 new base::TestSimpleTaskRunner;
236 bool throttle_frame_production = true;
237 const base::TimeDelta display_refresh_interval =
238 BeginFrameArgs::DefaultInterval();
240 output_surface.InitializeBeginImplFrameEmulation(
242 throttle_frame_production,
243 display_refresh_interval);
245 output_surface.SetMaxFramesPending(2);
246 output_surface.EnableRetroactiveBeginImplFrameDeadline(
247 false, false, base::TimeDelta());
249 // We should start off with 0 BeginImplFrames
250 EXPECT_EQ(client.begin_impl_frame_count(), 0);
251 EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
253 // We should not have a pending task until a BeginImplFrame has been
255 EXPECT_FALSE(task_runner->HasPendingTask());
256 output_surface.SetNeedsBeginImplFrame(true);
257 EXPECT_TRUE(task_runner->HasPendingTask());
259 // BeginImplFrame should be called on the first tick.
260 task_runner->RunPendingTasks();
261 EXPECT_EQ(client.begin_impl_frame_count(), 1);
262 EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
264 // BeginImplFrame should not be called when there is a pending BeginImplFrame.
265 task_runner->RunPendingTasks();
266 EXPECT_EQ(client.begin_impl_frame_count(), 1);
267 EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
269 // SetNeedsBeginImplFrame should clear the pending BeginImplFrame after
271 output_surface.DidSwapBuffersForTesting();
272 output_surface.SetNeedsBeginImplFrame(true);
273 EXPECT_EQ(client.begin_impl_frame_count(), 1);
274 EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
275 task_runner->RunPendingTasks();
276 EXPECT_EQ(client.begin_impl_frame_count(), 2);
277 EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
279 // BeginImplFrame should be throttled by pending swap buffers.
280 output_surface.DidSwapBuffersForTesting();
281 output_surface.SetNeedsBeginImplFrame(true);
282 EXPECT_EQ(client.begin_impl_frame_count(), 2);
283 EXPECT_EQ(output_surface.pending_swap_buffers(), 2);
284 task_runner->RunPendingTasks();
285 EXPECT_EQ(client.begin_impl_frame_count(), 2);
286 EXPECT_EQ(output_surface.pending_swap_buffers(), 2);
288 // SwapAck should decrement pending swap buffers and unblock BeginImplFrame
290 output_surface.OnSwapBuffersCompleteForTesting();
291 EXPECT_EQ(client.begin_impl_frame_count(), 2);
292 EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
293 task_runner->RunPendingTasks();
294 EXPECT_EQ(client.begin_impl_frame_count(), 3);
295 EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
297 // Calling SetNeedsBeginImplFrame again indicates a swap did not occur but
298 // the client still wants another BeginImplFrame.
299 output_surface.SetNeedsBeginImplFrame(true);
300 task_runner->RunPendingTasks();
301 EXPECT_EQ(client.begin_impl_frame_count(), 4);
302 EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
304 // Disabling SetNeedsBeginImplFrame should prevent further BeginImplFrames.
305 output_surface.SetNeedsBeginImplFrame(false);
306 task_runner->RunPendingTasks();
307 EXPECT_FALSE(task_runner->HasPendingTask());
308 EXPECT_EQ(client.begin_impl_frame_count(), 4);
309 EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
312 TEST(OutputSurfaceTest, OptimisticAndRetroactiveBeginImplFrames) {
313 TestOutputSurface output_surface(TestContextProvider::Create());
314 EXPECT_FALSE(output_surface.HasClient());
316 FakeOutputSurfaceClient client;
317 EXPECT_TRUE(output_surface.BindToClient(&client));
318 EXPECT_TRUE(output_surface.HasClient());
319 EXPECT_FALSE(client.deferred_initialize_called());
321 output_surface.SetMaxFramesPending(2);
322 output_surface.EnableRetroactiveBeginImplFrameDeadline(
323 true, false, base::TimeDelta());
325 // Optimistically injected BeginImplFrames should be throttled if
326 // SetNeedsBeginImplFrame is false...
327 output_surface.SetNeedsBeginImplFrame(false);
328 output_surface.BeginImplFrameForTesting();
329 EXPECT_EQ(client.begin_impl_frame_count(), 0);
330 // ...and retroactively triggered by a SetNeedsBeginImplFrame.
331 output_surface.SetNeedsBeginImplFrame(true);
332 EXPECT_EQ(client.begin_impl_frame_count(), 1);
334 // Optimistically injected BeginImplFrames should be throttled by pending
335 // BeginImplFrames...
336 output_surface.BeginImplFrameForTesting();
337 EXPECT_EQ(client.begin_impl_frame_count(), 1);
338 // ...and retroactively triggered by a SetNeedsBeginImplFrame.
339 output_surface.SetNeedsBeginImplFrame(true);
340 EXPECT_EQ(client.begin_impl_frame_count(), 2);
341 // ...or retroactively triggered by a Swap.
342 output_surface.BeginImplFrameForTesting();
343 EXPECT_EQ(client.begin_impl_frame_count(), 2);
344 output_surface.DidSwapBuffersForTesting();
345 output_surface.SetNeedsBeginImplFrame(true);
346 EXPECT_EQ(client.begin_impl_frame_count(), 3);
347 EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
349 // Optimistically injected BeginImplFrames should be by throttled by pending
351 output_surface.DidSwapBuffersForTesting();
352 output_surface.SetNeedsBeginImplFrame(true);
353 EXPECT_EQ(client.begin_impl_frame_count(), 3);
354 EXPECT_EQ(output_surface.pending_swap_buffers(), 2);
355 output_surface.BeginImplFrameForTesting();
356 EXPECT_EQ(client.begin_impl_frame_count(), 3);
357 // ...and retroactively triggered by OnSwapBuffersComplete
358 output_surface.OnSwapBuffersCompleteForTesting();
359 EXPECT_EQ(client.begin_impl_frame_count(), 4);
362 TEST(OutputSurfaceTest,
363 RetroactiveBeginImplFrameDoesNotDoubleTickWhenEmulating) {
364 scoped_refptr<TestContextProvider> context_provider =
365 TestContextProvider::Create();
367 TestOutputSurface output_surface(context_provider);
368 EXPECT_FALSE(output_surface.HasClient());
370 FakeOutputSurfaceClient client;
371 EXPECT_TRUE(output_surface.BindToClient(&client));
372 EXPECT_TRUE(output_surface.HasClient());
373 EXPECT_FALSE(client.deferred_initialize_called());
375 base::TimeDelta big_interval = base::TimeDelta::FromSeconds(10);
377 // Initialize BeginImplFrame emulation
378 scoped_refptr<base::TestSimpleTaskRunner> task_runner =
379 new base::TestSimpleTaskRunner;
380 bool throttle_frame_production = true;
381 const base::TimeDelta display_refresh_interval = big_interval;
383 output_surface.InitializeBeginImplFrameEmulation(
385 throttle_frame_production,
386 display_refresh_interval);
388 // We need to subtract an epsilon from Now() because some platforms have
390 output_surface.CommitVSyncParametersForTesting(
391 gfx::FrameTime::Now() - base::TimeDelta::FromSeconds(1), big_interval);
393 output_surface.SetMaxFramesPending(2);
394 output_surface.EnableRetroactiveBeginImplFrameDeadline(
395 true, true, big_interval);
397 // We should start off with 0 BeginImplFrames
398 EXPECT_EQ(client.begin_impl_frame_count(), 0);
399 EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
401 // The first SetNeedsBeginImplFrame(true) should start a retroactive
403 EXPECT_FALSE(task_runner->HasPendingTask());
404 output_surface.SetNeedsBeginImplFrame(true);
405 EXPECT_TRUE(task_runner->HasPendingTask());
406 EXPECT_GT(task_runner->NextPendingTaskDelay(), big_interval / 2);
407 EXPECT_EQ(client.begin_impl_frame_count(), 1);
409 output_surface.SetNeedsBeginImplFrame(false);
410 EXPECT_TRUE(task_runner->HasPendingTask());
411 EXPECT_EQ(client.begin_impl_frame_count(), 1);
413 // The second SetNeedBeginImplFrame(true) should not retroactively start a
414 // BeginImplFrame if the timestamp would be the same as the previous
416 output_surface.SetNeedsBeginImplFrame(true);
417 EXPECT_TRUE(task_runner->HasPendingTask());
418 EXPECT_EQ(client.begin_impl_frame_count(), 1);
421 TEST(OutputSurfaceTest, MemoryAllocation) {
422 scoped_refptr<TestContextProvider> context_provider =
423 TestContextProvider::Create();
425 TestOutputSurface output_surface(context_provider);
427 FakeOutputSurfaceClient client;
428 EXPECT_TRUE(output_surface.BindToClient(&client));
430 ManagedMemoryPolicy policy(0);
431 policy.bytes_limit_when_visible = 1234;
432 policy.priority_cutoff_when_visible =
433 gpu::MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY;
435 context_provider->SetMemoryAllocation(policy);
436 EXPECT_EQ(1234u, client.memory_policy().bytes_limit_when_visible);
437 EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY,
438 client.memory_policy().priority_cutoff_when_visible);
440 policy.priority_cutoff_when_visible =
441 gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING;
442 context_provider->SetMemoryAllocation(policy);
443 EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING,
444 client.memory_policy().priority_cutoff_when_visible);
446 // 0 bytes limit should be ignored.
447 policy.bytes_limit_when_visible = 0;
448 context_provider->SetMemoryAllocation(policy);
449 EXPECT_EQ(1234u, client.memory_policy().bytes_limit_when_visible);
452 TEST(OutputSurfaceTest, SoftwareOutputDeviceBackbufferManagement) {
453 TestSoftwareOutputDevice* software_output_device =
454 new TestSoftwareOutputDevice();
456 // TestOutputSurface now owns software_output_device and has responsibility to
458 scoped_ptr<TestSoftwareOutputDevice> p(software_output_device);
459 TestOutputSurface output_surface(p.PassAs<SoftwareOutputDevice>());
461 EXPECT_EQ(0, software_output_device->ensure_backbuffer_count());
462 EXPECT_EQ(0, software_output_device->discard_backbuffer_count());
464 output_surface.EnsureBackbuffer();
465 EXPECT_EQ(1, software_output_device->ensure_backbuffer_count());
466 EXPECT_EQ(0, software_output_device->discard_backbuffer_count());
467 output_surface.DiscardBackbuffer();
469 EXPECT_EQ(1, software_output_device->ensure_backbuffer_count());
470 EXPECT_EQ(1, software_output_device->discard_backbuffer_count());