Flutter Engine
 
Loading...
Searching...
No Matches
flatland_connection_unittests.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter 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
6
7#include <fuchsia/scenic/scheduling/cpp/fidl.h>
8#include <fuchsia/ui/composition/cpp/fidl.h>
9#include <lib/async-testing/test_loop.h>
10#include <lib/async/cpp/task.h>
11#include <zircon/rights.h>
12#include <zircon/types.h>
13
14#include <string>
15#include <vector>
16
17#include "flutter/fml/logging.h"
20#include "gtest/gtest.h"
21
23
25
26namespace {
27
28std::string GetCurrentTestName() {
29 return ::testing::UnitTest::GetInstance()->current_test_info()->name();
30}
31
32void AwaitVsyncChecked(FlatlandConnection& flatland_connection,
33 bool& condition_variable,
34 fml::TimeDelta expected_frame_delta) {
35 flatland_connection.AwaitVsync(
36 [&condition_variable, expected_frame_delta](fml::TimePoint frame_start,
37 fml::TimePoint frame_end) {
38 EXPECT_EQ(frame_end.ToEpochDelta() - frame_start.ToEpochDelta(),
39 expected_frame_delta);
40 condition_variable = true;
41 });
42}
43
44void AwaitVsyncChecked(FlatlandConnection& flatland_connection,
45 bool& condition_variable,
46 fml::TimePoint expected_frame_end) {
47 flatland_connection.AwaitVsync(
48 [&condition_variable, expected_frame_end](fml::TimePoint frame_start,
49 fml::TimePoint frame_end) {
50 EXPECT_EQ(frame_end, expected_frame_end);
51 condition_variable = true;
52 });
53}
54
55std::vector<fuchsia::scenic::scheduling::PresentationInfo>
56CreateFuturePresentationInfos(const fml::TimePoint& presentation_time_1,
57 const fml::TimePoint& presentation_time_2) {
58 fuchsia::scenic::scheduling::PresentationInfo info_1;
59 info_1.set_presentation_time(
60 presentation_time_1.ToEpochDelta().ToNanoseconds());
61 std::vector<fuchsia::scenic::scheduling::PresentationInfo> infos;
62 infos.push_back(std::move(info_1));
63 fuchsia::scenic::scheduling::PresentationInfo info_2;
64 info_2.set_presentation_time(
65 presentation_time_2.ToEpochDelta().ToNanoseconds());
66 infos.push_back(std::move(info_2));
67 return infos;
68}
69
70} // namespace
71
72class FlatlandConnectionTest : public ::testing::Test {
73 protected:
75 : session_subloop_(loop_.StartNewLoop()),
76 flatland_handle_(
77 fake_flatland_.ConnectFlatland(session_subloop_->dispatcher())) {}
78 ~FlatlandConnectionTest() override = default;
79
80 async::TestLoop& loop() { return loop_; }
81
82 async_dispatcher_t* subloop_dispatcher() {
83 return session_subloop_->dispatcher();
84 }
85
86 FakeFlatland& fake_flatland() { return fake_flatland_; }
87
88 fidl::InterfaceHandle<fuchsia::ui::composition::Flatland>
90 FML_CHECK(flatland_handle_.is_valid());
91 return std::move(flatland_handle_);
92 }
93
94 // Syntactic sugar for OnNextFrameBegin
95 void OnNextFrameBegin(int num_present_credits,
96 const fml::TimePoint& presentation_time_1,
97 const fml::TimePoint& presentation_time_2) {
98 fuchsia::ui::composition::OnNextFrameBeginValues on_next_frame_begin_values;
99 on_next_frame_begin_values.set_additional_present_credits(
100 num_present_credits);
101 on_next_frame_begin_values.set_future_presentation_infos(
102 CreateFuturePresentationInfos(presentation_time_1,
103 presentation_time_2));
105 std::move(on_next_frame_begin_values));
106 }
107 void OnNextFrameBegin(int num_present_credits) {
108 const auto now = fml::TimePoint::Now();
109 const auto kPresentationTime1 = now + fml::TimeDelta::FromSeconds(100);
110 const auto kPresentationTime2 = now + fml::TimeDelta::FromSeconds(200);
111 OnNextFrameBegin(num_present_credits, kPresentationTime1,
112 kPresentationTime2);
113 }
114
115 private:
116 async::TestLoop loop_;
117 std::unique_ptr<async::LoopInterface> session_subloop_;
118
119 FakeFlatland fake_flatland_;
120
121 fidl::InterfaceHandle<fuchsia::ui::composition::Flatland> flatland_handle_;
122};
123
125 // Create the FlatlandConnection but don't pump the loop. No FIDL calls are
126 // completed yet.
127 const std::string debug_name = GetCurrentTestName();
128 flutter_runner::FlatlandConnection flatland_connection(
129 debug_name, TakeFlatlandHandle(), []() { FAIL(); },
130 [](auto...) { FAIL(); }, loop().dispatcher());
131 EXPECT_EQ(fake_flatland().debug_name(), "");
132
133 // Simulate an AwaitVsync that returns immediately.
134 bool await_vsync_fired = false;
135 AwaitVsyncChecked(flatland_connection, await_vsync_fired,
137 EXPECT_TRUE(await_vsync_fired);
138
139 // Ensure the debug name is set.
140 loop().RunUntilIdle();
141 EXPECT_EQ(fake_flatland().debug_name(), debug_name);
142}
143
144TEST_F(FlatlandConnectionTest, FlatlandDisconnect) {
145 // Set up a callback which allows sensing of the error state.
146 bool error_fired = false;
147 fml::closure on_session_error = [&error_fired]() { error_fired = true; };
148
149 // Create the FlatlandConnection but don't pump the loop. No FIDL calls are
150 // completed yet.
151 flutter_runner::FlatlandConnection flatland_connection(
152 GetCurrentTestName(), TakeFlatlandHandle(), std::move(on_session_error),
153 [](auto...) { FAIL(); }, loop().dispatcher());
154 EXPECT_FALSE(error_fired);
155
156 // Simulate a flatland disconnection, then Pump the loop. The error callback
157 // will fire.
158 fake_flatland().Disconnect(
159 fuchsia::ui::composition::FlatlandError::BAD_OPERATION);
160 loop().RunUntilIdle();
161 EXPECT_TRUE(error_fired);
162}
163
165 // Set up callbacks which allow sensing of how many presents were handled.
166 size_t presents_called = 0u;
167 zx_handle_t release_fence_handle;
168 fake_flatland().SetPresentHandler([&presents_called,
169 &release_fence_handle](auto present_args) {
170 presents_called++;
171 release_fence_handle = present_args.release_fences().empty()
172 ? ZX_HANDLE_INVALID
173 : present_args.release_fences().front().get();
174 });
175
176 // Set up a callback which allows sensing of how many vsync's
177 // (`OnFramePresented` events) were handled.
178 size_t vsyncs_handled = 0u;
179 on_frame_presented_event on_frame_presented = [&vsyncs_handled](auto...) {
180 vsyncs_handled++;
181 };
182
183 // Create the FlatlandConnection but don't pump the loop. No FIDL calls are
184 // completed yet.
185 flutter_runner::FlatlandConnection flatland_connection(
186 GetCurrentTestName(), TakeFlatlandHandle(), []() { FAIL(); },
187 std::move(on_frame_presented), loop().dispatcher());
188 EXPECT_EQ(presents_called, 0u);
189 EXPECT_EQ(vsyncs_handled, 0u);
190
191 // Pump the loop. Nothing is called.
192 loop().RunUntilIdle();
193 EXPECT_EQ(presents_called, 0u);
194 EXPECT_EQ(vsyncs_handled, 0u);
195
196 // Simulate an AwaitVsync that comes after the first call.
197 bool await_vsync_fired = false;
198 AwaitVsyncChecked(flatland_connection, await_vsync_fired,
200 EXPECT_TRUE(await_vsync_fired);
201
202 // Call Present and Pump the loop; `Present` and its callback is called. No
203 // release fence should be queued.
204 await_vsync_fired = false;
205 zx::event first_release_fence;
206 zx::event::create(0u, &first_release_fence);
207 const zx_handle_t first_release_fence_handle = first_release_fence.get();
208 flatland_connection.EnqueueReleaseFence(std::move(first_release_fence));
209 flatland_connection.Present();
210 loop().RunUntilIdle();
211 EXPECT_EQ(presents_called, 1u);
212 EXPECT_EQ(release_fence_handle, ZX_HANDLE_INVALID);
213 EXPECT_EQ(vsyncs_handled, 0u);
214 EXPECT_FALSE(await_vsync_fired);
215
216 // Fire the `OnNextFrameBegin` event. AwaitVsync should be fired.
217 const auto now = fml::TimePoint::Now();
218 const auto kPresentationTime1 = now + fml::TimeDelta::FromSeconds(100);
219 const auto kPresentationTime2 = now + fml::TimeDelta::FromSeconds(200);
220 fuchsia::ui::composition::OnNextFrameBeginValues on_next_frame_begin_values;
221 on_next_frame_begin_values.set_additional_present_credits(3);
222 on_next_frame_begin_values.set_future_presentation_infos(
223 CreateFuturePresentationInfos(kPresentationTime1, kPresentationTime2));
224 fake_flatland().FireOnNextFrameBeginEvent(
225 std::move(on_next_frame_begin_values));
226 loop().RunUntilIdle();
227 AwaitVsyncChecked(flatland_connection, await_vsync_fired, kPresentationTime1);
228 EXPECT_TRUE(await_vsync_fired);
229
230 // Fire the `OnFramePresented` event associated with the first `Present`,
231 fake_flatland().FireOnFramePresentedEvent(
232 fuchsia::scenic::scheduling::FramePresentedInfo());
233 loop().RunUntilIdle();
234 EXPECT_EQ(vsyncs_handled, 1u);
235
236 // Call Present for a second time and Pump the loop; `Present` and its
237 // callback is called. Release fences for the earlier present is used.
238 await_vsync_fired = false;
239 flatland_connection.Present();
240 loop().RunUntilIdle();
241 EXPECT_EQ(presents_called, 2u);
242 EXPECT_EQ(release_fence_handle, first_release_fence_handle);
243
244 // AwaitVsync should be fired with the second present.
245 await_vsync_fired = false;
246 AwaitVsyncChecked(flatland_connection, await_vsync_fired, kPresentationTime2);
247 EXPECT_TRUE(await_vsync_fired);
248}
249
250TEST_F(FlatlandConnectionTest, AwaitVsyncsBeforeOnNextFrameBegin) {
251 // Set up callbacks which allow sensing of how many presents were handled.
252 size_t presents_called = 0u;
253 fake_flatland().SetPresentHandler(
254 [&presents_called](auto present_args) { presents_called++; });
255
256 // Create the FlatlandConnection but don't pump the loop. No FIDL calls are
257 // completed yet.
258 flutter_runner::FlatlandConnection flatland_connection(
259 GetCurrentTestName(), TakeFlatlandHandle(), []() { FAIL(); },
260 [](auto...) {}, loop().dispatcher());
261 EXPECT_EQ(presents_called, 0u);
262
263 // Pump the loop. Nothing is called.
264 loop().RunUntilIdle();
265 EXPECT_EQ(presents_called, 0u);
266
267 // Simulate an AwaitVsync that comes before the first Present.
268 bool await_vsync_callback_fired = false;
269 AwaitVsyncChecked(flatland_connection, await_vsync_callback_fired,
271 EXPECT_TRUE(await_vsync_callback_fired);
272
273 // AwaitVsync that comes before the first Present.
274 bool await_vsync_secondary_callback_fired = false;
275 flatland_connection.AwaitVsyncForSecondaryCallback(
276 [&await_vsync_secondary_callback_fired](fml::TimePoint frame_start,
277 fml::TimePoint frame_end) {
278 await_vsync_secondary_callback_fired = true;
279 });
280 EXPECT_TRUE(await_vsync_secondary_callback_fired);
281}
282
283TEST_F(FlatlandConnectionTest, RunsOutOfFuturePresentationInfos) {
284 // Set up callbacks which allow sensing of how many presents were handled.
285 size_t presents_called = 0u;
286 fake_flatland().SetPresentHandler(
287 [&presents_called](auto present_args) { presents_called++; });
288
289 // Set up a callback which allows sensing of how many vsync's
290 // (`OnFramePresented` events) were handled.
291 size_t vsyncs_handled = 0u;
292 on_frame_presented_event on_frame_presented = [&vsyncs_handled](auto...) {
293 vsyncs_handled++;
294 };
295
296 // Create the FlatlandConnection but don't pump the loop. No FIDL calls are
297 // completed yet.
298 flutter_runner::FlatlandConnection flatland_connection(
299 GetCurrentTestName(), TakeFlatlandHandle(), []() { FAIL(); },
300 std::move(on_frame_presented), loop().dispatcher());
301 EXPECT_EQ(presents_called, 0u);
302 EXPECT_EQ(vsyncs_handled, 0u);
303
304 // Pump the loop. Nothing is called.
305 loop().RunUntilIdle();
306 EXPECT_EQ(presents_called, 0u);
307 EXPECT_EQ(vsyncs_handled, 0u);
308
309 // Simulate an AwaitVsync that comes before the first Present.
310 bool await_vsync_callback_fired = false;
311 AwaitVsyncChecked(flatland_connection, await_vsync_callback_fired,
313 EXPECT_TRUE(await_vsync_callback_fired);
314
315 // Queue Present.
316 flatland_connection.Present();
317 loop().RunUntilIdle();
318 EXPECT_EQ(presents_called, 1u);
319
320 // Fire the `OnNextFrameBegin` event. AwaitVsync callback should be fired with
321 // the first presentation time.
322 await_vsync_callback_fired = false;
323 const auto kPresentationTime1 =
325 const auto kVsyncInterval = fml::TimeDelta::FromSeconds(234);
326 const auto kPresentationTime2 = kPresentationTime1 + kVsyncInterval;
327 OnNextFrameBegin(1, kPresentationTime1, kPresentationTime2);
328 loop().RunUntilIdle();
329 AwaitVsyncChecked(flatland_connection, await_vsync_callback_fired,
330 kPresentationTime1);
331 EXPECT_TRUE(await_vsync_callback_fired);
332
333 // Second consecutive AwaitVsync callback should be fired with
334 // the second presentation time.
335 await_vsync_callback_fired = false;
336 AwaitVsyncChecked(flatland_connection, await_vsync_callback_fired,
337 kPresentationTime2);
338 EXPECT_TRUE(await_vsync_callback_fired);
339
340 // Another AwaitVsync callback should be fired with vsync_interval.
341 await_vsync_callback_fired = false;
342 AwaitVsyncChecked(flatland_connection, await_vsync_callback_fired,
343 kPresentationTime2 + kVsyncInterval);
344 EXPECT_TRUE(await_vsync_callback_fired);
345}
346
347TEST_F(FlatlandConnectionTest, PresentCreditExhaustion) {
348 // Set up callbacks which allow sensing of how many presents were handled.
349 size_t num_presents_called = 0u;
350 size_t num_release_fences = 0u;
351 size_t num_acquire_fences = 0u;
352
353 auto reset_test_counters = [&num_presents_called, &num_acquire_fences,
354 &num_release_fences]() {
355 num_presents_called = 0u;
356 num_release_fences = 0u;
357 num_acquire_fences = 0u;
358 };
359
360 fake_flatland().SetPresentHandler(
361 [&num_presents_called, &num_acquire_fences, &num_release_fences](
362 fuchsia::ui::composition::PresentArgs present_args) {
363 num_presents_called++;
364 num_acquire_fences = present_args.acquire_fences().size();
365 num_release_fences = present_args.release_fences().size();
366 });
367
368 // Create the FlatlandConnection but don't pump the loop. No FIDL calls are
369 // completed yet.
370 on_frame_presented_event on_frame_presented = [](auto...) {};
371 flutter_runner::FlatlandConnection flatland_connection(
372 GetCurrentTestName(), TakeFlatlandHandle(), []() { FAIL(); },
373 std::move(on_frame_presented), loop().dispatcher());
374 EXPECT_EQ(num_presents_called, 0u);
375
376 // Pump the loop. Nothing is called.
377 loop().RunUntilIdle();
378 EXPECT_EQ(num_presents_called, 0u);
379
380 // Simulate an AwaitVsync that comes before the first Present.
381 flatland_connection.AwaitVsync([](fml::TimePoint, fml::TimePoint) {});
382 loop().RunUntilIdle();
383 EXPECT_EQ(num_presents_called, 0u);
384
385 // This test uses a fire callback that triggers Present() with a single
386 // acquire and release fence in order to approximate the behavior of the real
387 // flutter fire callback and let us drive presents with ONFBs
388 auto fire_callback = [dispatcher = loop().dispatcher(), &flatland_connection](
389 fml::TimePoint frame_start,
390 fml::TimePoint frame_end) {
391 async::PostTask(dispatcher, [&flatland_connection]() {
392 zx::event acquire_fence;
393 zx::event::create(0u, &acquire_fence);
394 zx::event release_fence;
395 zx::event::create(0u, &release_fence);
396 flatland_connection.EnqueueAcquireFence(std::move(acquire_fence));
397 flatland_connection.EnqueueReleaseFence(std::move(release_fence));
398 flatland_connection.Present();
399 });
400 };
401
402 // Call Await Vsync with a callback that triggers Present and consumes the one
403 // and only present credit we start with.
404 reset_test_counters();
405 flatland_connection.AwaitVsync(fire_callback);
406 loop().RunUntilIdle();
407 EXPECT_EQ(num_presents_called, 1u);
408 EXPECT_EQ(num_acquire_fences, 1u);
409 EXPECT_EQ(num_release_fences, 0u);
410
411 // Do it again, but this time we should not get a present because the client
412 // has exhausted its present credits.
413 reset_test_counters();
414 flatland_connection.AwaitVsync(fire_callback);
415 OnNextFrameBegin(0);
416 loop().RunUntilIdle();
417 EXPECT_EQ(num_presents_called, 0u);
418
419 // Supply a present credit but dont set a new fire callback. Fire callback
420 // from previous ONFB should fire and trigger a Present()
421 reset_test_counters();
422 OnNextFrameBegin(1);
423 loop().RunUntilIdle();
424 EXPECT_EQ(num_presents_called, 1u);
425 EXPECT_EQ(num_acquire_fences, 1u);
426 EXPECT_EQ(num_release_fences, 1u);
427
428 // From here on we are testing handling of a race condition where a fire
429 // callback is fired but another ONFB arrives before the present from the
430 // first fire callback comes in, causing present_credits to be negative
431 // within Present().
432
433 uint num_onfb = 5;
434 uint num_deferred_callbacks = 0;
435 // This callback will accumulate num_onfb+1 calls before firing all
436 // of their presents at once.
437 auto accumulating_fire_callback = [&](fml::TimePoint frame_start,
438 fml::TimePoint frame_end) {
439 num_deferred_callbacks++;
440 if (num_deferred_callbacks > num_onfb) {
442 for (uint i = 0; i < num_onfb + 1; i++) {
443 fire_callback(now, now);
444 num_deferred_callbacks--;
445 }
446 }
447 };
448
449 reset_test_counters();
450 for (uint i = 0; i < num_onfb; i++) {
451 flatland_connection.AwaitVsync(accumulating_fire_callback);
452 // only supply a present credit on the first call. Since Presents are being
453 // deferred this credit will not be used up, but we need a credit to call
454 // the accumulating_fire_callback
455 OnNextFrameBegin(i == 0 ? 1 : 0);
456 loop().RunUntilIdle();
457 EXPECT_EQ(num_presents_called, 0u);
458 }
459
460 // This is the num_onfb+1 call to accumulating_fire_callback which triggers
461 // all of the "racing" presents to fire. the first one should be fired,
462 // but the other num_onfb Presents should be deferred.
463 flatland_connection.AwaitVsync(accumulating_fire_callback);
464 OnNextFrameBegin(0);
465 loop().RunUntilIdle();
466 EXPECT_EQ(num_presents_called, 1u);
467 EXPECT_EQ(num_acquire_fences, 1u);
468 EXPECT_EQ(num_release_fences, 1u);
469
470 // Supply a present credit, but pass an empty lambda to AwaitVsync so
471 // that it doesnt call Present(). Should get a deferred present with
472 // all the accumulate acuire fences
473 reset_test_counters();
474 flatland_connection.AwaitVsync([](fml::TimePoint, fml::TimePoint) {});
475 OnNextFrameBegin(1);
476 loop().RunUntilIdle();
477 EXPECT_EQ(num_presents_called, 1u);
478 EXPECT_EQ(num_acquire_fences, num_onfb);
479 EXPECT_EQ(num_release_fences, 1u);
480
481 // Pump another frame to check that release fences accumulate as expected
482 reset_test_counters();
483 flatland_connection.AwaitVsync(fire_callback);
484 OnNextFrameBegin(1);
485 loop().RunUntilIdle();
486 EXPECT_EQ(num_presents_called, 1u);
487 EXPECT_EQ(num_acquire_fences, 1u);
488 EXPECT_EQ(num_release_fences, num_onfb);
489}
490
491typedef struct {
492 std::shared_ptr<std::vector<zx::event>> fences;
493 std::shared_ptr<std::vector<zx::event>> fences_dup;
494} FencesPair;
495
496// Create two vectors of paired fences.
497FencesPair GetFencesPair(size_t num_fences) {
498 auto fences = std::make_shared<std::vector<zx::event>>();
499 auto fences_dup = std::make_shared<std::vector<zx::event>>();
500 for (size_t i = 0; i < num_fences; i++) {
501 zx::event fence;
502 auto status = zx::event::create(0u, &fence);
503 EXPECT_EQ(status, ZX_OK);
504
505 zx::event fence_dup;
506 status = fence.duplicate(ZX_RIGHT_SAME_RIGHTS, &fence_dup);
507 EXPECT_EQ(status, ZX_OK);
508
509 fences->push_back(std::move(fence));
510 fences_dup->push_back(std::move(fence_dup));
511 }
512 return FencesPair{
513 .fences = fences,
514 .fences_dup = fences_dup,
515 };
516}
517
518void SignalAll(std::vector<zx::event>* fences) {
519 for (auto& fence : *fences) {
520 const auto status = fence.signal(0, ZX_EVENT_SIGNALED);
521 ASSERT_EQ(status, ZX_OK);
522 }
523}
524
525void WaitAll(std::vector<zx::event>* fences) {
526 for (auto& fence : *fences) {
527 zx_signals_t ignored;
528 // Maybe the timeout here should be finite.
529 const auto status =
530 fence.wait_one(ZX_EVENT_SIGNALED, zx::time::infinite(), &ignored);
531 ASSERT_EQ(status, ZX_OK);
532 }
533}
534
536 // Set up callbacks which allow sensing of how many presents were handled.
537 size_t num_presents_called = 0u;
538 size_t num_release_fences = 0u;
539 size_t num_acquire_fences = 0u;
540
541 auto reset_test_counters = [&num_presents_called, &num_acquire_fences,
542 &num_release_fences]() {
543 num_presents_called = 0u;
544 num_release_fences = 0u;
545 num_acquire_fences = 0u;
546 };
547
548 fuchsia::ui::composition::PresentArgs last_present_args;
549 fake_flatland().SetPresentHandler(
550 [&num_presents_called, &num_acquire_fences, &num_release_fences,
551 &last_present_args](fuchsia::ui::composition::PresentArgs present_args) {
552 num_presents_called++;
553 num_acquire_fences = present_args.acquire_fences().size();
554 num_release_fences = present_args.release_fences().size();
555
556 last_present_args = std::move(present_args);
557 });
558
559 // Create the FlatlandConnection but don't pump the loop. No FIDL calls are
560 // completed yet.
561 on_frame_presented_event on_frame_presented = [](auto...) {};
562 flutter_runner::FlatlandConnection flatland_connection(
563 GetCurrentTestName(), TakeFlatlandHandle(), []() { FAIL(); },
564 std::move(on_frame_presented), subloop_dispatcher());
565 EXPECT_EQ(num_presents_called, 0u);
566
567 // Pump the loop. Nothing is called.
568 loop().RunUntilIdle();
569 EXPECT_EQ(num_presents_called, 0u);
570
571 // Simulate an AwaitVsync that comes before the first Present.
572 flatland_connection.AwaitVsync([](fml::TimePoint, fml::TimePoint) {});
573 loop().RunUntilIdle();
574 EXPECT_EQ(num_presents_called, 0u);
575
576 constexpr size_t kMaxFences = 16;
577
578 // We must signal these.
579 FencesPair acquire = GetFencesPair(kMaxFences + 1);
580 // Flatland will signal these.
581 FencesPair release = GetFencesPair(kMaxFences + 1);
582
583 auto fire_callback = [dispatcher = loop().dispatcher(), &flatland_connection,
584 rfd = release.fences_dup, afd = acquire.fences_dup](
585 fml::TimePoint frame_start,
586 fml::TimePoint frame_end) mutable {
587 async::PostTask(dispatcher, [&flatland_connection, rf = rfd, af = afd]() {
588 for (auto& fence : *rf) {
589 zx::event fence_dup;
590 const auto status = fence.duplicate(ZX_RIGHT_SAME_RIGHTS, &fence_dup);
591 ASSERT_EQ(status, ZX_OK);
592 flatland_connection.EnqueueReleaseFence(std::move(fence_dup));
593 }
594 for (auto& fence : *af) {
595 zx::event fence_dup;
596 const auto status = fence.duplicate(ZX_RIGHT_SAME_RIGHTS, &fence_dup);
597 ASSERT_EQ(status, ZX_OK);
598 flatland_connection.EnqueueAcquireFence(std::move(fence_dup));
599 }
600 flatland_connection.Present();
601 });
602 };
603
604 SignalAll(acquire.fences.get());
605
606 // Call Await Vsync with a callback that triggers Present and consumes the one
607 // and only present credit we start with.
608 reset_test_counters();
609 flatland_connection.AwaitVsync(fire_callback);
610
611 loop().RunUntilIdle();
612
613 EXPECT_EQ(num_presents_called, 1u);
614 EXPECT_EQ(num_acquire_fences, 16u);
615 EXPECT_EQ(num_release_fences, 0u);
616
617 // Move on to next present call. Reset all the expectations and callbacks.
618 reset_test_counters();
619 OnNextFrameBegin(1);
620 // Replenish present credits.
621 loop().RunUntilIdle();
622
623 flatland_connection.AwaitVsync([dispatcher = subloop_dispatcher(),
624 &flatland_connection](fml::TimePoint,
626 async::PostTask(dispatcher,
627 [&flatland_connection] { flatland_connection.Present(); });
628 });
629 loop().RunUntilIdle();
630
631 // Simulate Flatland signaling all release fences. Note that the set of
632 // release fences here is only the first ~15 of the fences, the rest are
633 // released indirectly via the overflow mechanism.
634 SignalAll(last_present_args.mutable_release_fences());
635
636 loop().RunUntilIdle();
637
638 // At this point all release fences from prior frame should have been released
639 // by Flatland.
640 EXPECT_EQ(num_presents_called, 1u);
641 EXPECT_EQ(num_acquire_fences, 0u);
642 EXPECT_EQ(num_release_fences, 16u);
643
644 // Prove that all release fences have been signaled. If not, this will block
645 // forever.
646 WaitAll(release.fences.get());
647}
648
649} // namespace flutter_runner::testing
void FireOnNextFrameBeginEvent(fuchsia::ui::composition::OnNextFrameBeginValues on_next_frame_begin_values)
void OnNextFrameBegin(int num_present_credits, const fml::TimePoint &presentation_time_1, const fml::TimePoint &presentation_time_2)
fidl::InterfaceHandle< fuchsia::ui::composition::Flatland > TakeFlatlandHandle()
static constexpr TimeDelta FromSeconds(int64_t seconds)
Definition time_delta.h:49
constexpr int64_t ToNanoseconds() const
Definition time_delta.h:61
constexpr TimeDelta ToEpochDelta() const
Definition time_point.h:52
static TimePoint Now()
Definition time_point.cc:49
#define FML_CHECK(condition)
Definition logging.h:104
std::string GetCurrentTestName()
Gets the name of the currently running test. This is useful in generating logs or assets based on tes...
Definition testing.cc:14
void SignalAll(std::vector< zx::event > *fences)
void WaitAll(std::vector< zx::event > *fences)
FencesPair GetFencesPair(size_t num_fences)
TEST_F(FocusDelegateTest, WatchCallbackSeries)
static constexpr size_t kMaxFences
std::function< void(fuchsia::scenic::scheduling::FramePresentedInfo)> on_frame_presented_event
static constexpr fml::TimeDelta kInitialFlatlandVsyncOffset
std::function< void()> closure
Definition closure.h:14
std::shared_ptr< std::vector< zx::event > > fences
std::shared_ptr< std::vector< zx::event > > fences_dup