Flutter Engine
The Flutter Engine
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
5#include "flutter/shell/platform/fuchsia/flutter/flatland_connection.h"
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"
18#include "flutter/fml/time/time_delta.h"
19#include "flutter/fml/time/time_point.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](
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](
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
TimeDelta ToEpochDelta() const
Definition: time_point.h:52
static TimePoint Now()
Definition: time_point.cc:49
#define FAIL(name, result)
EMSCRIPTEN_KEEPALIVE void empty()
FlKeyEvent * event
#define FML_CHECK(condition)
Definition: logging.h:85
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:15
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
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
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
int_closure create
#define EXPECT_TRUE(handle)
Definition: unit_test.h:678