OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stdint.h> | 5 #include <stdint.h> |
6 | 6 |
7 #include "base/macros.h" | 7 #include "base/macros.h" |
8 #include "base/run_loop.h" | 8 #include "base/run_loop.h" |
| 9 #include "base/test/test_mock_time_task_runner.h" |
9 #include "base/threading/thread_task_runner_handle.h" | 10 #include "base/threading/thread_task_runner_handle.h" |
10 #include "cc/output/begin_frame_args.h" | 11 #include "cc/output/begin_frame_args.h" |
11 #include "cc/surfaces/local_surface_id_allocator.h" | 12 #include "cc/surfaces/local_surface_id_allocator.h" |
12 #include "cc/surfaces/surface_factory.h" | 13 #include "cc/surfaces/surface_factory.h" |
13 #include "cc/surfaces/surface_factory_client.h" | 14 #include "cc/surfaces/surface_factory_client.h" |
14 #include "cc/surfaces/surface_manager.h" | 15 #include "cc/surfaces/surface_manager.h" |
15 #include "cc/test/begin_frame_args_test.h" | 16 #include "cc/test/begin_frame_args_test.h" |
16 #include "testing/gmock/include/gmock/gmock.h" | 17 #include "testing/gmock/include/gmock/gmock.h" |
17 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
18 #include "ui/compositor/compositor.h" | 19 #include "ui/compositor/compositor.h" |
19 #include "ui/compositor/layer.h" | 20 #include "ui/compositor/layer.h" |
20 #include "ui/compositor/test/context_factories_for_test.h" | 21 #include "ui/compositor/test/context_factories_for_test.h" |
21 #include "ui/compositor/test/draw_waiter_for_test.h" | 22 #include "ui/compositor/test/draw_waiter_for_test.h" |
22 | 23 |
23 using testing::Mock; | 24 using testing::Mock; |
24 using testing::_; | 25 using testing::_; |
25 | 26 |
26 namespace ui { | 27 namespace ui { |
27 namespace { | 28 namespace { |
28 | 29 |
29 // Test fixture for tests that require a ui::Compositor with a real task | |
30 // runner. | |
31 class CompositorTest : public testing::Test { | 30 class CompositorTest : public testing::Test { |
32 public: | 31 public: |
33 CompositorTest() {} | 32 CompositorTest() {} |
34 ~CompositorTest() override {} | 33 ~CompositorTest() override {} |
35 | 34 |
36 void SetUp() override { | 35 void SetUp() override { |
37 task_runner_ = base::ThreadTaskRunnerHandle::Get(); | |
38 | |
39 ui::ContextFactory* context_factory = nullptr; | 36 ui::ContextFactory* context_factory = nullptr; |
40 ui::ContextFactoryPrivate* context_factory_private = nullptr; | 37 ui::ContextFactoryPrivate* context_factory_private = nullptr; |
41 ui::InitializeContextFactoryForTests(false, &context_factory, | 38 ui::InitializeContextFactoryForTests(false, &context_factory, |
42 &context_factory_private); | 39 &context_factory_private); |
43 | 40 |
44 compositor_.reset(new ui::Compositor( | 41 compositor_.reset(new ui::Compositor( |
45 context_factory_private->AllocateFrameSinkId(), context_factory, | 42 context_factory_private->AllocateFrameSinkId(), context_factory, |
46 context_factory_private, task_runner_)); | 43 context_factory_private, CreateTaskRunner())); |
47 compositor_->SetAcceleratedWidget(gfx::kNullAcceleratedWidget); | 44 compositor_->SetAcceleratedWidget(gfx::kNullAcceleratedWidget); |
48 } | 45 } |
| 46 |
49 void TearDown() override { | 47 void TearDown() override { |
50 compositor_.reset(); | 48 compositor_.reset(); |
51 ui::TerminateContextFactoryForTests(); | 49 ui::TerminateContextFactoryForTests(); |
52 } | 50 } |
53 | 51 |
54 protected: | 52 void DestroyCompositor() { compositor_.reset(); } |
55 base::SingleThreadTaskRunner* task_runner() { return task_runner_.get(); } | 53 |
| 54 protected: |
| 55 virtual scoped_refptr<base::SingleThreadTaskRunner> CreateTaskRunner() = 0; |
| 56 |
56 ui::Compositor* compositor() { return compositor_.get(); } | 57 ui::Compositor* compositor() { return compositor_.get(); } |
57 | 58 |
58 private: | 59 private: |
| 60 std::unique_ptr<ui::Compositor> compositor_; |
| 61 |
| 62 DISALLOW_COPY_AND_ASSIGN(CompositorTest); |
| 63 }; |
| 64 |
| 65 // For tests that control time. |
| 66 class CompositorTestWithMockedTime : public CompositorTest { |
| 67 protected: |
| 68 scoped_refptr<base::SingleThreadTaskRunner> CreateTaskRunner() override { |
| 69 task_runner_ = new base::TestMockTimeTaskRunner; |
| 70 return task_runner_; |
| 71 } |
| 72 |
| 73 base::TestMockTimeTaskRunner* task_runner() { return task_runner_.get(); } |
| 74 |
| 75 protected: |
| 76 scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; |
| 77 }; |
| 78 |
| 79 // For tests that run on a real MessageLoop with real time. |
| 80 class CompositorTestWithMessageLoop : public CompositorTest { |
| 81 protected: |
| 82 scoped_refptr<base::SingleThreadTaskRunner> CreateTaskRunner() override { |
| 83 task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
| 84 return task_runner_; |
| 85 } |
| 86 |
| 87 base::SequencedTaskRunner* task_runner() { return task_runner_.get(); } |
| 88 |
| 89 private: |
59 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 90 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
60 std::unique_ptr<ui::Compositor> compositor_; | 91 }; |
61 | 92 |
62 DISALLOW_COPY_AND_ASSIGN(CompositorTest); | 93 class CompositorObserverForLocks : public CompositorObserver { |
| 94 public: |
| 95 CompositorObserverForLocks() = default; |
| 96 |
| 97 void OnCompositingDidCommit(Compositor* compositor) override {} |
| 98 void OnCompositingStarted(Compositor* compositor, |
| 99 base::TimeTicks start_time) override {} |
| 100 void OnCompositingLockStateChanged(Compositor* compositor) override { |
| 101 changed_ = true; |
| 102 locked_ = compositor->IsLocked(); |
| 103 } |
| 104 void OnCompositingShuttingDown(Compositor* compositor) override {} |
| 105 |
| 106 bool changed() const { return changed_; } |
| 107 bool locked() const { return locked_; } |
| 108 |
| 109 void Reset() { changed_ = false; } |
| 110 |
| 111 private: |
| 112 bool changed_ = false; |
| 113 bool locked_ = false; |
| 114 }; |
| 115 |
| 116 class MockCompositorLockClient |
| 117 : NON_EXPORTED_BASE(public ui::CompositorLockClient) { |
| 118 public: |
| 119 MOCK_METHOD0(CompositorLockTimedOut, void()); |
63 }; | 120 }; |
64 | 121 |
65 } // namespace | 122 } // namespace |
66 | 123 |
67 TEST_F(CompositorTest, LocksTimeOut) { | 124 TEST_F(CompositorTestWithMockedTime, LocksAreObserved) { |
68 scoped_refptr<ui::CompositorLock> lock; | 125 std::unique_ptr<CompositorLock> lock; |
69 { | 126 |
70 base::RunLoop run_loop; | 127 CompositorObserverForLocks observer; |
71 // Ensure that the lock times out by default. | 128 compositor()->AddObserver(&observer); |
72 lock = compositor()->GetCompositorLock(); | 129 |
| 130 EXPECT_FALSE(observer.changed()); |
| 131 |
| 132 lock = compositor()->GetCompositorLock(nullptr, base::TimeDelta()); |
| 133 // The observer see that locks changed and that the compositor is locked |
| 134 // at the time. |
| 135 EXPECT_TRUE(observer.changed()); |
| 136 EXPECT_TRUE(observer.locked()); |
| 137 |
| 138 observer.Reset(); |
| 139 EXPECT_FALSE(observer.changed()); |
| 140 |
| 141 lock = nullptr; |
| 142 // The observer see that locks changed and that the compositor is not locked |
| 143 // at the time. |
| 144 EXPECT_TRUE(observer.changed()); |
| 145 EXPECT_FALSE(observer.locked()); |
| 146 |
| 147 compositor()->RemoveObserver(&observer); |
| 148 } |
| 149 |
| 150 TEST_F(CompositorTestWithMockedTime, LocksTimeOut) { |
| 151 std::unique_ptr<CompositorLock> lock; |
| 152 |
| 153 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(100); |
| 154 |
| 155 { |
| 156 testing::StrictMock<MockCompositorLockClient> lock_client; |
| 157 // This lock has a timeout. |
| 158 lock = compositor()->GetCompositorLock(&lock_client, timeout); |
73 EXPECT_TRUE(compositor()->IsLocked()); | 159 EXPECT_TRUE(compositor()->IsLocked()); |
74 task_runner()->PostDelayedTask( | 160 EXPECT_CALL(lock_client, CompositorLockTimedOut()).Times(1); |
75 FROM_HERE, run_loop.QuitClosure(), | 161 task_runner()->FastForwardBy(timeout); |
76 base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs)); | 162 task_runner()->RunUntilIdle(); |
77 run_loop.Run(); | |
78 EXPECT_FALSE(compositor()->IsLocked()); | 163 EXPECT_FALSE(compositor()->IsLocked()); |
79 } | 164 } |
80 | 165 |
81 { | 166 { |
82 base::RunLoop run_loop; | 167 testing::StrictMock<MockCompositorLockClient> lock_client; |
83 // Ensure that the lock does not time out when set. | 168 // This lock has no timeout. |
84 compositor()->SetLocksWillTimeOut(false); | 169 lock = compositor()->GetCompositorLock(&lock_client, base::TimeDelta()); |
85 lock = compositor()->GetCompositorLock(); | |
86 EXPECT_TRUE(compositor()->IsLocked()); | 170 EXPECT_TRUE(compositor()->IsLocked()); |
87 task_runner()->PostDelayedTask( | 171 EXPECT_CALL(lock_client, CompositorLockTimedOut()).Times(0); |
88 FROM_HERE, run_loop.QuitClosure(), | 172 task_runner()->FastForwardBy(timeout); |
89 base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs)); | 173 task_runner()->RunUntilIdle(); |
90 run_loop.Run(); | |
91 EXPECT_TRUE(compositor()->IsLocked()); | 174 EXPECT_TRUE(compositor()->IsLocked()); |
92 } | 175 } |
93 } | 176 } |
94 | 177 |
95 TEST_F(CompositorTest, ReleaseWidgetWithOutputSurfaceNeverCreated) { | 178 TEST_F(CompositorTestWithMockedTime, MultipleLockClients) { |
| 179 testing::StrictMock<MockCompositorLockClient> lock_client1; |
| 180 std::unique_ptr<CompositorLock> lock1; |
| 181 testing::StrictMock<MockCompositorLockClient> lock_client2; |
| 182 std::unique_ptr<CompositorLock> lock2; |
| 183 |
| 184 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(1); |
| 185 // Both locks are grabbed from the Compositor with a separate client. |
| 186 lock1 = compositor()->GetCompositorLock(&lock_client1, timeout); |
| 187 lock2 = compositor()->GetCompositorLock(&lock_client2, timeout); |
| 188 EXPECT_TRUE(compositor()->IsLocked()); |
| 189 // Both clients get notified of timeout. |
| 190 EXPECT_CALL(lock_client1, CompositorLockTimedOut()).Times(1); |
| 191 EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(1); |
| 192 task_runner()->FastForwardBy(timeout); |
| 193 task_runner()->RunUntilIdle(); |
| 194 EXPECT_FALSE(compositor()->IsLocked()); |
| 195 } |
| 196 |
| 197 TEST_F(CompositorTestWithMockedTime, ExtendingLifeOfLockDoesntUseDeadClient) { |
| 198 testing::StrictMock<MockCompositorLockClient> lock_client1; |
| 199 std::unique_ptr<CompositorLock> lock1; |
| 200 testing::StrictMock<MockCompositorLockClient> lock_client2; |
| 201 std::unique_ptr<CompositorLock> lock2; |
| 202 |
| 203 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(1); |
| 204 |
| 205 // One lock is grabbed from the compositor with a client. The other |
| 206 // extends its lifetime past that of the first. |
| 207 lock1 = compositor()->GetCompositorLock(&lock_client1, timeout); |
| 208 EXPECT_TRUE(compositor()->IsLocked()); |
| 209 |
| 210 // This also locks the compositor and will do so past |lock1| ending. |
| 211 lock2 = compositor()->GetCompositorLock(&lock_client2, timeout); |
| 212 // |lock1| is destroyed, so it won't timeout but |lock2| will. |
| 213 lock1 = nullptr; |
| 214 |
| 215 EXPECT_CALL(lock_client1, CompositorLockTimedOut()).Times(0); |
| 216 EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(1); |
| 217 task_runner()->FastForwardBy(timeout); |
| 218 task_runner()->RunUntilIdle(); |
| 219 |
| 220 EXPECT_FALSE(compositor()->IsLocked()); |
| 221 } |
| 222 |
| 223 TEST_F(CompositorTestWithMockedTime, AddingLocksDoesNotExtendTimeout) { |
| 224 testing::StrictMock<MockCompositorLockClient> lock_client1; |
| 225 std::unique_ptr<CompositorLock> lock1; |
| 226 testing::StrictMock<MockCompositorLockClient> lock_client2; |
| 227 std::unique_ptr<CompositorLock> lock2; |
| 228 |
| 229 base::TimeDelta timeout1 = base::TimeDelta::FromMilliseconds(1); |
| 230 base::TimeDelta timeout2 = base::TimeDelta::FromMilliseconds(10); |
| 231 |
| 232 // The first lock has a short timeout. |
| 233 lock1 = compositor()->GetCompositorLock(&lock_client1, timeout1); |
| 234 EXPECT_TRUE(compositor()->IsLocked()); |
| 235 |
| 236 // The second lock has a longer timeout, but since a lock is active, |
| 237 // the first one is used for both. |
| 238 lock2 = compositor()->GetCompositorLock(&lock_client2, timeout2); |
| 239 |
| 240 EXPECT_CALL(lock_client1, CompositorLockTimedOut()).Times(1); |
| 241 EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(1); |
| 242 task_runner()->FastForwardBy(timeout1); |
| 243 task_runner()->RunUntilIdle(); |
| 244 EXPECT_FALSE(compositor()->IsLocked()); |
| 245 } |
| 246 |
| 247 TEST_F(CompositorTestWithMockedTime, LockIsDestroyedDoesntTimeout) { |
| 248 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(1); |
| 249 |
| 250 testing::StrictMock<MockCompositorLockClient> lock_client1; |
| 251 std::unique_ptr<CompositorLock> lock1; |
| 252 lock1 = compositor()->GetCompositorLock(&lock_client1, timeout); |
| 253 EXPECT_TRUE(compositor()->IsLocked()); |
| 254 // The CompositorLockClient is destroyed when |lock1| is released. |
| 255 lock1 = nullptr; |
| 256 // The client isn't called as a result. |
| 257 EXPECT_CALL(lock_client1, CompositorLockTimedOut()).Times(0); |
| 258 task_runner()->FastForwardBy(timeout); |
| 259 task_runner()->RunUntilIdle(); |
| 260 EXPECT_FALSE(compositor()->IsLocked()); |
| 261 } |
| 262 |
| 263 TEST_F(CompositorTestWithMockedTime, TimeoutEndsWhenLockEnds) { |
| 264 testing::StrictMock<MockCompositorLockClient> lock_client1; |
| 265 std::unique_ptr<CompositorLock> lock1; |
| 266 testing::StrictMock<MockCompositorLockClient> lock_client2; |
| 267 std::unique_ptr<CompositorLock> lock2; |
| 268 |
| 269 base::TimeDelta timeout1 = base::TimeDelta::FromMilliseconds(1); |
| 270 base::TimeDelta timeout2 = base::TimeDelta::FromMilliseconds(10); |
| 271 |
| 272 // The first lock has a short timeout. |
| 273 lock1 = compositor()->GetCompositorLock(&lock_client1, timeout1); |
| 274 EXPECT_TRUE(compositor()->IsLocked()); |
| 275 // But the first lock is ended before timeout. |
| 276 lock1 = nullptr; |
| 277 EXPECT_FALSE(compositor()->IsLocked()); |
| 278 |
| 279 // The second lock has a longer timeout, and it should use that timeout, |
| 280 // since the first lock is done. |
| 281 lock2 = compositor()->GetCompositorLock(&lock_client2, timeout2); |
| 282 EXPECT_TRUE(compositor()->IsLocked()); |
| 283 |
| 284 { |
| 285 // The second lock doesn't timeout from the first lock which has ended. |
| 286 EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(0); |
| 287 task_runner()->FastForwardBy(timeout1); |
| 288 task_runner()->RunUntilIdle(); |
| 289 } |
| 290 |
| 291 { |
| 292 // The second lock can still timeout on its own though. |
| 293 EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(1); |
| 294 task_runner()->FastForwardBy(timeout2 - timeout1); |
| 295 task_runner()->RunUntilIdle(); |
| 296 } |
| 297 |
| 298 EXPECT_FALSE(compositor()->IsLocked()); |
| 299 } |
| 300 |
| 301 TEST_F(CompositorTestWithMockedTime, CompositorLockOutlivesCompositor) { |
| 302 testing::StrictMock<MockCompositorLockClient> lock_client1; |
| 303 std::unique_ptr<CompositorLock> lock1; |
| 304 |
| 305 lock1 = compositor()->GetCompositorLock(&lock_client1, base::TimeDelta()); |
| 306 // The compositor is destroyed before the lock. |
| 307 DestroyCompositor(); |
| 308 // This doesn't crash. |
| 309 lock1 = nullptr; |
| 310 } |
| 311 |
| 312 TEST_F(CompositorTestWithMockedTime, |
| 313 ReleaseWidgetWithOutputSurfaceNeverCreated) { |
96 compositor()->SetVisible(false); | 314 compositor()->SetVisible(false); |
97 EXPECT_EQ(gfx::kNullAcceleratedWidget, | 315 EXPECT_EQ(gfx::kNullAcceleratedWidget, |
98 compositor()->ReleaseAcceleratedWidget()); | 316 compositor()->ReleaseAcceleratedWidget()); |
99 compositor()->SetAcceleratedWidget(gfx::kNullAcceleratedWidget); | 317 compositor()->SetAcceleratedWidget(gfx::kNullAcceleratedWidget); |
100 compositor()->SetVisible(true); | 318 compositor()->SetVisible(true); |
101 } | 319 } |
102 | 320 |
103 #if defined(OS_WIN) | 321 #if defined(OS_WIN) |
104 // TODO(crbug.com/608436): Flaky on windows trybots | 322 // TODO(crbug.com/608436): Flaky on windows trybots |
105 #define MAYBE_CreateAndReleaseOutputSurface \ | 323 #define MAYBE_CreateAndReleaseOutputSurface \ |
106 DISABLED_CreateAndReleaseOutputSurface | 324 DISABLED_CreateAndReleaseOutputSurface |
107 #else | 325 #else |
108 #define MAYBE_CreateAndReleaseOutputSurface CreateAndReleaseOutputSurface | 326 #define MAYBE_CreateAndReleaseOutputSurface CreateAndReleaseOutputSurface |
109 #endif | 327 #endif |
110 TEST_F(CompositorTest, MAYBE_CreateAndReleaseOutputSurface) { | 328 TEST_F(CompositorTestWithMessageLoop, MAYBE_CreateAndReleaseOutputSurface) { |
111 std::unique_ptr<Layer> root_layer(new Layer(ui::LAYER_SOLID_COLOR)); | 329 std::unique_ptr<Layer> root_layer(new Layer(ui::LAYER_SOLID_COLOR)); |
112 root_layer->SetBounds(gfx::Rect(10, 10)); | 330 root_layer->SetBounds(gfx::Rect(10, 10)); |
113 compositor()->SetRootLayer(root_layer.get()); | 331 compositor()->SetRootLayer(root_layer.get()); |
114 compositor()->SetScaleAndSize(1.0f, gfx::Size(10, 10)); | 332 compositor()->SetScaleAndSize(1.0f, gfx::Size(10, 10)); |
115 DCHECK(compositor()->IsVisible()); | 333 DCHECK(compositor()->IsVisible()); |
116 compositor()->ScheduleDraw(); | 334 compositor()->ScheduleDraw(); |
117 DrawWaiterForTest::WaitForCompositingStarted(compositor()); | 335 DrawWaiterForTest::WaitForCompositingStarted(compositor()); |
118 compositor()->SetVisible(false); | 336 compositor()->SetVisible(false); |
119 EXPECT_EQ(gfx::kNullAcceleratedWidget, | 337 EXPECT_EQ(gfx::kNullAcceleratedWidget, |
120 compositor()->ReleaseAcceleratedWidget()); | 338 compositor()->ReleaseAcceleratedWidget()); |
121 compositor()->SetAcceleratedWidget(gfx::kNullAcceleratedWidget); | 339 compositor()->SetAcceleratedWidget(gfx::kNullAcceleratedWidget); |
122 compositor()->SetVisible(true); | 340 compositor()->SetVisible(true); |
123 compositor()->ScheduleDraw(); | 341 compositor()->ScheduleDraw(); |
124 DrawWaiterForTest::WaitForCompositingStarted(compositor()); | 342 DrawWaiterForTest::WaitForCompositingStarted(compositor()); |
125 compositor()->SetRootLayer(nullptr); | 343 compositor()->SetRootLayer(nullptr); |
126 } | 344 } |
127 | 345 |
128 } // namespace ui | 346 } // namespace ui |
OLD | NEW |