ui_puppet_lib/
presentation_loop.rs

1// Copyright 2022 The Fuchsia 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
5use flatland_frame_scheduling_lib::*;
6use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
7use futures::channel::oneshot;
8use futures::prelude::*;
9use log::warn;
10use std::rc::Weak;
11use {fidl_fuchsia_ui_composition as ui_comp, fuchsia_async as fasync};
12
13/// Unbounded sender used for presentation messages.
14pub type PresentationSender = UnboundedSender<oneshot::Sender<()>>;
15
16/// Unbounded receiver used for presentation messages.
17pub type PresentationReceiver = UnboundedReceiver<oneshot::Sender<()>>;
18
19pub fn start_flatland_presentation_loop(
20    mut receiver: PresentationReceiver,
21    weak_flatland: Weak<ui_comp::FlatlandProxy>,
22) {
23    fasync::Task::local(async move {
24        let scheduler = ThroughputScheduler::new();
25        let mut flatland_event_stream = {
26            if let Some(flatland) = weak_flatland.upgrade() {
27                flatland.take_event_stream()
28            } else {
29                panic!(
30                    "failed to upgrade Flatand weak ref"
31                );
32            }
33        };
34
35        let mut pingback_channel: Option<oneshot::Sender<()>> = None;
36
37        loop {
38            futures::select! {
39                message = receiver.next() => {
40                    match message {
41                        Some(channel) => {
42                            assert!(pingback_channel.is_none());
43                            pingback_channel = Some(channel);
44                            scheduler.request_present();
45                        }
46                        None => {}
47                    }
48                }
49                flatland_event = flatland_event_stream.next() => {
50                    match flatland_event {
51                        Some(Ok(ui_comp::FlatlandEvent::OnNextFrameBegin{ values })) => {
52                            let credits = values
53                                          .additional_present_credits
54                                          .expect("Present credits must exist");
55                            let infos = values
56                                .future_presentation_infos
57                                .expect("Future presentation infos must exist")
58                                .iter()
59                                .map(
60                                |x| PresentationInfo{
61                                    latch_point: zx::MonotonicInstant::from_nanos(x.latch_point.unwrap()),
62                                    presentation_time: zx::MonotonicInstant::from_nanos(
63                                                        x.presentation_time.unwrap())
64                                })
65                                .collect();
66                            scheduler.on_next_frame_begin(credits, infos);
67                        }
68                        Some(Ok(ui_comp::FlatlandEvent::OnFramePresented{ frame_presented_info })) => {
69                            let actual_presentation_time =
70                                zx::MonotonicInstant::from_nanos(frame_presented_info.actual_presentation_time);
71                            let presented_infos: Vec<PresentedInfo> =
72                                frame_presented_info.presentation_infos
73                                .into_iter()
74                                .map(|x| x.into())
75                                .collect();
76
77                            if let Some(channel) = pingback_channel.take() {
78                                _ = channel.send(());
79                            }
80
81                            scheduler.on_frame_presented(actual_presentation_time, presented_infos);
82                        }
83                        Some(Ok(ui_comp::FlatlandEvent::OnError{ error })) => {
84                            panic!(
85                                "Received FlatlandError code: {}",
86                                error.into_primitive()
87                            );
88                        }
89                        _ => {
90                            warn!(
91                                "Flatland event stream closed; exiting. This message may be expected during test teardown");
92                                return;
93                        }
94                    }
95                }
96                present_parameters = scheduler.wait_to_update().fuse() => {
97                    if let Some(flatland) = weak_flatland.upgrade() {
98                        flatland
99                            .present(present_parameters.into())
100                            .expect("Present failed");
101                    } else {
102                        warn!(
103                            "Failed to upgrade Flatand weak ref; exiting listener loop"
104                        );
105                        return;
106                    }
107            }
108        }
109    }})
110    .detach()
111}