OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
rjkroege
2017/06/02 22:45:45
removed the commented out code?
gklassen
2017/06/05 21:32:14
Done.
| |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 /* | |
6 #include "base/containers/flat_set.h" | |
7 #include "cc/surfaces/compositor_frame_sink_support.h" | |
8 #include "cc/surfaces/surface_manager.h" | |
9 #include "cc/test/begin_frame_args_test.h" | |
10 #include "cc/test/compositor_frame_helpers.h" | |
11 #include "cc/test/fake_external_begin_frame_source.h" | |
12 #include "cc/test/fake_surface_observer.h" | |
13 #include "cc/test/mock_compositor_frame_sink_support_client.h" | |
14 #include "testing/gmock/include/gmock/gmock.h" | |
15 */ | |
16 | |
17 #include "cc/surfaces/frame_sink_id.h" | |
18 #include "cc/surfaces/local_surface_id.h" | |
19 #include "cc/surfaces/surface_id.h" | |
20 #include "hittest_aggregator.h" | |
21 #include "testing/gtest/include/gtest/gtest.h" | |
22 | |
23 namespace viz { | |
24 namespace test { | |
25 | |
26 namespace { | |
27 | |
28 /* | |
29 constexpr bool kIsRoot = true; | |
30 constexpr bool kIsChildRoot = false; | |
31 constexpr bool kHandlesFrameSinkIdInvalidation = true; | |
32 constexpr bool kNeedsSyncPoints = true; | |
33 constexpr FrameSinkId kDisplayFrameSink(2, 0); | |
34 constexpr FrameSinkId kParentFrameSink(3, 0); | |
35 constexpr FrameSinkId kChildFrameSink1(65563, 0); | |
36 constexpr FrameSinkId kChildFrameSink2(65564, 0); | |
37 constexpr FrameSinkId kArbitraryFrameSink(1337, 7331); | |
38 | |
39 std::vector<SurfaceId> empty_surface_ids() { | |
40 return std::vector<SurfaceId>(); | |
41 } | |
42 */ | |
43 constexpr cc::FrameSinkId kDisplayFrameSink(2, 0); | |
44 // constexpr gfx::Transform identityTransform(); | |
45 | |
46 cc::SurfaceId MakeSurfaceId(const cc::FrameSinkId& frame_sink_id, | |
47 uint32_t local_id) { | |
48 return cc::SurfaceId( | |
49 frame_sink_id, | |
50 cc::LocalSurfaceId(local_id, base::UnguessableToken::Deserialize(0, 1u))); | |
51 } | |
52 | |
53 } // namespace | |
54 | |
55 using namespace hittest::mojom; | |
56 | |
57 class HittestAggregatorTest : public testing::Test { | |
58 public: | |
59 HittestAggregatorTest() {} | |
60 ~HittestAggregatorTest() override {} | |
61 | |
62 void SetUp() override {} | |
63 | |
64 void TearDown() override {} | |
65 | |
66 HittestAggregator aggregator_; | |
67 | |
68 int count() { | |
69 HittestAggregator::Element* end = aggregator_.current_regions_; | |
70 while (end->child_count_ != LAST_REGION) { | |
71 end++; | |
72 } | |
73 return end - aggregator_.current_regions_; | |
74 } | |
75 | |
76 HittestRegion RegionAtIndex(int i) { | |
77 return aggregator_.current_regions_[i].region_; | |
78 } | |
79 }; | |
80 | |
81 TEST_F(HittestAggregatorTest, HittestAggregation) { | |
82 EXPECT_TRUE(true); | |
83 } | |
84 | |
85 TEST(HittestAggregatorTestNoFixture, HittestDataValidation) { | |
86 EXPECT_TRUE(false); | |
87 } | |
88 | |
89 // tests brainstorm | |
90 // A. Validation | |
91 // - SurfaceId is valid and exists | |
rjkroege
2017/06/02 22:45:45
let cc worry about it. You can assume in your obse
gklassen
2017/06/05 21:32:14
Acknowledged.
| |
92 // - Rect is within the display | |
93 // - flags is one of available values? | |
94 // B. Aggregation | |
95 // - happy paths: | |
96 // - missing surface parent | |
97 // - cyclic surfaces ( possible? ) | |
rjkroege
2017/06/02 22:45:46
probably can't/won't happen
gklassen
2017/06/05 21:32:14
Acknowledged.
| |
98 // C. SurfaceFinding | |
99 // - | |
100 | |
101 TEST_F(HittestAggregatorTest, SimplestHappyPath) { | |
rjkroege
2017/06/02 22:45:46
A happy path is like a happy meal for the input ta
| |
102 // one hittest_data with no sub-regions gets all events | |
rjkroege
2017/06/02 22:45:45
Ascii art would be simply spiffy here.
gklassen
2017/06/05 21:32:14
Acknowledged.
| |
103 | |
104 EXPECT_TRUE(count() == 0); | |
105 | |
106 cc::SurfaceId display_surface_id = MakeSurfaceId(kDisplayFrameSink, 1); | |
107 | |
108 auto hittest_data = HittestData::New(); | |
rjkroege
2017/06/02 22:45:46
New is an unfortunate choice of method name. Given
gklassen
2017/06/05 21:32:14
perhaps, but it's the name given by the auto-gen c
| |
109 hittest_data->surface_id_ = display_surface_id; | |
110 hittest_data->flags_ = hittest::mojom::HittestRegionFlags::HITTEST_NONE; | |
111 hittest_data->rect_.SetRect(0, 0, 1024, 768); | |
112 | |
113 aggregator_.SubmitHittestData(std::move(hittest_data)); | |
114 | |
115 EXPECT_TRUE(count() == 0); | |
116 | |
117 aggregator_.Aggregate(display_surface_id); | |
118 | |
119 // there should now be only one region | |
120 EXPECT_TRUE(count() == 1); | |
121 | |
122 HittestRegion region = RegionAtIndex(0); | |
123 EXPECT_TRUE(region.rect_ == gfx::Rect(0, 0, 1027, 768)); | |
124 EXPECT_TRUE(region.flags_ == HittestRegionFlags::HITTEST_NONE); | |
125 } | |
126 | |
127 TEST_F(HittestAggregatorTest, HittestDataValidation) { | |
128 auto hittest_data = hittest::mojom::HittestData::New(); | |
129 hittest_data->surface_id_ = MakeSurfaceId(kDisplayFrameSink, 1); | |
130 hittest_data->flags_ = hittest::mojom::HittestRegionFlags::HITTEST_NONE; | |
131 hittest_data->rect_.SetRect(0, 0, 10, 10); | |
132 | |
133 auto hittest_region = hittest::mojom::HittestRegion::New(); | |
134 hittest_region->surface_id_ = MakeSurfaceId(kDisplayFrameSink, 2); | |
135 hittest_region->flags_ = hittest::mojom::HittestRegionFlags::HITTEST_ASK; | |
136 hittest_region->rect_.SetRect(0, 0, 10, 10); | |
137 | |
138 // todo: confirm that transform inits to Identity | |
139 // DCHECK( hittest_region.transform_ ) | |
140 | |
141 hittest_data->regions_.push_back(std::move(hittest_region)); | |
142 | |
143 aggregator_.SubmitHittestData(std::move(hittest_data)); | |
144 } | |
145 | |
146 /* | |
rjkroege
2017/06/02 22:45:46
this looks copied from elsewhere. not reviewing ye
gklassen
2017/06/05 21:32:14
Acknowledged.
| |
147 | |
148 class SurfaceSynchronizationTest : public testing::Test { | |
149 public: | |
150 SurfaceSynchronizationTest() | |
151 : surface_manager_(SurfaceManager::LifetimeType::REFERENCES), | |
152 surface_observer_(false) {} | |
153 ~SurfaceSynchronizationTest() override {} | |
154 | |
155 CompositorFrameSinkSupport& display_support() { return *supports_[0]; } | |
156 Surface* display_surface() { | |
157 return display_support().current_surface_for_testing(); | |
158 } | |
159 | |
160 CompositorFrameSinkSupport& parent_support() { return *supports_[1]; } | |
161 Surface* parent_surface() { | |
162 return parent_support().current_surface_for_testing(); | |
163 } | |
164 const ReferencedSurfaceTracker& parent_reference_tracker() { | |
165 return parent_support().ReferenceTrackerForTesting(); | |
166 } | |
167 | |
168 CompositorFrameSinkSupport& child_support1() { return *supports_[2]; } | |
169 Surface* child_surface1() { | |
170 return child_support1().current_surface_for_testing(); | |
171 } | |
172 | |
173 CompositorFrameSinkSupport& child_support2() { return *supports_[3]; } | |
174 Surface* child_surface2() { | |
175 return child_support2().current_surface_for_testing(); | |
176 } | |
177 | |
178 CompositorFrameSinkSupport& support(int index) { return *supports_[index]; } | |
179 Surface* surface(int index) { | |
180 return support(index).current_surface_for_testing(); | |
181 } | |
182 | |
183 SurfaceManager& surface_manager() { return surface_manager_; } | |
184 | |
185 // Returns all the references where |surface_id| is the parent. | |
186 const base::flat_set<SurfaceId>& GetChildReferences( | |
187 const SurfaceId& surface_id) { | |
188 return surface_manager().parent_to_child_refs_[surface_id]; | |
189 } | |
190 | |
191 // Returns true if there is a temporary reference for |surface_id|. | |
192 bool HasTemporaryReference(const SurfaceId& surface_id) { | |
193 return surface_manager().HasTemporaryReference(surface_id); | |
194 } | |
195 | |
196 SurfaceDependencyTracker& dependency_tracker() { | |
197 return *surface_manager_.dependency_tracker(); | |
198 } | |
199 | |
200 FakeExternalBeginFrameSource* begin_frame_source() { | |
201 return begin_frame_source_.get(); | |
202 } | |
203 | |
204 FakeSurfaceObserver& surface_observer() { return surface_observer_; } | |
205 | |
206 // testing::Test: | |
207 void SetUp() override { | |
208 testing::Test::SetUp(); | |
209 | |
210 begin_frame_source_ = | |
211 base::MakeUnique<FakeExternalBeginFrameSource>(0.f, false); | |
212 dependency_tracker_ = base::MakeUnique<SurfaceDependencyTracker>( | |
213 &surface_manager_, begin_frame_source_.get()); | |
214 surface_manager_.SetDependencyTracker(dependency_tracker_.get()); | |
215 surface_manager_.AddObserver(&surface_observer_); | |
216 supports_.push_back(CompositorFrameSinkSupport::Create( | |
217 &support_client_, &surface_manager_, kDisplayFrameSink, kIsRoot, | |
218 kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints)); | |
219 supports_.push_back(CompositorFrameSinkSupport::Create( | |
220 &support_client_, &surface_manager_, kParentFrameSink, kIsChildRoot, | |
221 kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints)); | |
222 supports_.push_back(CompositorFrameSinkSupport::Create( | |
223 &support_client_, &surface_manager_, kChildFrameSink1, kIsChildRoot, | |
224 kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints)); | |
225 supports_.push_back(CompositorFrameSinkSupport::Create( | |
226 &support_client_, &surface_manager_, kChildFrameSink2, kIsChildRoot, | |
227 kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints)); | |
228 | |
229 // Normally, the BeginFrameSource would be registered by the Display. We | |
230 // register it here so that BeginFrames are received by the display support, | |
231 // for use in the PassesOnBeginFrameAcks test. Other supports do not receive | |
232 // BeginFrames, since the frame sink hierarchy is not set up in this test. | |
233 surface_manager_.RegisterBeginFrameSource(begin_frame_source_.get(), | |
234 kDisplayFrameSink); | |
235 } | |
236 | |
237 void TearDown() override { | |
238 surface_manager_.RemoveObserver(&surface_observer_); | |
239 surface_manager_.SetDependencyTracker(nullptr); | |
240 surface_manager_.UnregisterBeginFrameSource(begin_frame_source_.get()); | |
241 | |
242 dependency_tracker_.reset(); | |
243 | |
244 // SurfaceDependencyTracker depends on this BeginFrameSource and so it must | |
245 // be destroyed AFTER the dependency tracker is destroyed. | |
246 begin_frame_source_.reset(); | |
247 | |
248 supports_.clear(); | |
249 | |
250 surface_observer_.Reset(); | |
251 } | |
252 | |
253 protected: | |
254 testing::NiceMock<MockCompositorFrameSinkSupportClient> support_client_; | |
255 | |
256 private: | |
257 SurfaceManager surface_manager_; | |
258 FakeSurfaceObserver surface_observer_; | |
259 std::unique_ptr<FakeExternalBeginFrameSource> begin_frame_source_; | |
260 std::unique_ptr<SurfaceDependencyTracker> dependency_tracker_; | |
261 std::vector<std::unique_ptr<CompositorFrameSinkSupport>> supports_; | |
262 | |
263 DISALLOW_COPY_AND_ASSIGN(SurfaceSynchronizationTest); | |
264 }; | |
265 | |
266 // The display root surface should have a surface reference from the top-level | |
267 // root added/removed when a CompositorFrame is submitted with a new SurfaceId. | |
268 TEST_F(SurfaceSynchronizationTest, RootSurfaceReceivesReferences) { | |
269 const SurfaceId display_id_first = MakeSurfaceId(kDisplayFrameSink, 1); | |
270 const SurfaceId display_id_second = MakeSurfaceId(kDisplayFrameSink, 2); | |
271 | |
272 // Submit a CompositorFrame for the first display root surface. | |
273 display_support().SubmitCompositorFrame(display_id_first.local_surface_id(), | |
274 MakeCompositorFrame()); | |
275 | |
276 // A surface reference from the top-level root is added and there shouldn't be | |
277 // a temporary reference. | |
278 EXPECT_FALSE(HasTemporaryReference(display_id_first)); | |
279 EXPECT_THAT(GetChildReferences(surface_manager().GetRootSurfaceId()), | |
280 UnorderedElementsAre(display_id_first)); | |
281 | |
282 // Submit a CompositorFrame for the second display root surface. | |
283 display_support().SubmitCompositorFrame(display_id_second.local_surface_id(), | |
284 MakeCompositorFrame()); | |
285 | |
286 // A surface reference from the top-level root to |display_id_second| should | |
287 // be added and the reference to |display_root_first| removed. | |
288 EXPECT_FALSE(HasTemporaryReference(display_id_second)); | |
289 EXPECT_THAT(GetChildReferences(surface_manager().GetRootSurfaceId()), | |
290 UnorderedElementsAre(display_id_second)); | |
291 | |
292 // Surface |display_id_first| is unreachable and should get deleted. | |
293 EXPECT_EQ(nullptr, surface_manager().GetSurfaceForId(display_id_first)); | |
294 } | |
295 | |
296 // The parent Surface is blocked on |child_id1| and |child_id2|. | |
297 TEST_F(SurfaceSynchronizationTest, BlockedOnTwo) { | |
298 const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); | |
299 const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); | |
300 const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1); | |
301 | |
302 parent_support().SubmitCompositorFrame( | |
303 parent_id.local_surface_id(), | |
304 MakeCompositorFrame({child_id1, child_id2}, empty_surface_ids(), | |
305 TransferableResourceArray())); | |
306 | |
307 // parent_support is blocked on |child_id1| and |child_id2|. | |
308 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
309 EXPECT_FALSE(parent_surface()->HasActiveFrame()); | |
310 EXPECT_TRUE(parent_surface()->HasPendingFrame()); | |
311 EXPECT_THAT(parent_surface()->blocking_surfaces(), | |
312 UnorderedElementsAre(child_id1, child_id2)); | |
313 | |
314 // Submit a CompositorFrame without any dependencies to |child_id1|. | |
315 // parent_support should now only be blocked on |child_id2|. | |
316 child_support1().SubmitCompositorFrame(child_id1.local_surface_id(), | |
317 MakeCompositorFrame()); | |
318 | |
319 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
320 EXPECT_FALSE(parent_surface()->HasActiveFrame()); | |
321 EXPECT_TRUE(parent_surface()->HasPendingFrame()); | |
322 EXPECT_THAT(parent_surface()->blocking_surfaces(), | |
323 UnorderedElementsAre(child_id2)); | |
324 | |
325 // Submit a CompositorFrame without any dependencies to |child_id2|. | |
326 // parent_support should be activated. | |
327 child_support2().SubmitCompositorFrame(child_id2.local_surface_id(), | |
328 MakeCompositorFrame()); | |
329 | |
330 EXPECT_FALSE(dependency_tracker().has_deadline()); | |
331 EXPECT_TRUE(parent_surface()->HasActiveFrame()); | |
332 EXPECT_FALSE(parent_surface()->HasPendingFrame()); | |
333 EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); | |
334 } | |
335 | |
336 // The parent Surface is blocked on |child_id2| which is blocked on |child_id3|. | |
337 TEST_F(SurfaceSynchronizationTest, BlockedChain) { | |
338 const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); | |
339 const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); | |
340 const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1); | |
341 | |
342 parent_support().SubmitCompositorFrame( | |
343 parent_id.local_surface_id(), | |
344 MakeCompositorFrame({child_id1}, empty_surface_ids(), | |
345 TransferableResourceArray())); | |
346 | |
347 // parent_support is blocked on |child_id1|. | |
348 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
349 EXPECT_FALSE(parent_surface()->HasActiveFrame()); | |
350 EXPECT_TRUE(parent_surface()->HasPendingFrame()); | |
351 EXPECT_THAT(parent_surface()->blocking_surfaces(), | |
352 UnorderedElementsAre(child_id1)); | |
353 // The parent should not report damage until it activates. | |
354 EXPECT_FALSE(surface_observer().IsSurfaceDamaged(parent_id)); | |
355 | |
356 child_support1().SubmitCompositorFrame( | |
357 child_id1.local_surface_id(), | |
358 MakeCompositorFrame({child_id2}, empty_surface_ids(), | |
359 TransferableResourceArray())); | |
360 | |
361 // child_support1 should now be blocked on |child_id2|. | |
362 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
363 EXPECT_FALSE(child_surface1()->HasActiveFrame()); | |
364 EXPECT_TRUE(child_surface1()->HasPendingFrame()); | |
365 EXPECT_THAT(child_surface1()->blocking_surfaces(), | |
366 UnorderedElementsAre(child_id2)); | |
367 // The parent and child should not report damage until they activate. | |
368 EXPECT_FALSE(surface_observer().IsSurfaceDamaged(parent_id)); | |
369 EXPECT_FALSE(surface_observer().IsSurfaceDamaged(child_id1)); | |
370 | |
371 // The parent should still be blocked on |child_id1| because it's pending. | |
372 EXPECT_THAT(parent_surface()->blocking_surfaces(), | |
373 UnorderedElementsAre(child_id1)); | |
374 | |
375 // Submit a CompositorFrame without any dependencies to |child_id2|. | |
376 // parent_support should be activated. | |
377 child_support2().SubmitCompositorFrame( | |
378 child_id2.local_surface_id(), | |
379 MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(), | |
380 TransferableResourceArray())); | |
381 | |
382 EXPECT_FALSE(dependency_tracker().has_deadline()); | |
383 | |
384 // child_surface1 should now be active. | |
385 EXPECT_TRUE(child_surface1()->HasActiveFrame()); | |
386 EXPECT_FALSE(child_surface1()->HasPendingFrame()); | |
387 EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty()); | |
388 | |
389 // parent_surface should now be active. | |
390 EXPECT_TRUE(parent_surface()->HasActiveFrame()); | |
391 EXPECT_FALSE(parent_surface()->HasPendingFrame()); | |
392 EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); | |
393 | |
394 // All three surfaces |parent_id|, |child_id1|, and |child_id2| should | |
395 // now report damage. This would trigger a new display frame. | |
396 EXPECT_TRUE(surface_observer().IsSurfaceDamaged(parent_id)); | |
397 EXPECT_TRUE(surface_observer().IsSurfaceDamaged(child_id1)); | |
398 EXPECT_TRUE(surface_observer().IsSurfaceDamaged(child_id2)); | |
399 } | |
400 | |
401 // parent_surface and child_surface1 are blocked on |child_id2|. | |
402 TEST_F(SurfaceSynchronizationTest, TwoBlockedOnOne) { | |
403 const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); | |
404 const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); | |
405 const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1); | |
406 | |
407 parent_support().SubmitCompositorFrame( | |
408 parent_id.local_surface_id(), | |
409 MakeCompositorFrame({child_id2}, empty_surface_ids(), | |
410 TransferableResourceArray())); | |
411 | |
412 // parent_support is blocked on |child_id2|. | |
413 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
414 EXPECT_FALSE(parent_surface()->HasActiveFrame()); | |
415 EXPECT_TRUE(parent_surface()->HasPendingFrame()); | |
416 EXPECT_THAT(parent_surface()->blocking_surfaces(), | |
417 UnorderedElementsAre(child_id2)); | |
418 | |
419 // child_support1 should now be blocked on |child_id2|. | |
420 child_support1().SubmitCompositorFrame( | |
421 child_id1.local_surface_id(), | |
422 MakeCompositorFrame({child_id2}, empty_surface_ids(), | |
423 TransferableResourceArray())); | |
424 | |
425 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
426 EXPECT_FALSE(child_surface1()->HasActiveFrame()); | |
427 EXPECT_TRUE(child_surface1()->HasPendingFrame()); | |
428 EXPECT_THAT(child_surface1()->blocking_surfaces(), | |
429 UnorderedElementsAre(child_id2)); | |
430 | |
431 // The parent should still be blocked on |child_id2|. | |
432 EXPECT_THAT(parent_surface()->blocking_surfaces(), | |
433 UnorderedElementsAre(child_id2)); | |
434 | |
435 // Submit a CompositorFrame without any dependencies to |child_id2|. | |
436 // parent_support should be activated. | |
437 child_support2().SubmitCompositorFrame(child_id2.local_surface_id(), | |
438 MakeCompositorFrame()); | |
439 | |
440 EXPECT_FALSE(dependency_tracker().has_deadline()); | |
441 | |
442 // child_surface1 should now be active. | |
443 EXPECT_TRUE(child_surface1()->HasActiveFrame()); | |
444 EXPECT_FALSE(child_surface1()->HasPendingFrame()); | |
445 EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty()); | |
446 | |
447 // parent_surface should now be active. | |
448 EXPECT_TRUE(parent_surface()->HasActiveFrame()); | |
449 EXPECT_FALSE(parent_surface()->HasPendingFrame()); | |
450 EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); | |
451 } | |
452 | |
453 // parent_surface is blocked on |child_id1|, and child_surface2 is blocked on | |
454 // |child_id2| until the deadline hits. | |
455 TEST_F(SurfaceSynchronizationTest, DeadlineHits) { | |
456 const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); | |
457 const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); | |
458 const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1); | |
459 | |
460 parent_support().SubmitCompositorFrame( | |
461 parent_id.local_surface_id(), | |
462 MakeCompositorFrame({child_id1}, empty_surface_ids(), | |
463 TransferableResourceArray())); | |
464 | |
465 // parent_support is blocked on |child_id1|. | |
466 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
467 EXPECT_FALSE(parent_surface()->HasActiveFrame()); | |
468 EXPECT_TRUE(parent_surface()->HasPendingFrame()); | |
469 EXPECT_THAT(parent_surface()->blocking_surfaces(), | |
470 UnorderedElementsAre(child_id1)); | |
471 | |
472 child_support1().SubmitCompositorFrame( | |
473 child_id1.local_surface_id(), | |
474 MakeCompositorFrame({child_id2}, empty_surface_ids(), | |
475 TransferableResourceArray())); | |
476 | |
477 // child_support1 should now be blocked on |child_id2|. | |
478 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
479 EXPECT_FALSE(child_surface1()->HasActiveFrame()); | |
480 EXPECT_TRUE(child_surface1()->HasPendingFrame()); | |
481 EXPECT_THAT(child_surface1()->blocking_surfaces(), | |
482 UnorderedElementsAre(child_id2)); | |
483 | |
484 // The parent should still be blocked on |child_id1| because it's pending. | |
485 EXPECT_THAT(parent_surface()->blocking_surfaces(), | |
486 UnorderedElementsAre(child_id1)); | |
487 | |
488 BeginFrameArgs args = | |
489 CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); | |
490 | |
491 for (int i = 0; i < 3; ++i) { | |
492 begin_frame_source()->TestOnBeginFrame(args); | |
493 // There is still a looming deadline! Eeek! | |
494 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
495 | |
496 // parent_support is still blocked on |child_id1|. | |
497 EXPECT_FALSE(parent_surface()->HasActiveFrame()); | |
498 EXPECT_TRUE(parent_surface()->HasPendingFrame()); | |
499 EXPECT_THAT(parent_surface()->blocking_surfaces(), | |
500 UnorderedElementsAre(child_id1)); | |
501 | |
502 // child_support1 is still blocked on |child_id2|. | |
503 EXPECT_FALSE(child_surface1()->HasActiveFrame()); | |
504 EXPECT_TRUE(child_surface1()->HasPendingFrame()); | |
505 EXPECT_THAT(child_surface1()->blocking_surfaces(), | |
506 UnorderedElementsAre(child_id2)); | |
507 } | |
508 | |
509 begin_frame_source()->TestOnBeginFrame(args); | |
510 | |
511 // The deadline has passed. | |
512 EXPECT_FALSE(dependency_tracker().has_deadline()); | |
513 | |
514 // parent_surface has been activated. | |
515 EXPECT_TRUE(parent_surface()->HasActiveFrame()); | |
516 EXPECT_FALSE(parent_surface()->HasPendingFrame()); | |
517 EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); | |
518 | |
519 // child_surface1 has been activated. | |
520 EXPECT_TRUE(child_surface1()->HasActiveFrame()); | |
521 EXPECT_FALSE(child_surface1()->HasPendingFrame()); | |
522 EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty()); | |
523 } | |
524 | |
525 // Verifies that the deadline does not reset if we submit CompositorFrames | |
526 // to new Surfaces with unresolved dependencies. | |
527 TEST_F(SurfaceSynchronizationTest, FramesSubmittedAfterDeadlineSet) { | |
528 const SurfaceId arbitrary_id = MakeSurfaceId(kArbitraryFrameSink, 1); | |
529 BeginFrameArgs args = | |
530 CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); | |
531 for (int i = 0; i < 3; ++i) { | |
532 LocalSurfaceId local_surface_id(1, base::UnguessableToken::Create()); | |
533 support(i).SubmitCompositorFrame( | |
534 local_surface_id, | |
535 MakeCompositorFrame({arbitrary_id}, empty_surface_ids(), | |
536 TransferableResourceArray())); | |
537 // The deadline has been set. | |
538 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
539 | |
540 // support(i) should be blocked on arbitrary_id. | |
541 EXPECT_FALSE(surface(i)->HasActiveFrame()); | |
542 EXPECT_TRUE(surface(i)->HasPendingFrame()); | |
543 EXPECT_THAT(surface(i)->blocking_surfaces(), | |
544 UnorderedElementsAre(arbitrary_id)); | |
545 | |
546 // Issue a BeginFrame to get closer to the deadline. | |
547 begin_frame_source()->TestOnBeginFrame(args); | |
548 } | |
549 | |
550 // The deadline hits and all the Surfaces should activate. | |
551 begin_frame_source()->TestOnBeginFrame(args); | |
552 for (int i = 0; i < 3; ++i) { | |
553 EXPECT_TRUE(surface(i)->HasActiveFrame()); | |
554 EXPECT_FALSE(surface(i)->HasPendingFrame()); | |
555 EXPECT_THAT(surface(i)->blocking_surfaces(), IsEmpty()); | |
556 } | |
557 } | |
558 | |
559 // This test verifies at the Surface activates once a CompositorFrame is | |
560 // submitted that has no unresolved dependencies. | |
561 TEST_F(SurfaceSynchronizationTest, NewFrameOverridesOldDependencies) { | |
562 const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); | |
563 const SurfaceId arbitrary_id = MakeSurfaceId(kArbitraryFrameSink, 1); | |
564 | |
565 // Submit a CompositorFrame that depends on |arbitrary_id|. | |
566 parent_support().SubmitCompositorFrame( | |
567 parent_id.local_surface_id(), | |
568 MakeCompositorFrame({arbitrary_id}, empty_surface_ids(), | |
569 TransferableResourceArray())); | |
570 | |
571 // Verify that the CompositorFrame is blocked on |arbitrary_id|. | |
572 EXPECT_FALSE(parent_surface()->HasActiveFrame()); | |
573 EXPECT_TRUE(parent_surface()->HasPendingFrame()); | |
574 EXPECT_THAT(parent_surface()->blocking_surfaces(), | |
575 UnorderedElementsAre(arbitrary_id)); | |
576 | |
577 // Submit a CompositorFrame that has no dependencies. | |
578 parent_support().SubmitCompositorFrame(parent_id.local_surface_id(), | |
579 MakeCompositorFrame()); | |
580 | |
581 // Verify that the CompositorFrame has been activated. | |
582 EXPECT_TRUE(parent_surface()->HasActiveFrame()); | |
583 EXPECT_FALSE(parent_surface()->HasPendingFrame()); | |
584 EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); | |
585 } | |
586 | |
587 // This test verifies that a pending CompositorFrame does not affect surface | |
588 // references. A new surface from a child will continue to exist as a temporary | |
589 // reference until the parent's frame activates. | |
590 TEST_F(SurfaceSynchronizationTest, OnlyActiveFramesAffectSurfaceReferences) { | |
591 const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); | |
592 const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); | |
593 const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1); | |
594 | |
595 // child_support1 submits a CompositorFrame without any dependencies. | |
596 // DidReceiveCompositorFrameAck should call on immediate activation. | |
597 EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(1); | |
598 child_support1().SubmitCompositorFrame(child_id1.local_surface_id(), | |
599 MakeCompositorFrame()); | |
600 testing::Mock::VerifyAndClearExpectations(&support_client_); | |
601 | |
602 // Verify that the child surface is not blocked. | |
603 EXPECT_TRUE(child_surface1()->HasActiveFrame()); | |
604 EXPECT_FALSE(child_surface1()->HasPendingFrame()); | |
605 EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty()); | |
606 | |
607 // Verify that there's a temporary reference for |child_id1|. | |
608 EXPECT_TRUE(HasTemporaryReference(child_id1)); | |
609 | |
610 // parent_support submits a CompositorFrame that depends on |child_id1| | |
611 // (which is already active) and |child_id2|. Thus, the parent should not | |
612 // activate immediately. DidReceiveCompositorFrameAck should not be called | |
613 // immediately because the parent CompositorFrame is also blocked on | |
614 // |child_id2|. | |
615 EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(0); | |
616 parent_support().SubmitCompositorFrame( | |
617 parent_id.local_surface_id(), | |
618 MakeCompositorFrame({child_id2}, {child_id1}, | |
619 TransferableResourceArray())); | |
620 EXPECT_FALSE(parent_surface()->HasActiveFrame()); | |
621 EXPECT_TRUE(parent_surface()->HasPendingFrame()); | |
622 EXPECT_THAT(parent_surface()->blocking_surfaces(), | |
623 UnorderedElementsAre(child_id2)); | |
624 EXPECT_THAT(GetChildReferences(parent_id), IsEmpty()); | |
625 testing::Mock::VerifyAndClearExpectations(&support_client_); | |
626 | |
627 // Verify that there's a temporary reference for |child_id1| that still | |
628 // exists. | |
629 EXPECT_TRUE(HasTemporaryReference(child_id1)); | |
630 | |
631 // child_support2 submits a CompositorFrame without any dependencies. | |
632 // Both the child and the parent should immediately ACK CompositorFrames | |
633 // on activation. | |
634 EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(2); | |
635 child_support2().SubmitCompositorFrame(child_id2.local_surface_id(), | |
636 MakeCompositorFrame()); | |
637 testing::Mock::VerifyAndClearExpectations(&support_client_); | |
638 | |
639 // Verify that the child surface is not blocked. | |
640 EXPECT_TRUE(child_surface1()->HasActiveFrame()); | |
641 EXPECT_FALSE(child_surface1()->HasPendingFrame()); | |
642 EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty()); | |
643 | |
644 // Verify that the parent surface's CompositorFrame has activated and that the | |
645 // temporary reference has been replaced by a permanent one. | |
646 EXPECT_TRUE(parent_surface()->HasActiveFrame()); | |
647 EXPECT_FALSE(parent_surface()->HasPendingFrame()); | |
648 EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); | |
649 EXPECT_FALSE(HasTemporaryReference(child_id1)); | |
650 EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1)); | |
651 } | |
652 | |
653 // This test verifies that we do not double count returned resources when a | |
654 // CompositorFrame starts out as pending, then becomes active, and then is | |
655 // replaced with another active CompositorFrame. | |
656 TEST_F(SurfaceSynchronizationTest, ResourcesOnlyReturnedOnce) { | |
657 const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); | |
658 const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1); | |
659 | |
660 // The parent submits a CompositorFrame that depends on |child_id| before the | |
661 // child submits a CompositorFrame. The CompositorFrame also has resources in | |
662 // its resource list. | |
663 TransferableResource resource; | |
664 resource.id = 1337; | |
665 resource.format = ALPHA_8; | |
666 resource.filter = 1234; | |
667 resource.size = gfx::Size(1234, 5678); | |
668 TransferableResourceArray resource_list = {resource}; | |
669 parent_support().SubmitCompositorFrame( | |
670 parent_id.local_surface_id(), | |
671 MakeCompositorFrame({child_id}, empty_surface_ids(), resource_list)); | |
672 | |
673 // Verify that the CompositorFrame is blocked on |child_id|. | |
674 EXPECT_FALSE(parent_surface()->HasActiveFrame()); | |
675 EXPECT_TRUE(parent_surface()->HasPendingFrame()); | |
676 EXPECT_THAT(parent_surface()->blocking_surfaces(), | |
677 UnorderedElementsAre(child_id)); | |
678 | |
679 child_support1().SubmitCompositorFrame( | |
680 child_id.local_surface_id(), | |
681 MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(), | |
682 TransferableResourceArray())); | |
683 | |
684 // Verify that the child CompositorFrame activates immediately. | |
685 EXPECT_TRUE(child_surface1()->HasActiveFrame()); | |
686 EXPECT_FALSE(child_surface1()->HasPendingFrame()); | |
687 EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty()); | |
688 | |
689 // Verify that the parent has activated. | |
690 EXPECT_TRUE(parent_surface()->HasActiveFrame()); | |
691 EXPECT_FALSE(parent_surface()->HasPendingFrame()); | |
692 EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); | |
693 | |
694 ReturnedResourceArray returned_resources = {resource.ToReturnedResource()}; | |
695 EXPECT_CALL(support_client_, | |
696 DidReceiveCompositorFrameAck(returned_resources)); | |
697 | |
698 // The parent submits a CompositorFrame without any dependencies. That frame | |
699 // should activate immediately, replacing the earlier frame. The resource from | |
700 // the earlier frame should be returned to the client. | |
701 parent_support().SubmitCompositorFrame( | |
702 parent_id.local_surface_id(), | |
703 MakeCompositorFrame({empty_surface_ids()}, {empty_surface_ids()}, | |
704 TransferableResourceArray())); | |
705 EXPECT_TRUE(parent_surface()->HasActiveFrame()); | |
706 EXPECT_FALSE(parent_surface()->HasPendingFrame()); | |
707 EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); | |
708 } | |
709 | |
710 // The parent Surface is blocked on |child_id2| which is blocked on |child_id3|. | |
711 // child_support1 evicts its blocked Surface. The parent surface should | |
712 // activate. | |
713 TEST_F(SurfaceSynchronizationTest, EvictSurfaceWithPendingFrame) { | |
714 const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); | |
715 const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); | |
716 const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1); | |
717 | |
718 // Submit a CompositorFrame that depends on |child_id1|. | |
719 parent_support().SubmitCompositorFrame( | |
720 parent_id1.local_surface_id(), | |
721 MakeCompositorFrame({child_id1}, empty_surface_ids(), | |
722 TransferableResourceArray())); | |
723 | |
724 // Verify that the CompositorFrame is blocked on |child_id1|. | |
725 EXPECT_FALSE(parent_surface()->HasActiveFrame()); | |
726 EXPECT_TRUE(parent_surface()->HasPendingFrame()); | |
727 EXPECT_THAT(parent_surface()->blocking_surfaces(), | |
728 UnorderedElementsAre(child_id1)); | |
729 | |
730 // Submit a CompositorFrame that depends on |child_id2|. | |
731 child_support1().SubmitCompositorFrame( | |
732 child_id1.local_surface_id(), | |
733 MakeCompositorFrame({child_id2}, empty_surface_ids(), | |
734 TransferableResourceArray())); | |
735 | |
736 // Verify that the CompositorFrame is blocked on |child_id2|. | |
737 EXPECT_FALSE(child_surface1()->HasActiveFrame()); | |
738 EXPECT_TRUE(child_surface1()->HasPendingFrame()); | |
739 EXPECT_THAT(child_surface1()->blocking_surfaces(), | |
740 UnorderedElementsAre(child_id2)); | |
741 | |
742 // Evict child_support1's current Surface. | |
743 // TODO(fsamuel): EvictCurrentSurface => EvictCurrentSurface. | |
744 child_support1().EvictCurrentSurface(); | |
745 | |
746 // The parent Surface should immediately activate. | |
747 EXPECT_TRUE(parent_surface()->HasActiveFrame()); | |
748 EXPECT_FALSE(parent_surface()->HasPendingFrame()); | |
749 EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); | |
750 EXPECT_FALSE(dependency_tracker().has_deadline()); | |
751 } | |
752 | |
753 // This test verifies that if a surface has both a pending and active | |
754 // CompositorFrame and the pending CompositorFrame activates, replacing the | |
755 // existing active CompositorFrame, then the surface reference hierarchy will be | |
756 // updated allowing garbage collection of surfaces that are no longer | |
757 // referenced. | |
758 TEST_F(SurfaceSynchronizationTest, DropStaleReferencesAfterActivation) { | |
759 const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); | |
760 const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); | |
761 const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1); | |
762 | |
763 // The parent submits a CompositorFrame that depends on |child_id1| before the | |
764 // child submits a CompositorFrame. | |
765 EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(0); | |
766 parent_support().SubmitCompositorFrame( | |
767 parent_id.local_surface_id(), | |
768 MakeCompositorFrame({child_id1}, empty_surface_ids(), | |
769 TransferableResourceArray())); | |
770 | |
771 // Verify that the CompositorFrame is blocked on |child_id|. | |
772 EXPECT_FALSE(parent_surface()->HasActiveFrame()); | |
773 EXPECT_TRUE(parent_surface()->HasPendingFrame()); | |
774 EXPECT_THAT(parent_surface()->blocking_surfaces(), | |
775 UnorderedElementsAre(child_id1)); | |
776 testing::Mock::VerifyAndClearExpectations(&support_client_); | |
777 | |
778 // Verify that no references are added while the CompositorFrame is pending. | |
779 EXPECT_THAT(GetChildReferences(parent_id), IsEmpty()); | |
780 | |
781 // DidReceiveCompositorFrameAck should get called twice: once for the child | |
782 // and once for the now active parent CompositorFrame. | |
783 EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(2); | |
784 child_support1().SubmitCompositorFrame(child_id1.local_surface_id(), | |
785 MakeCompositorFrame()); | |
786 testing::Mock::VerifyAndClearExpectations(&support_client_); | |
787 | |
788 // Verify that the child CompositorFrame activates immediately. | |
789 EXPECT_TRUE(child_surface1()->HasActiveFrame()); | |
790 EXPECT_FALSE(child_surface1()->HasPendingFrame()); | |
791 EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty()); | |
792 | |
793 // Verify that the parent Surface has activated. | |
794 EXPECT_TRUE(parent_surface()->HasActiveFrame()); | |
795 EXPECT_FALSE(parent_surface()->HasPendingFrame()); | |
796 EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); | |
797 | |
798 // Submit a new parent CompositorFrame to add a reference. | |
799 parent_support().SubmitCompositorFrame( | |
800 parent_id.local_surface_id(), | |
801 MakeCompositorFrame(empty_surface_ids(), {child_id1}, | |
802 TransferableResourceArray())); | |
803 | |
804 // Verify that the parent Surface has activated. | |
805 EXPECT_TRUE(parent_surface()->HasActiveFrame()); | |
806 EXPECT_FALSE(parent_surface()->HasPendingFrame()); | |
807 EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); | |
808 | |
809 // Verify that there is no temporary reference for the child and that | |
810 // the reference from the parent to the child still exists. | |
811 EXPECT_FALSE(HasTemporaryReference(child_id1)); | |
812 EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1)); | |
813 | |
814 // The parent submits another CompositorFrame that depends on |child_id2|. | |
815 // Submitting a pending CompositorFrame will not trigger a CompositorFrameAck. | |
816 EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(0); | |
817 parent_support().SubmitCompositorFrame( | |
818 parent_id.local_surface_id(), | |
819 MakeCompositorFrame({child_id2}, empty_surface_ids(), | |
820 TransferableResourceArray())); | |
821 testing::Mock::VerifyAndClearExpectations(&support_client_); | |
822 | |
823 // The parent surface should now have both a pending and activate | |
824 // CompositorFrame. Verify that the set of child references from | |
825 // |parent_id| are only from the active CompositorFrame. | |
826 EXPECT_TRUE(parent_surface()->HasActiveFrame()); | |
827 EXPECT_TRUE(parent_surface()->HasPendingFrame()); | |
828 EXPECT_THAT(parent_surface()->blocking_surfaces(), | |
829 UnorderedElementsAre(child_id2)); | |
830 EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1)); | |
831 | |
832 child_support2().SubmitCompositorFrame(child_id2.local_surface_id(), | |
833 MakeCompositorFrame()); | |
834 | |
835 // Verify that the parent Surface has activated and no longer has a pending | |
836 // CompositorFrame. Also verify that |child_id1| is no longer a child | |
837 // reference of |parent_id|. | |
838 EXPECT_TRUE(parent_surface()->HasActiveFrame()); | |
839 EXPECT_FALSE(parent_surface()->HasPendingFrame()); | |
840 EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); | |
841 // The parent will not immediately refer to the child until it submits a new | |
842 // CompositorFrame with the reference. | |
843 EXPECT_THAT(GetChildReferences(parent_id), IsEmpty()); | |
844 } | |
845 | |
846 // Checks whether the latency info are moved to the new surface from the old | |
847 // one when LocalSurfaceId changes. No frame has unresolved dependencies. | |
848 TEST_F(SurfaceSynchronizationTest, | |
849 LatencyInfoCarriedOverOnResize_NoUnresolvedDependencies) { | |
850 const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); | |
851 const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2); | |
852 const ui::LatencyComponentType latency_type1 = | |
853 ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT; | |
854 const int64_t latency_id1 = 234; | |
855 const int64_t latency_sequence_number1 = 5645432; | |
856 const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT; | |
857 const int64_t latency_id2 = 31434351; | |
858 const int64_t latency_sequence_number2 = 663788; | |
859 | |
860 // Submit a frame with latency info | |
861 ui::LatencyInfo info; | |
862 info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1); | |
863 | |
864 CompositorFrame frame = MakeCompositorFrame(); | |
865 frame.metadata.latency_info.push_back(info); | |
866 | |
867 parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(), | |
868 std::move(frame)); | |
869 | |
870 // Verify that the old surface has an active frame and no pending frame. | |
871 Surface* old_surface = surface_manager().GetSurfaceForId(parent_id1); | |
872 ASSERT_NE(nullptr, old_surface); | |
873 EXPECT_TRUE(old_surface->HasActiveFrame()); | |
874 EXPECT_FALSE(old_surface->HasPendingFrame()); | |
875 | |
876 // Submit another frame with some other latency info and a different | |
877 // LocalSurfaceId. | |
878 ui::LatencyInfo info2; | |
879 info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2); | |
880 | |
881 CompositorFrame frame2 = MakeCompositorFrame(); | |
882 frame2.metadata.latency_info.push_back(info2); | |
883 | |
884 parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(), | |
885 std::move(frame2)); | |
886 | |
887 // Verify that the new surface has an active frame and no pending frames. | |
888 Surface* surface = surface_manager().GetSurfaceForId(parent_id2); | |
889 ASSERT_NE(nullptr, surface); | |
890 EXPECT_TRUE(surface->HasActiveFrame()); | |
891 EXPECT_FALSE(surface->HasPendingFrame()); | |
892 | |
893 // Verify that the new surface has both latency info elements. | |
894 std::vector<ui::LatencyInfo> info_list; | |
895 surface->TakeLatencyInfo(&info_list); | |
896 EXPECT_EQ(2u, info_list.size()); | |
897 | |
898 ui::LatencyInfo aggregated_latency_info = info_list[0]; | |
899 aggregated_latency_info.AddNewLatencyFrom(info_list[1]); | |
900 | |
901 // Two components are the original ones, and the third one is | |
902 // DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, logged on compositor frame | |
903 // submit. | |
904 EXPECT_EQ(3u, aggregated_latency_info.latency_components().size()); | |
905 | |
906 ui::LatencyInfo::LatencyComponent comp1; | |
907 EXPECT_TRUE( | |
908 aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1)); | |
909 EXPECT_EQ(latency_sequence_number1, comp1.sequence_number); | |
910 EXPECT_TRUE( | |
911 aggregated_latency_info.FindLatency(latency_type2, latency_id2, nullptr)); | |
912 EXPECT_TRUE(aggregated_latency_info.FindLatency( | |
913 ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, nullptr)); | |
914 } | |
915 | |
916 // Checks whether the latency info are moved to the new surface from the old | |
917 // one when LocalSurfaceId changes. Old surface has unresolved dependencies. | |
918 TEST_F(SurfaceSynchronizationTest, | |
919 LatencyInfoCarriedOverOnResize_OldSurfaceHasPendingAndActiveFrame) { | |
920 const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); | |
921 const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2); | |
922 const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1); | |
923 | |
924 const ui::LatencyComponentType latency_type1 = | |
925 ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT; | |
926 const int64_t latency_id1 = 234; | |
927 const int64_t latency_sequence_number1 = 5645432; | |
928 const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT; | |
929 const int64_t latency_id2 = 31434351; | |
930 const int64_t latency_sequence_number2 = 663788; | |
931 | |
932 // Submit a frame with no unresolved dependecy. | |
933 ui::LatencyInfo info; | |
934 info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1); | |
935 | |
936 CompositorFrame frame = MakeCompositorFrame(); | |
937 frame.metadata.latency_info.push_back(info); | |
938 | |
939 parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(), | |
940 std::move(frame)); | |
941 | |
942 // Submit a frame with unresolved dependencies. | |
943 ui::LatencyInfo info2; | |
944 info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2); | |
945 | |
946 CompositorFrame frame2 = MakeCompositorFrame({child_id}, empty_surface_ids(), | |
947 TransferableResourceArray()); | |
948 frame2.metadata.latency_info.push_back(info2); | |
949 | |
950 parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(), | |
951 std::move(frame2)); | |
952 | |
953 // Verify that the old surface has both an active and a pending frame. | |
954 Surface* old_surface = surface_manager().GetSurfaceForId(parent_id1); | |
955 ASSERT_NE(nullptr, old_surface); | |
956 EXPECT_TRUE(old_surface->HasActiveFrame()); | |
957 EXPECT_TRUE(old_surface->HasPendingFrame()); | |
958 | |
959 // Submit a frame with a new local surface id. | |
960 parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(), | |
961 MakeCompositorFrame()); | |
962 | |
963 // Verify that the new surface has an active frame only. | |
964 Surface* surface = surface_manager().GetSurfaceForId(parent_id2); | |
965 ASSERT_NE(nullptr, surface); | |
966 EXPECT_TRUE(surface->HasActiveFrame()); | |
967 EXPECT_FALSE(surface->HasPendingFrame()); | |
968 | |
969 // Verify that the new surface has latency info from both active and pending | |
970 // frame of the old surface. | |
971 std::vector<ui::LatencyInfo> info_list; | |
972 surface->TakeLatencyInfo(&info_list); | |
973 EXPECT_EQ(2u, info_list.size()); | |
974 | |
975 ui::LatencyInfo aggregated_latency_info = info_list[0]; | |
976 aggregated_latency_info.AddNewLatencyFrom(info_list[1]); | |
977 | |
978 // Two components are the original ones, and the third one is | |
979 // DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, logged on compositor frame | |
980 // submit. | |
981 EXPECT_EQ(3u, aggregated_latency_info.latency_components().size()); | |
982 | |
983 ui::LatencyInfo::LatencyComponent comp1; | |
984 EXPECT_TRUE( | |
985 aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1)); | |
986 EXPECT_EQ(latency_sequence_number1, comp1.sequence_number); | |
987 EXPECT_TRUE( | |
988 aggregated_latency_info.FindLatency(latency_type2, latency_id2, nullptr)); | |
989 EXPECT_TRUE(aggregated_latency_info.FindLatency( | |
990 ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, nullptr)); | |
991 } | |
992 | |
993 // Checks whether the latency info are moved to the new surface from the old | |
994 // one when LocalSurfaceId changes. The new surface has unresolved dependencies. | |
995 TEST_F(SurfaceSynchronizationTest, | |
996 LatencyInfoCarriedOverOnResize_NewSurfaceHasPendingFrame) { | |
997 const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); | |
998 const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2); | |
999 const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1); | |
1000 | |
1001 const ui::LatencyComponentType latency_type1 = | |
1002 ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT; | |
1003 const int64_t latency_id1 = 234; | |
1004 const int64_t latency_sequence_number1 = 5645432; | |
1005 const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT; | |
1006 const int64_t latency_id2 = 31434351; | |
1007 const int64_t latency_sequence_number2 = 663788; | |
1008 | |
1009 // Submit a frame with no unresolved dependencies. | |
1010 ui::LatencyInfo info; | |
1011 info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1); | |
1012 | |
1013 CompositorFrame frame = MakeCompositorFrame(); | |
1014 frame.metadata.latency_info.push_back(info); | |
1015 | |
1016 parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(), | |
1017 std::move(frame)); | |
1018 | |
1019 // Verify that the old surface has an active frame only. | |
1020 Surface* old_surface = surface_manager().GetSurfaceForId(parent_id1); | |
1021 ASSERT_NE(nullptr, old_surface); | |
1022 EXPECT_TRUE(old_surface->HasActiveFrame()); | |
1023 EXPECT_FALSE(old_surface->HasPendingFrame()); | |
1024 | |
1025 // Submit a frame with a new local surface id and with unresolved | |
1026 // dependencies. | |
1027 ui::LatencyInfo info2; | |
1028 info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2); | |
1029 | |
1030 CompositorFrame frame2 = MakeCompositorFrame({child_id}, empty_surface_ids(), | |
1031 TransferableResourceArray()); | |
1032 frame2.metadata.latency_info.push_back(info2); | |
1033 | |
1034 parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(), | |
1035 std::move(frame2)); | |
1036 | |
1037 // Verify that the new surface has a pending frame and no active frame. | |
1038 Surface* surface = surface_manager().GetSurfaceForId(parent_id2); | |
1039 ASSERT_NE(nullptr, surface); | |
1040 EXPECT_TRUE(surface->HasPendingFrame()); | |
1041 EXPECT_FALSE(surface->HasActiveFrame()); | |
1042 | |
1043 // Resolve the dependencies. The frame in parent's surface must become active. | |
1044 child_support1().SubmitCompositorFrame(child_id.local_surface_id(), | |
1045 MakeCompositorFrame()); | |
1046 EXPECT_FALSE(surface->HasPendingFrame()); | |
1047 EXPECT_TRUE(surface->HasActiveFrame()); | |
1048 | |
1049 // Both latency info elements must exist in the now-activated frame of the | |
1050 // new surface. | |
1051 std::vector<ui::LatencyInfo> info_list; | |
1052 surface->TakeLatencyInfo(&info_list); | |
1053 EXPECT_EQ(2u, info_list.size()); | |
1054 | |
1055 ui::LatencyInfo aggregated_latency_info = info_list[0]; | |
1056 aggregated_latency_info.AddNewLatencyFrom(info_list[1]); | |
1057 | |
1058 // Two components are the original ones, and the third one is | |
1059 // DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, logged on compositor frame | |
1060 // submit. | |
1061 EXPECT_EQ(3u, aggregated_latency_info.latency_components().size()); | |
1062 | |
1063 ui::LatencyInfo::LatencyComponent comp1; | |
1064 EXPECT_TRUE( | |
1065 aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1)); | |
1066 EXPECT_EQ(latency_sequence_number1, comp1.sequence_number); | |
1067 EXPECT_TRUE( | |
1068 aggregated_latency_info.FindLatency(latency_type2, latency_id2, nullptr)); | |
1069 EXPECT_TRUE(aggregated_latency_info.FindLatency( | |
1070 ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, nullptr)); | |
1071 } | |
1072 | |
1073 // Checks that resources and ack are sent together if possible. | |
1074 TEST_F(SurfaceSynchronizationTest, ReturnResourcesWithAck) { | |
1075 const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); | |
1076 TransferableResource resource; | |
1077 resource.id = 1234; | |
1078 parent_support().SubmitCompositorFrame( | |
1079 parent_id.local_surface_id(), | |
1080 MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(), | |
1081 {resource})); | |
1082 ReturnedResourceArray returned_resources; | |
1083 TransferableResource::ReturnResources({resource}, &returned_resources); | |
1084 EXPECT_CALL(support_client_, ReclaimResources(_)).Times(0); | |
1085 EXPECT_CALL(support_client_, | |
1086 DidReceiveCompositorFrameAck(Eq(returned_resources))); | |
1087 parent_support().SubmitCompositorFrame(parent_id.local_surface_id(), | |
1088 MakeCompositorFrame()); | |
1089 } | |
1090 | |
1091 // Verifies that if a surface is marked destroyed and a new frame arrives for | |
1092 // it, it will be recovered. | |
1093 TEST_F(SurfaceSynchronizationTest, SurfaceResurrection) { | |
1094 const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); | |
1095 const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 3); | |
1096 | |
1097 // Create the child surface by submitting a frame to it. | |
1098 EXPECT_EQ(nullptr, surface_manager().GetSurfaceForId(child_id)); | |
1099 child_support1().SubmitCompositorFrame(child_id.local_surface_id(), | |
1100 MakeCompositorFrame()); | |
1101 | |
1102 // Verify that the child surface is created. | |
1103 Surface* surface = surface_manager().GetSurfaceForId(child_id); | |
1104 EXPECT_NE(nullptr, surface); | |
1105 | |
1106 // Add a reference from the parent to the child. | |
1107 parent_support().SubmitCompositorFrame( | |
1108 parent_id.local_surface_id(), | |
1109 MakeCompositorFrame({child_id}, {child_id}, TransferableResourceArray())); | |
1110 | |
1111 // Attempt to destroy the child surface. The surface must still exist since | |
1112 // the parent needs it but it will be marked as destroyed. | |
1113 child_support1().EvictCurrentSurface(); | |
1114 surface = surface_manager().GetSurfaceForId(child_id); | |
1115 EXPECT_NE(nullptr, surface); | |
1116 EXPECT_TRUE(surface->destroyed()); | |
1117 | |
1118 // Child submits another frame to the same local surface id that is marked | |
1119 // destroyed. | |
1120 child_support1().SubmitCompositorFrame(child_id.local_surface_id(), | |
1121 MakeCompositorFrame()); | |
1122 | |
1123 // Verify that the surface that was marked destroyed is recovered and is being | |
1124 // used again. | |
1125 Surface* surface2 = surface_manager().GetSurfaceForId(child_id); | |
1126 EXPECT_EQ(surface, surface2); | |
1127 EXPECT_FALSE(surface2->destroyed()); | |
1128 } | |
1129 | |
1130 // Verifies that if a LocalSurfaceId belonged to a surface that doesn't exist | |
1131 // anymore, it can still be reused for new surfaces. | |
1132 TEST_F(SurfaceSynchronizationTest, LocalSurfaceIdIsReusable) { | |
1133 const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); | |
1134 const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 3); | |
1135 | |
1136 // Submit the first frame. Creates the surface. | |
1137 child_support1().SubmitCompositorFrame(child_id.local_surface_id(), | |
1138 MakeCompositorFrame()); | |
1139 EXPECT_NE(nullptr, surface_manager().GetSurfaceForId(child_id)); | |
1140 | |
1141 // Add a reference from parent. | |
1142 parent_support().SubmitCompositorFrame( | |
1143 parent_id.local_surface_id(), | |
1144 MakeCompositorFrame({child_id}, {child_id}, TransferableResourceArray())); | |
1145 | |
1146 // Remove the reference from parant. This allows us to destroy the surface. | |
1147 parent_support().SubmitCompositorFrame(parent_id.local_surface_id(), | |
1148 MakeCompositorFrame()); | |
1149 | |
1150 // Destroy the surface. | |
1151 child_support1().EvictCurrentSurface(); | |
1152 EXPECT_EQ(nullptr, surface_manager().GetSurfaceForId(child_id)); | |
1153 | |
1154 // Submit another frame with the same local surface id. This should work fine | |
1155 // and a new surface must be created. | |
1156 child_support1().SubmitCompositorFrame(child_id.local_surface_id(), | |
1157 MakeCompositorFrame()); | |
1158 EXPECT_NE(nullptr, surface_manager().GetSurfaceForId(child_id)); | |
1159 } | |
1160 | |
1161 // This test verifies that a crash does not occur if garbage collection is | |
1162 // triggered during surface dependency resolution. This test triggers garbage | |
1163 // collection during surface resolution, by causing an activation to remove | |
1164 // a surface subtree from the root. Both the old subtree and the new | |
1165 // activated subtree refer to the same dependency. The old subtree was activated | |
1166 // by deadline, and the new subtree was activated by a dependency finally | |
1167 // resolving. | |
1168 TEST_F(SurfaceSynchronizationTest, DependencyTrackingGarbageCollection) { | |
1169 const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1); | |
1170 const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); | |
1171 const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2); | |
1172 const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1); | |
1173 | |
1174 parent_support().SubmitCompositorFrame( | |
1175 parent_id1.local_surface_id(), | |
1176 MakeCompositorFrame({child_id}, empty_surface_ids(), | |
1177 TransferableResourceArray())); | |
1178 display_support().SubmitCompositorFrame( | |
1179 display_id.local_surface_id(), | |
1180 MakeCompositorFrame({parent_id1}, empty_surface_ids(), | |
1181 TransferableResourceArray())); | |
1182 | |
1183 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
1184 | |
1185 BeginFrameArgs args = | |
1186 CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); | |
1187 | |
1188 // Advance BeginFrames to trigger a deadline. | |
1189 for (int i = 0; i < 3; ++i) { | |
1190 begin_frame_source()->TestOnBeginFrame(args); | |
1191 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
1192 } | |
1193 begin_frame_source()->TestOnBeginFrame(args); | |
1194 EXPECT_FALSE(dependency_tracker().has_deadline()); | |
1195 | |
1196 EXPECT_TRUE(display_surface()->HasActiveFrame()); | |
1197 EXPECT_FALSE(display_surface()->HasPendingFrame()); | |
1198 EXPECT_TRUE(parent_surface()->HasActiveFrame()); | |
1199 EXPECT_FALSE(parent_surface()->HasPendingFrame()); | |
1200 | |
1201 parent_support().SubmitCompositorFrame( | |
1202 parent_id2.local_surface_id(), | |
1203 MakeCompositorFrame({child_id}, empty_surface_ids(), | |
1204 TransferableResourceArray())); | |
1205 display_support().SubmitCompositorFrame( | |
1206 display_id.local_surface_id(), | |
1207 MakeCompositorFrame({parent_id2}, empty_surface_ids(), | |
1208 TransferableResourceArray())); | |
1209 | |
1210 // The display surface now has two CompositorFrames. One that is pending, | |
1211 // indirectly blocked on child_id and one that is active, also indirectly | |
1212 // referring to child_id, but activated due to the deadline above. | |
1213 EXPECT_TRUE(display_surface()->HasActiveFrame()); | |
1214 EXPECT_TRUE(display_surface()->HasPendingFrame()); | |
1215 | |
1216 // Submitting a CompositorFrame will trigger garbage collection of the | |
1217 // |parent_id1| subtree. This should not crash. | |
1218 child_support1().SubmitCompositorFrame(child_id.local_surface_id(), | |
1219 MakeCompositorFrame()); | |
1220 } | |
1221 | |
1222 // This test verifies that a crash does not occur if garbage collection is | |
1223 // triggered when a deadline forces frame activation. This test triggers garbage | |
1224 // collection during deadline activation by causing the activation of a display | |
1225 // frame to replace a previously activated display frame that was referring to | |
1226 // a now-unreachable surface subtree. That subtree gets garbage collected during | |
1227 // deadline activation. SurfaceDependencyTracker is also tracking a surface | |
1228 // from that subtree due to an unresolved dependency. This test verifies that | |
1229 // this dependency resolution does not crash. | |
1230 TEST_F(SurfaceSynchronizationTest, GarbageCollectionOnDeadline) { | |
1231 const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1); | |
1232 const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); | |
1233 const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2); | |
1234 const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1); | |
1235 | |
1236 // |parent_id1| is blocked on |child_id|. | |
1237 parent_support().SubmitCompositorFrame( | |
1238 parent_id1.local_surface_id(), | |
1239 MakeCompositorFrame({child_id}, empty_surface_ids(), | |
1240 TransferableResourceArray())); | |
1241 | |
1242 display_support().SubmitCompositorFrame( | |
1243 display_id.local_surface_id(), | |
1244 MakeCompositorFrame({parent_id1}, {parent_id1}, | |
1245 TransferableResourceArray())); | |
1246 | |
1247 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
1248 EXPECT_TRUE(display_surface()->HasPendingFrame()); | |
1249 EXPECT_FALSE(display_surface()->HasActiveFrame()); | |
1250 | |
1251 // Advance BeginFrames to trigger a deadline. This activates the | |
1252 // CompositorFrame submitted above. | |
1253 BeginFrameArgs args = | |
1254 CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); | |
1255 for (int i = 0; i < 3; ++i) { | |
1256 begin_frame_source()->TestOnBeginFrame(args); | |
1257 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
1258 } | |
1259 begin_frame_source()->TestOnBeginFrame(args); | |
1260 EXPECT_FALSE(dependency_tracker().has_deadline()); | |
1261 EXPECT_FALSE(display_surface()->HasPendingFrame()); | |
1262 EXPECT_TRUE(display_surface()->HasActiveFrame()); | |
1263 | |
1264 // By submitting a display CompositorFrame, and replacing the parent's | |
1265 // CompositorFrame with another surface ID, parent_id1 becomes unreachable and | |
1266 // a candidate for garbage collection. | |
1267 display_support().SubmitCompositorFrame( | |
1268 display_id.local_surface_id(), | |
1269 MakeCompositorFrame({parent_id2}, empty_surface_ids(), | |
1270 TransferableResourceArray())); | |
1271 | |
1272 // Now |parent_id1| is only kept alive by the active |display_id| frame. | |
1273 parent_support().SubmitCompositorFrame( | |
1274 parent_id2.local_surface_id(), | |
1275 MakeCompositorFrame({child_id}, empty_surface_ids(), | |
1276 TransferableResourceArray())); | |
1277 | |
1278 // SurfaceDependencyTracker should now be tracking |display_id|, |parent_id1| | |
1279 // and |parent_id2|. By activating the pending |display_id| frame by deadline, | |
1280 // |parent_id1| becomes unreachable and is garbage collected while | |
1281 // SurfaceDependencyTracker is in the process of activating surfaces. This | |
1282 // should not cause a crash or use-after-free. | |
1283 for (int i = 0; i < 3; ++i) { | |
1284 begin_frame_source()->TestOnBeginFrame(args); | |
1285 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
1286 } | |
1287 begin_frame_source()->TestOnBeginFrame(args); | |
1288 EXPECT_FALSE(dependency_tracker().has_deadline()); | |
1289 } | |
1290 | |
1291 // This test verifies that a CompositorFrame will only blocked on embedded | |
1292 // surfaces but not on other retained surface IDs in the CompositorFrame. | |
1293 TEST_F(SurfaceSynchronizationTest, OnlyBlockOnEmbeddedSurfaces) { | |
1294 const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1); | |
1295 const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); | |
1296 const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2); | |
1297 | |
1298 // Submitting a CompositorFrame with |parent_id2| so that the display | |
1299 // CompositorFrame can hold a reference to it. | |
1300 parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(), | |
1301 MakeCompositorFrame()); | |
1302 | |
1303 display_support().SubmitCompositorFrame( | |
1304 display_id.local_surface_id(), | |
1305 MakeCompositorFrame({parent_id1}, {parent_id2}, | |
1306 TransferableResourceArray())); | |
1307 | |
1308 EXPECT_TRUE(display_surface()->HasPendingFrame()); | |
1309 EXPECT_FALSE(display_surface()->HasActiveFrame()); | |
1310 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
1311 | |
1312 // Verify that the display CompositorFrame will only block on |parent_id1| but | |
1313 // not |parent_id2|. | |
1314 EXPECT_THAT(display_surface()->blocking_surfaces(), | |
1315 UnorderedElementsAre(parent_id1)); | |
1316 // Verify that the display surface holds no references while its | |
1317 // CompositorFrame is pending. | |
1318 EXPECT_THAT(GetChildReferences(display_id), IsEmpty()); | |
1319 | |
1320 // Submitting a CompositorFrame with |parent_id1| should unblock the display | |
1321 // CompositorFrame. | |
1322 parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(), | |
1323 MakeCompositorFrame()); | |
1324 | |
1325 EXPECT_FALSE(dependency_tracker().has_deadline()); | |
1326 EXPECT_FALSE(display_surface()->HasPendingFrame()); | |
1327 EXPECT_TRUE(display_surface()->HasActiveFrame()); | |
1328 EXPECT_THAT(display_surface()->blocking_surfaces(), IsEmpty()); | |
1329 } | |
1330 | |
1331 // This test verifies that a late arriving CompositorFrame activates immediately | |
1332 // and does not trigger a new deadline. | |
1333 TEST_F(SurfaceSynchronizationTest, LateArrivingDependency) { | |
1334 const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1); | |
1335 const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); | |
1336 const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); | |
1337 | |
1338 display_support().SubmitCompositorFrame( | |
1339 display_id.local_surface_id(), | |
1340 MakeCompositorFrame({parent_id1}, empty_surface_ids(), | |
1341 TransferableResourceArray())); | |
1342 | |
1343 EXPECT_TRUE(display_surface()->HasPendingFrame()); | |
1344 EXPECT_FALSE(display_surface()->HasActiveFrame()); | |
1345 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
1346 | |
1347 // Advance BeginFrames to trigger a deadline. This activates the | |
1348 // CompositorFrame submitted above. | |
1349 BeginFrameArgs args = | |
1350 CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); | |
1351 for (int i = 0; i < 3; ++i) { | |
1352 begin_frame_source()->TestOnBeginFrame(args); | |
1353 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
1354 } | |
1355 begin_frame_source()->TestOnBeginFrame(args); | |
1356 EXPECT_FALSE(dependency_tracker().has_deadline()); | |
1357 EXPECT_FALSE(display_surface()->HasPendingFrame()); | |
1358 EXPECT_TRUE(display_surface()->HasActiveFrame()); | |
1359 | |
1360 // A late arriving CompositorFrame should activate immediately without | |
1361 // scheduling a deadline and without waiting for dependencies to resolve. | |
1362 parent_support().SubmitCompositorFrame( | |
1363 parent_id1.local_surface_id(), | |
1364 MakeCompositorFrame({child_id1}, empty_surface_ids(), | |
1365 TransferableResourceArray())); | |
1366 EXPECT_FALSE(dependency_tracker().has_deadline()); | |
1367 EXPECT_FALSE(parent_surface()->HasPendingFrame()); | |
1368 EXPECT_TRUE(parent_surface()->HasActiveFrame()); | |
1369 } | |
1370 | |
1371 // This test verifies that CompositorFrames submitted to a surface referenced | |
1372 // by a parent CompositorFrame as a fallback will be rejected and ACK'ed | |
1373 // immediately. | |
1374 TEST_F(SurfaceSynchronizationTest, FallbackSurfacesClosed) { | |
1375 const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); | |
1376 // This is the fallback child surface that the parent holds a reference to. | |
1377 const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); | |
1378 // This is the primary child surface that the parent wants to block on. | |
1379 const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 2); | |
1380 | |
1381 // child_support1 submits a CompositorFrame without any dependencies. | |
1382 // DidReceiveCompositorFrameAck should call on immediate activation. | |
1383 // However, resources will not be returned because this frame is a candidate | |
1384 // for display. | |
1385 TransferableResource resource; | |
1386 resource.id = 1337; | |
1387 resource.format = ALPHA_8; | |
1388 resource.filter = 1234; | |
1389 resource.size = gfx::Size(1234, 5678); | |
1390 ReturnedResourceArray returned_resources; | |
1391 TransferableResource::ReturnResources({resource}, &returned_resources); | |
1392 | |
1393 EXPECT_CALL(support_client_, | |
1394 DidReceiveCompositorFrameAck(Eq(ReturnedResourceArray()))); | |
1395 child_support1().SubmitCompositorFrame( | |
1396 child_id1.local_surface_id(), | |
1397 MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(), | |
1398 {resource})); | |
1399 testing::Mock::VerifyAndClearExpectations(&support_client_); | |
1400 | |
1401 // The parent is blocked on |child_id2| and references |child_id1|. The | |
1402 // surface corresponding to |child_id1| will not accept new CompositorFrames | |
1403 // while the parent CompositorFrame is blocked. | |
1404 parent_support().SubmitCompositorFrame( | |
1405 parent_id1.local_surface_id(), | |
1406 MakeCompositorFrame({child_id2}, {child_id1}, | |
1407 TransferableResourceArray())); | |
1408 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
1409 EXPECT_TRUE(parent_surface()->HasPendingFrame()); | |
1410 EXPECT_FALSE(parent_surface()->HasActiveFrame()); | |
1411 | |
1412 // Resources will be returned immediately because |child_id1|'s surface is | |
1413 // closed. | |
1414 TransferableResource resource2; | |
1415 resource2.id = 1246; | |
1416 resource2.format = ALPHA_8; | |
1417 resource2.filter = 1357; | |
1418 resource2.size = gfx::Size(8765, 4321); | |
1419 ReturnedResourceArray returned_resources2; | |
1420 TransferableResource::ReturnResources({resource2}, &returned_resources2); | |
1421 EXPECT_CALL(support_client_, | |
1422 DidReceiveCompositorFrameAck(Eq(returned_resources2))); | |
1423 child_support1().SubmitCompositorFrame( | |
1424 child_id1.local_surface_id(), | |
1425 MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(), | |
1426 {resource2})); | |
1427 testing::Mock::VerifyAndClearExpectations(&support_client_); | |
1428 | |
1429 // Advance BeginFrames to trigger a deadline. This activates the | |
1430 // CompositorFrame submitted to the parent. | |
1431 BeginFrameArgs args = | |
1432 CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); | |
1433 for (int i = 0; i < 3; ++i) { | |
1434 begin_frame_source()->TestOnBeginFrame(args); | |
1435 EXPECT_TRUE(dependency_tracker().has_deadline()); | |
1436 } | |
1437 begin_frame_source()->TestOnBeginFrame(args); | |
1438 EXPECT_FALSE(dependency_tracker().has_deadline()); | |
1439 EXPECT_FALSE(parent_surface()->HasPendingFrame()); | |
1440 EXPECT_TRUE(parent_surface()->HasActiveFrame()); | |
1441 | |
1442 // Resources will be returned immediately because |child_id1|'s surface is | |
1443 // closed forever. | |
1444 EXPECT_CALL(support_client_, | |
1445 DidReceiveCompositorFrameAck(Eq(returned_resources2))); | |
1446 child_support1().SubmitCompositorFrame( | |
1447 child_id1.local_surface_id(), | |
1448 MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(), | |
1449 {resource2})); | |
1450 testing::Mock::VerifyAndClearExpectations(&support_client_); | |
1451 } | |
1452 */ | |
1453 | |
1454 } // namespace test | |
1455 } // namespace cc | |
OLD | NEW |