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. 4 5 #include "cc/output/output_surface.h" 6 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" 19 20 namespace cc { 21 namespace { 22 23 class TestOutputSurface : public OutputSurface { 24 public: 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) {} 29 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) {} 34 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) {} 40 41 bool InitializeNewContext3d( 42 scoped_refptr<ContextProvider> new_context_provider) { 43 return InitializeAndSetContext3d(new_context_provider, 44 scoped_refptr<ContextProvider>()); 45 } 46 47 using OutputSurface::ReleaseGL; 48 49 void OnVSyncParametersChangedForTesting(base::TimeTicks timebase, 50 base::TimeDelta interval) { 51 OnVSyncParametersChanged(timebase, interval); 52 } 53 54 void BeginImplFrameForTesting() { 55 OutputSurface::BeginImplFrame(BeginFrameArgs::CreateExpiredForTesting()); 56 } 57 58 void DidSwapBuffersForTesting() { 59 DidSwapBuffers(); 60 } 61 62 int pending_swap_buffers() { 63 return pending_swap_buffers_; 64 } 65 66 void OnSwapBuffersCompleteForTesting() { 67 OnSwapBuffersComplete(); 68 } 69 70 void EnableRetroactiveBeginImplFrameDeadline( 71 bool enable, 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; 77 } 78 79 protected: 80 virtual void PostCheckForRetroactiveBeginImplFrame() OVERRIDE { 81 // For testing purposes, we check immediately rather than posting a task. 82 CheckForRetroactiveBeginImplFrame(); 83 } 84 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_; 90 } else { 91 return OutputSurface::RetroactiveBeginImplFrameDeadline(); 92 } 93 } 94 return base::TimeTicks(); 95 } 96 97 bool retroactive_begin_impl_frame_deadline_enabled_; 98 bool override_retroactive_period_; 99 base::TimeDelta retroactive_period_override_; 100 }; 101 102 class TestSoftwareOutputDevice : public SoftwareOutputDevice { 103 public: 104 TestSoftwareOutputDevice(); 105 virtual ~TestSoftwareOutputDevice(); 106 107 // Overriden from cc:SoftwareOutputDevice 108 virtual void DiscardBackbuffer() OVERRIDE; 109 virtual void EnsureBackbuffer() OVERRIDE; 110 111 int discard_backbuffer_count() { return discard_backbuffer_count_; } 112 int ensure_backbuffer_count() { return ensure_backbuffer_count_; } 113 114 private: 115 int discard_backbuffer_count_; 116 int ensure_backbuffer_count_; 117 }; 118 119 TestSoftwareOutputDevice::TestSoftwareOutputDevice() 120 : discard_backbuffer_count_(0), ensure_backbuffer_count_(0) {} 121 122 TestSoftwareOutputDevice::~TestSoftwareOutputDevice() {} 123 124 void TestSoftwareOutputDevice::DiscardBackbuffer() { 125 SoftwareOutputDevice::DiscardBackbuffer(); 126 discard_backbuffer_count_++; 127 } 128 129 void TestSoftwareOutputDevice::EnsureBackbuffer() { 130 SoftwareOutputDevice::EnsureBackbuffer(); 131 ensure_backbuffer_count_++; 132 } 133 134 TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientSuccess) { 135 TestOutputSurface output_surface(TestContextProvider::Create()); 136 EXPECT_FALSE(output_surface.HasClient()); 137 138 FakeOutputSurfaceClient client; 139 EXPECT_TRUE(output_surface.BindToClient(&client)); 140 EXPECT_TRUE(output_surface.HasClient()); 141 EXPECT_FALSE(client.deferred_initialize_called()); 142 143 // Verify DidLoseOutputSurface callback is hooked up correctly. 144 EXPECT_FALSE(client.did_lose_output_surface_called()); 145 output_surface.context_provider()->Context3d()->loseContextCHROMIUM( 146 GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB); 147 EXPECT_TRUE(client.did_lose_output_surface_called()); 148 } 149 150 TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientFailure) { 151 scoped_refptr<TestContextProvider> context_provider = 152 TestContextProvider::Create(); 153 154 // Lose the context so BindToClient fails. 155 context_provider->UnboundTestContext3d()->set_context_lost(true); 156 157 TestOutputSurface output_surface(context_provider); 158 EXPECT_FALSE(output_surface.HasClient()); 159 160 FakeOutputSurfaceClient client; 161 EXPECT_FALSE(output_surface.BindToClient(&client)); 162 EXPECT_FALSE(output_surface.HasClient()); 163 } 164 165 class OutputSurfaceTestInitializeNewContext3d : public ::testing::Test { 166 public: 167 OutputSurfaceTestInitializeNewContext3d() 168 : context_provider_(TestContextProvider::Create()), 169 output_surface_( 170 scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice)) {} 171 172 protected: 173 void BindOutputSurface() { 174 EXPECT_TRUE(output_surface_.BindToClient(&client_)); 175 EXPECT_TRUE(output_surface_.HasClient()); 176 } 177 178 void InitializeNewContextExpectFail() { 179 EXPECT_FALSE(output_surface_.InitializeNewContext3d(context_provider_)); 180 EXPECT_TRUE(output_surface_.HasClient()); 181 182 EXPECT_FALSE(output_surface_.context_provider()); 183 EXPECT_TRUE(output_surface_.software_device()); 184 } 185 186 scoped_refptr<TestContextProvider> context_provider_; 187 TestOutputSurface output_surface_; 188 FakeOutputSurfaceClient client_; 189 }; 190 191 TEST_F(OutputSurfaceTestInitializeNewContext3d, Success) { 192 BindOutputSurface(); 193 EXPECT_FALSE(client_.deferred_initialize_called()); 194 195 EXPECT_TRUE(output_surface_.InitializeNewContext3d(context_provider_)); 196 EXPECT_TRUE(client_.deferred_initialize_called()); 197 EXPECT_EQ(context_provider_, output_surface_.context_provider()); 198 199 EXPECT_FALSE(client_.did_lose_output_surface_called()); 200 context_provider_->Context3d()->loseContextCHROMIUM( 201 GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB); 202 EXPECT_TRUE(client_.did_lose_output_surface_called()); 203 204 output_surface_.ReleaseGL(); 205 EXPECT_FALSE(output_surface_.context_provider()); 206 } 207 208 TEST_F(OutputSurfaceTestInitializeNewContext3d, Context3dMakeCurrentFails) { 209 BindOutputSurface(); 210 211 context_provider_->UnboundTestContext3d()->set_context_lost(true); 212 InitializeNewContextExpectFail(); 213 } 214 215 TEST_F(OutputSurfaceTestInitializeNewContext3d, ClientDeferredInitializeFails) { 216 BindOutputSurface(); 217 client_.set_deferred_initialize_result(false); 218 InitializeNewContextExpectFail(); 219 } 220 221 TEST(OutputSurfaceTest, BeginImplFrameEmulation) { 222 TestOutputSurface output_surface(TestContextProvider::Create()); 223 EXPECT_FALSE(output_surface.HasClient()); 224 225 FakeOutputSurfaceClient client; 226 EXPECT_TRUE(output_surface.BindToClient(&client)); 227 EXPECT_TRUE(output_surface.HasClient()); 228 EXPECT_FALSE(client.deferred_initialize_called()); 229 230 // Initialize BeginImplFrame emulation 231 scoped_refptr<base::TestSimpleTaskRunner> task_runner = 232 new base::TestSimpleTaskRunner; 233 bool throttle_frame_production = true; 234 const base::TimeDelta display_refresh_interval = 235 BeginFrameArgs::DefaultInterval(); 236 237 output_surface.InitializeBeginImplFrameEmulation( 238 task_runner.get(), 239 throttle_frame_production, 240 display_refresh_interval); 241 242 output_surface.SetMaxFramesPending(2); 243 output_surface.EnableRetroactiveBeginImplFrameDeadline( 244 false, false, base::TimeDelta()); 245 246 // We should start off with 0 BeginImplFrames 247 EXPECT_EQ(client.begin_impl_frame_count(), 0); 248 EXPECT_EQ(output_surface.pending_swap_buffers(), 0); 249 250 // We should not have a pending task until a BeginImplFrame has been 251 // requested. 252 EXPECT_FALSE(task_runner->HasPendingTask()); 253 output_surface.SetNeedsBeginImplFrame(true); 254 EXPECT_TRUE(task_runner->HasPendingTask()); 255 256 // BeginImplFrame should be called on the first tick. 257 task_runner->RunPendingTasks(); 258 EXPECT_EQ(client.begin_impl_frame_count(), 1); 259 EXPECT_EQ(output_surface.pending_swap_buffers(), 0); 260 261 // BeginImplFrame should not be called when there is a pending BeginImplFrame. 262 task_runner->RunPendingTasks(); 263 EXPECT_EQ(client.begin_impl_frame_count(), 1); 264 EXPECT_EQ(output_surface.pending_swap_buffers(), 0); 265 266 // SetNeedsBeginImplFrame should clear the pending BeginImplFrame after 267 // a SwapBuffers. 268 output_surface.DidSwapBuffersForTesting(); 269 output_surface.SetNeedsBeginImplFrame(true); 270 EXPECT_EQ(client.begin_impl_frame_count(), 1); 271 EXPECT_EQ(output_surface.pending_swap_buffers(), 1); 272 task_runner->RunPendingTasks(); 273 EXPECT_EQ(client.begin_impl_frame_count(), 2); 274 EXPECT_EQ(output_surface.pending_swap_buffers(), 1); 275 276 // BeginImplFrame should be throttled by pending swap buffers. 277 output_surface.DidSwapBuffersForTesting(); 278 output_surface.SetNeedsBeginImplFrame(true); 279 EXPECT_EQ(client.begin_impl_frame_count(), 2); 280 EXPECT_EQ(output_surface.pending_swap_buffers(), 2); 281 task_runner->RunPendingTasks(); 282 EXPECT_EQ(client.begin_impl_frame_count(), 2); 283 EXPECT_EQ(output_surface.pending_swap_buffers(), 2); 284 285 // SwapAck should decrement pending swap buffers and unblock BeginImplFrame 286 // again. 287 output_surface.OnSwapBuffersCompleteForTesting(); 288 EXPECT_EQ(client.begin_impl_frame_count(), 2); 289 EXPECT_EQ(output_surface.pending_swap_buffers(), 1); 290 task_runner->RunPendingTasks(); 291 EXPECT_EQ(client.begin_impl_frame_count(), 3); 292 EXPECT_EQ(output_surface.pending_swap_buffers(), 1); 293 294 // Calling SetNeedsBeginImplFrame again indicates a swap did not occur but 295 // the client still wants another BeginImplFrame. 296 output_surface.SetNeedsBeginImplFrame(true); 297 task_runner->RunPendingTasks(); 298 EXPECT_EQ(client.begin_impl_frame_count(), 4); 299 EXPECT_EQ(output_surface.pending_swap_buffers(), 1); 300 301 // Disabling SetNeedsBeginImplFrame should prevent further BeginImplFrames. 302 output_surface.SetNeedsBeginImplFrame(false); 303 task_runner->RunPendingTasks(); 304 EXPECT_FALSE(task_runner->HasPendingTask()); 305 EXPECT_EQ(client.begin_impl_frame_count(), 4); 306 EXPECT_EQ(output_surface.pending_swap_buffers(), 1); 307 } 308 309 TEST(OutputSurfaceTest, OptimisticAndRetroactiveBeginImplFrames) { 310 TestOutputSurface output_surface(TestContextProvider::Create()); 311 EXPECT_FALSE(output_surface.HasClient()); 312 313 FakeOutputSurfaceClient client; 314 EXPECT_TRUE(output_surface.BindToClient(&client)); 315 EXPECT_TRUE(output_surface.HasClient()); 316 EXPECT_FALSE(client.deferred_initialize_called()); 317 318 output_surface.SetMaxFramesPending(2); 319 output_surface.EnableRetroactiveBeginImplFrameDeadline( 320 true, false, base::TimeDelta()); 321 322 // Optimistically injected BeginImplFrames should be throttled if 323 // SetNeedsBeginImplFrame is false... 324 output_surface.SetNeedsBeginImplFrame(false); 325 output_surface.BeginImplFrameForTesting(); 326 EXPECT_EQ(client.begin_impl_frame_count(), 0); 327 // ...and retroactively triggered by a SetNeedsBeginImplFrame. 328 output_surface.SetNeedsBeginImplFrame(true); 329 EXPECT_EQ(client.begin_impl_frame_count(), 1); 330 331 // Optimistically injected BeginImplFrames should be throttled by pending 332 // BeginImplFrames... 333 output_surface.BeginImplFrameForTesting(); 334 EXPECT_EQ(client.begin_impl_frame_count(), 1); 335 // ...and retroactively triggered by a SetNeedsBeginImplFrame. 336 output_surface.SetNeedsBeginImplFrame(true); 337 EXPECT_EQ(client.begin_impl_frame_count(), 2); 338 // ...or retroactively triggered by a Swap. 339 output_surface.BeginImplFrameForTesting(); 340 EXPECT_EQ(client.begin_impl_frame_count(), 2); 341 output_surface.DidSwapBuffersForTesting(); 342 output_surface.SetNeedsBeginImplFrame(true); 343 EXPECT_EQ(client.begin_impl_frame_count(), 3); 344 EXPECT_EQ(output_surface.pending_swap_buffers(), 1); 345 346 // Optimistically injected BeginImplFrames should be by throttled by pending 347 // swap buffers... 348 output_surface.DidSwapBuffersForTesting(); 349 output_surface.SetNeedsBeginImplFrame(true); 350 EXPECT_EQ(client.begin_impl_frame_count(), 3); 351 EXPECT_EQ(output_surface.pending_swap_buffers(), 2); 352 output_surface.BeginImplFrameForTesting(); 353 EXPECT_EQ(client.begin_impl_frame_count(), 3); 354 // ...and retroactively triggered by OnSwapBuffersComplete 355 output_surface.OnSwapBuffersCompleteForTesting(); 356 EXPECT_EQ(client.begin_impl_frame_count(), 4); 357 } 358 359 TEST(OutputSurfaceTest, 360 RetroactiveBeginImplFrameDoesNotDoubleTickWhenEmulating) { 361 scoped_refptr<TestContextProvider> context_provider = 362 TestContextProvider::Create(); 363 364 TestOutputSurface output_surface(context_provider); 365 EXPECT_FALSE(output_surface.HasClient()); 366 367 FakeOutputSurfaceClient client; 368 EXPECT_TRUE(output_surface.BindToClient(&client)); 369 EXPECT_TRUE(output_surface.HasClient()); 370 EXPECT_FALSE(client.deferred_initialize_called()); 371 372 base::TimeDelta big_interval = base::TimeDelta::FromSeconds(10); 373 374 // Initialize BeginImplFrame emulation 375 scoped_refptr<base::TestSimpleTaskRunner> task_runner = 376 new base::TestSimpleTaskRunner; 377 bool throttle_frame_production = true; 378 const base::TimeDelta display_refresh_interval = big_interval; 379 380 output_surface.InitializeBeginImplFrameEmulation( 381 task_runner.get(), 382 throttle_frame_production, 383 display_refresh_interval); 384 385 // We need to subtract an epsilon from Now() because some platforms have 386 // a slow clock. 387 output_surface.OnVSyncParametersChangedForTesting( 388 gfx::FrameTime::Now() - base::TimeDelta::FromSeconds(1), big_interval); 389 390 output_surface.SetMaxFramesPending(2); 391 output_surface.EnableRetroactiveBeginImplFrameDeadline( 392 true, true, big_interval); 393 394 // We should start off with 0 BeginImplFrames 395 EXPECT_EQ(client.begin_impl_frame_count(), 0); 396 EXPECT_EQ(output_surface.pending_swap_buffers(), 0); 397 398 // The first SetNeedsBeginImplFrame(true) should start a retroactive 399 // BeginImplFrame. 400 EXPECT_FALSE(task_runner->HasPendingTask()); 401 output_surface.SetNeedsBeginImplFrame(true); 402 EXPECT_TRUE(task_runner->HasPendingTask()); 403 EXPECT_GT(task_runner->NextPendingTaskDelay(), big_interval / 2); 404 EXPECT_EQ(client.begin_impl_frame_count(), 1); 405 406 output_surface.SetNeedsBeginImplFrame(false); 407 EXPECT_TRUE(task_runner->HasPendingTask()); 408 EXPECT_EQ(client.begin_impl_frame_count(), 1); 409 410 // The second SetNeedBeginImplFrame(true) should not retroactively start a 411 // BeginImplFrame if the timestamp would be the same as the previous 412 // BeginImplFrame. 413 output_surface.SetNeedsBeginImplFrame(true); 414 EXPECT_TRUE(task_runner->HasPendingTask()); 415 EXPECT_EQ(client.begin_impl_frame_count(), 1); 416 } 417 418 TEST(OutputSurfaceTest, MemoryAllocation) { 419 scoped_refptr<TestContextProvider> context_provider = 420 TestContextProvider::Create(); 421 422 TestOutputSurface output_surface(context_provider); 423 424 FakeOutputSurfaceClient client; 425 EXPECT_TRUE(output_surface.BindToClient(&client)); 426 427 ManagedMemoryPolicy policy(0); 428 policy.bytes_limit_when_visible = 1234; 429 policy.priority_cutoff_when_visible = 430 gpu::MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY; 431 432 context_provider->SetMemoryAllocation(policy); 433 EXPECT_EQ(1234u, client.memory_policy().bytes_limit_when_visible); 434 EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY, 435 client.memory_policy().priority_cutoff_when_visible); 436 437 policy.priority_cutoff_when_visible = 438 gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING; 439 context_provider->SetMemoryAllocation(policy); 440 EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING, 441 client.memory_policy().priority_cutoff_when_visible); 442 443 // 0 bytes limit should be ignored. 444 policy.bytes_limit_when_visible = 0; 445 context_provider->SetMemoryAllocation(policy); 446 EXPECT_EQ(1234u, client.memory_policy().bytes_limit_when_visible); 447 } 448 449 TEST(OutputSurfaceTest, SoftwareOutputDeviceBackbufferManagement) { 450 TestSoftwareOutputDevice* software_output_device = 451 new TestSoftwareOutputDevice(); 452 453 // TestOutputSurface now owns software_output_device and has responsibility to 454 // free it. 455 scoped_ptr<TestSoftwareOutputDevice> p(software_output_device); 456 TestOutputSurface output_surface(p.PassAs<SoftwareOutputDevice>()); 457 458 EXPECT_EQ(0, software_output_device->ensure_backbuffer_count()); 459 EXPECT_EQ(0, software_output_device->discard_backbuffer_count()); 460 461 output_surface.EnsureBackbuffer(); 462 EXPECT_EQ(1, software_output_device->ensure_backbuffer_count()); 463 EXPECT_EQ(0, software_output_device->discard_backbuffer_count()); 464 output_surface.DiscardBackbuffer(); 465 466 EXPECT_EQ(1, software_output_device->ensure_backbuffer_count()); 467 EXPECT_EQ(1, software_output_device->discard_backbuffer_count()); 468 } 469 470 } // namespace 471 } // namespace cc 472