Skip to main content

scene_management/
scene_manager.rs

1// Copyright 2019 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 crate::lib::{Position, Size};
6use crate::pointerinjector_config::{
7    InjectorViewportChangeFn, InjectorViewportHangingGet, InjectorViewportPublisher,
8    InjectorViewportSpec, InjectorViewportSubscriber,
9};
10use crate::{DisplayMetrics, ViewingDistance};
11use anyhow::{Context, Error, Result};
12use async_trait::async_trait;
13use async_utils::hanging_get::server as hanging_get;
14use fidl::endpoints::{Proxy, create_proxy};
15use fidl_fuchsia_accessibility_scene as a11y_scene;
16use fidl_fuchsia_math as math;
17use fidl_fuchsia_ui_app as ui_app;
18use fidl_fuchsia_ui_composition::{self as ui_comp, ContentId, TransformId};
19use fidl_fuchsia_ui_display_singleton as singleton_display;
20use fidl_fuchsia_ui_pointerinjector_configuration::{
21    SetupRequest as PointerInjectorConfigurationSetupRequest,
22    SetupRequestStream as PointerInjectorConfigurationSetupRequestStream,
23};
24use fidl_fuchsia_ui_views as ui_views;
25use flatland_frame_scheduling_lib::*;
26use fuchsia_async::{self as fasync, TimeoutExt};
27use fuchsia_scenic as scenic;
28use fuchsia_trace as trace;
29use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender, unbounded};
30use futures::channel::oneshot;
31use futures::prelude::*;
32use log::{error, info, warn};
33use math as fmath;
34use std::cell::{Cell, RefCell};
35use std::collections::VecDeque;
36use std::ffi::CStr;
37use std::process;
38use std::rc::Rc;
39use std::sync::{Arc, Weak};
40use zx;
41
42/// Presentation messages.
43pub enum PresentationMessage {
44    /// Request a present call.
45    RequestPresent,
46    // Requests a present call; also, provides a channel that will get a ping back
47    // when the next frame has been presented on screen.
48    RequestPresentWithPingback(oneshot::Sender<()>),
49}
50
51/// Unbounded sender used for presentation messages.
52pub type PresentationSender = UnboundedSender<PresentationMessage>;
53
54/// Unbounded receiver used for presentation messages.
55pub type PresentationReceiver = UnboundedReceiver<PresentationMessage>;
56
57const _CURSOR_SIZE: (u32, u32) = (18, 29);
58const CURSOR_HOTSPOT: (u32, u32) = (2, 4);
59
60// TODO(https://fxbug.dev/42158302): Remove hardcoded scale when Flatland provides
61// what is needed to determine the cursor scale factor.
62const CURSOR_SCALE_MULTIPLIER: u32 = 5;
63const CURSOR_SCALE_DIVIDER: u32 = 4;
64
65const DEFAULT_VIEW_CONNECTION_TIMEOUT: zx::MonotonicDuration =
66    zx::MonotonicDuration::from_seconds(15);
67
68// Converts a cursor size to physical pixels.
69fn physical_cursor_size(value: u32) -> u32 {
70    (CURSOR_SCALE_MULTIPLIER * value) / CURSOR_SCALE_DIVIDER
71}
72
73pub type FlatlandPtr = Arc<ui_comp::FlatlandProxy>;
74
75#[derive(Clone)]
76struct TransformContentIdPair {
77    transform_id: TransformId,
78    content_id: ContentId,
79}
80
81/// FlatlandInstance encapsulates a FIDL connection to a Flatland instance, along with some other
82/// state resulting from initializing the instance in a standard way; see FlatlandInstance::new().
83/// For example, a view is created during initialization, and so FlatlandInstance stores the
84/// corresponding ViewRef and a ParentViewportWatcher FIDL connection.
85struct FlatlandInstance {
86    flatland: FlatlandPtr,
87    view_ref: ui_views::ViewRef,
88    root_transform_id: TransformId,
89    parent_viewport_watcher: ui_comp::ParentViewportWatcherProxy,
90    focuser: ui_views::FocuserProxy,
91}
92
93impl FlatlandInstance {
94    fn new(
95        flatland: ui_comp::FlatlandProxy,
96        view_creation_token: ui_views::ViewCreationToken,
97        id_generator: &mut scenic::flatland::IdGenerator,
98    ) -> Result<FlatlandInstance, Error> {
99        let (parent_viewport_watcher, parent_viewport_watcher_request) =
100            create_proxy::<ui_comp::ParentViewportWatcherMarker>();
101
102        let (focuser, focuser_request) = create_proxy::<ui_views::FocuserMarker>();
103
104        let view_bound_protocols = ui_comp::ViewBoundProtocols {
105            view_focuser: Some(focuser_request),
106            ..Default::default()
107        };
108
109        let view_identity = ui_views::ViewIdentityOnCreation::from(scenic::ViewRefPair::new()?);
110        let view_ref = scenic::duplicate_view_ref(&view_identity.view_ref)?;
111        flatland.create_view2(
112            view_creation_token,
113            view_identity,
114            view_bound_protocols,
115            parent_viewport_watcher_request,
116        )?;
117
118        let root_transform_id = id_generator.next_transform_id();
119        flatland.create_transform(&root_transform_id)?;
120        flatland.set_root_transform(&root_transform_id)?;
121        flatland.set_hit_regions(&root_transform_id, &[])?;
122
123        Ok(FlatlandInstance {
124            flatland: Arc::new(flatland),
125            view_ref,
126            root_transform_id,
127            parent_viewport_watcher,
128            focuser,
129        })
130    }
131}
132
133fn request_present_with_pingback(
134    presentation_sender: &PresentationSender,
135) -> Result<oneshot::Receiver<()>, Error> {
136    let (sender, receiver) = oneshot::channel::<()>();
137    presentation_sender.unbounded_send(PresentationMessage::RequestPresentWithPingback(sender))?;
138    Ok(receiver)
139}
140
141async fn setup_child_view(
142    parent_flatland: &FlatlandInstance,
143    viewport_creation_token: scenic::flatland::ViewportCreationToken,
144    id_generator: &mut scenic::flatland::IdGenerator,
145    client_viewport_size: math::SizeU,
146) -> Result<ui_comp::ChildViewWatcherProxy, Error> {
147    let child_viewport_transform_id = id_generator.next_transform_id();
148    let child_viewport_content_id = id_generator.next_content_id();
149
150    let (child_view_watcher, child_view_watcher_request) =
151        create_proxy::<ui_comp::ChildViewWatcherMarker>();
152
153    {
154        let flatland = &parent_flatland.flatland;
155        flatland.create_transform(&child_viewport_transform_id)?;
156        flatland.add_child(&parent_flatland.root_transform_id, &child_viewport_transform_id)?;
157
158        let link_properties = ui_comp::ViewportProperties {
159            logical_size: Some(client_viewport_size),
160            ..Default::default()
161        };
162
163        flatland.create_viewport(
164            &child_viewport_content_id,
165            viewport_creation_token,
166            &link_properties,
167            child_view_watcher_request,
168        )?;
169        flatland.set_content(&child_viewport_transform_id, &child_viewport_content_id)?;
170    }
171
172    Ok(child_view_watcher)
173}
174
175/// SceneManager manages the platform/framework-controlled part of the global Scenic scene
176/// graph, with the fundamental goal of connecting the physical display to the product-defined user
177/// shell.  The part of the scene graph managed by the scene manager is split between three Flatland
178/// instances, which are linked by view/viewport pairs.
179//
180// The scene graph looks like this:
181//
182//         FD          FD:  FlatlandDisplay
183//         |
184//         R*          R*:  root transform of |root_flatland|,
185//         |                and also the corresponding view/view-ref (see below)
186//        / \
187//       /   \         Rc:  transform holding whatever is necessary to render the cursor
188//     Rpi    Rc
189//      |      \       Rpi: transform with viewport linking to |pointerinjector_flatland|
190//      |       (etc.)      (see docs on struct field for rationale)
191//      |
192//      P*             P*:  root transform of |pointerinjector_flatland|,
193//      |                   and also the corresponding view/view-ref (see below)
194//      |
195//      Pa             Pa:  transform with viewport linking to an external Flatland instance
196//      |                   owned by a11y manager.
197//      |
198//      A*             A*:  root transform of |a11y_flatland| (owned by a11y manager),
199//      |                   and also the corresponding view/view-ref (see below).
200//      |
201//      As             As:  transform with viewport linking to |scene_flatland|.
202//      |
203//      |
204//      S*             S*:  root transform of |scene_flatland|,
205//      |                   and also the corresponding view/view-ref (see below)
206//      |
207//      (user shell)   The session uses the SceneManager.SetRootView() FIDL API to attach the user
208//                     shell to the scene graph depicted above.
209//
210// A11y View can be disabled via `attach_a11y_view` flag. If disabled, Pa and A* is removed from the
211// scene graph.
212//
213// There is a reason why the "corresponding view/view-refs" are called out in the diagram above.
214// When registering an input device with the fuchsia.ui.pointerinjector.Registry API, the Config
215// must specify two ViewRefs, the "context" and the "target"; the former must be a strict ancestor
216// or the former (the target denotes the first eligible view to receive input; it will always be
217// the root of the focus chain).  The context ViewRef is R* and the target ViewRef is P*.  Note that
218// the possibly-inserted accessiblity view is the direct descendant of |pointerinjector_flatland|.
219// This gives the accessiblity manager the ability to give itself focus, and therefore receive all
220// input.
221pub struct SceneManager {
222    // Flatland connection between the physical display and the rest of the scene graph.
223    _display: ui_comp::FlatlandDisplayProxy,
224
225    // The size that will ultimately be assigned to the View created with the
226    // `fuchsia.session.scene.Manager` protocol.
227    client_viewport_size: math::SizeU,
228
229    // Flatland instance that connects to |display|.  Hosts a viewport which connects it to
230    // to a view in |pointerinjector_flatland|.
231    //
232    // See the above diagram of SceneManager's scene graph topology.
233    root_flatland: FlatlandInstance,
234
235    // Flatland instance that sits beneath |root_flatland| in the scene graph.  The reason that this
236    // exists is that two different ViewRefs must be provided when configuring the input pipeline to
237    // inject pointer events into Scenic via fuchsia.ui.pointerinjector.Registry; since a Flatland
238    // instance can have only a single view, we add an additional Flatland instance into the scene
239    // graph to obtain the second view (the "target" view; the "context" view is obtained from
240    // |root_flatland|).
241    //
242    // See the above diagram of SceneManager's scene graph topology.
243    _pointerinjector_flatland: FlatlandInstance,
244
245    // Flatland instance that embeds the system shell (i.e. via the SetRootView() FIDL API).  Its
246    // root view is attached to a viewport owned by the accessibility manager (via
247    // fuchsia.accessibility.scene.Provider/CreateView()).
248    scene_flatland: FlatlandInstance,
249
250    // These are the ViewRefs returned by get_pointerinjection_view_refs().  They are used to
251    // configure input-pipeline handlers for pointer events.
252    context_view_ref: ui_views::ViewRef,
253    target_view_ref: ui_views::ViewRef,
254
255    // Used to sent presentation requests for |root_flatand| and |scene_flatland|, respectively.
256    root_flatland_presentation_sender: PresentationSender,
257    _pointerinjector_flatland_presentation_sender: PresentationSender,
258    scene_flatland_presentation_sender: PresentationSender,
259
260    // Holds a pair of IDs that are used to embed the system shell inside |scene_flatland|, a
261    // TransformId identifying a transform in the scene graph, and a ContentId which identifies a
262    // a viewport that is set as the content of that transform.
263    scene_root_viewport_ids: RefCell<Option<TransformContentIdPair>>,
264
265    // Generates a sequential stream of ContentIds and TransformIds.  By guaranteeing
266    // uniqueness across all Flatland instances, we avoid potential confusion during debugging.
267    id_generator: RefCell<scenic::flatland::IdGenerator>,
268
269    // Supports callers of fuchsia.ui.pointerinjector.configuration.setup.WatchViewport(), allowing
270    // each invocation to subscribe to changes in the viewport region.
271    viewport_hanging_get: Rc<RefCell<InjectorViewportHangingGet>>,
272
273    // Used to publish viewport changes to subscribers of |viewport_hanging_get|.
274    // TODO(https://fxbug.dev/42168647): use this to publish changes to screen resolution.
275    _viewport_publisher: Rc<RefCell<InjectorViewportPublisher>>,
276
277    // Used to position the cursor.
278    cursor_transform_id: Option<TransformId>,
279
280    // Used to track cursor visibility.
281    cursor_visibility: Cell<bool>,
282
283    // Used to track the display metrics for the root scene.
284    display_metrics: DisplayMetrics,
285
286    // Used to convert between logical and physical pixels.
287    //
288    // (physical pixel) = (device_pixel_ratio) * (logical pixel)
289    device_pixel_ratio: f32,
290
291    // Lock to serialize set_root_view calls and prevent interleaving race conditions.
292    set_root_view_lock: futures::lock::Mutex<()>,
293
294    // Keep spawned tasks alive.
295    _tasks: RefCell<Vec<fasync::Task<()>>>,
296}
297
298/// A [SceneManager] manages a Scenic scene graph, and allows clients to add views to it.
299/// Each [`SceneManager`] can choose how to configure the scene, including lighting, setting the
300/// frames of added views, etc.
301///
302/// # Example
303///
304/// ```
305/// let view_provider = some_apips.connect_to_service::<ViewProviderMarker>()?;
306///
307/// let scenic = connect_to_service::<ScenicMarker>()?;
308/// let mut scene_manager = scene_management::FlatSceneManager::new(scenic).await?;
309/// scene_manager.set_root_view(viewport_token).await?;
310///
311/// ```
312#[async_trait(?Send)]
313pub trait SceneManagerTrait {
314    /// Sets the root view for the scene.
315    ///
316    /// ViewRef will be unset for Flatland views.
317    ///
318    /// Removes any previous root view, as well as all of its descendants.
319    async fn set_root_view(
320        &self,
321        viewport_creation_token: ui_views::ViewportCreationToken,
322        view_ref: Option<ui_views::ViewRef>,
323    ) -> Result<(), Error>;
324
325    /// DEPRECATED: Use ViewportToken version above.
326    /// Sets the root view for the scene.
327    ///
328    /// Removes any previous root view, as well as all of its descendants.
329    async fn set_root_view_deprecated(
330        &self,
331        view_provider: ui_app::ViewProviderProxy,
332    ) -> Result<ui_views::ViewRef, Error>;
333
334    /// Requests a new frame be presented in the scene.
335    fn present_root_view(&self);
336
337    /// Sets the position of the cursor in the current scene. If no cursor has been created it will
338    /// create one using default settings.
339    ///
340    /// # Parameters
341    /// - `position_physical_px`: A [`Position`] struct representing the cursor position, in physical
342    ///   pixels.
343    ///
344    /// # Notes
345    /// If a custom cursor has not been set using `set_cursor_image` or `set_cursor_shape` a default
346    /// cursor will be created and added to the scene.  The implementation of the `SceneManager` trait
347    /// is responsible for translating the raw input position into "pips".
348    fn set_cursor_position(&self, position_physical_px: Position);
349
350    /// Sets the visibility of the cursor in the current scene. The cursor is visible by default.
351    ///
352    /// # Parameters
353    /// - `visible`: Boolean value indicating if the cursor should be visible.
354    fn set_cursor_visibility(&self, visible: bool);
355
356    // Supports the implementation of fuchsia.ui.pointerinjector.configurator.Setup.GetViewRefs()
357    fn get_pointerinjection_view_refs(&self) -> (ui_views::ViewRef, ui_views::ViewRef);
358
359    /// Input pipeline handlers such as TouchInjectorHandler require the display size in order to be
360    /// instantiated.  This method exposes that information.
361    fn get_pointerinjection_display_size(&self) -> crate::lib::Size;
362
363    // Support the hanging get implementation of
364    // fuchsia.ui.pointerinjector.configurator.Setup.WatchViewport().
365    fn get_pointerinjector_viewport_watcher_subscription(&self) -> InjectorViewportSubscriber;
366
367    fn get_display_metrics(&self) -> &DisplayMetrics;
368
369    /// Store a task to keep it alive for the lifetime of the SceneManager.
370    fn manage_task(&self, task: fasync::Task<()>);
371}
372
373#[async_trait(?Send)]
374impl SceneManagerTrait for SceneManager {
375    /// Sets the root view for the scene.
376    ///
377    /// ViewRef will be unset for Flatland views.
378    ///
379    /// Removes any previous root view, as well as all of its descendants.
380    async fn set_root_view(
381        &self,
382        viewport_creation_token: ui_views::ViewportCreationToken,
383        _view_ref: Option<ui_views::ViewRef>,
384    ) -> Result<(), Error> {
385        let _guard = self.set_root_view_lock.lock().await;
386        self.set_root_view_internal(viewport_creation_token).await.map(|_view_ref| {})
387    }
388
389    /// DEPRECATED: Use ViewportToken version above.
390    /// Sets the root view for the scene.
391    ///
392    /// Removes any previous root view, as well as all of its descendants.
393    async fn set_root_view_deprecated(
394        &self,
395        view_provider: ui_app::ViewProviderProxy,
396    ) -> Result<ui_views::ViewRef, Error> {
397        let _guard = self.set_root_view_lock.lock().await;
398        let link_token_pair = scenic::flatland::ViewCreationTokenPair::new()?;
399
400        // Use view provider to initiate creation of the view which will be connected to the
401        // viewport that we create below.
402        view_provider.create_view2(ui_app::CreateView2Args {
403            view_creation_token: Some(link_token_pair.view_creation_token),
404            ..Default::default()
405        })?;
406
407        self.set_root_view_internal(link_token_pair.viewport_creation_token).await
408    }
409
410    /// Requests a new frame be presented in the scene.
411    fn present_root_view(&self) {
412        self.root_flatland_presentation_sender
413            .unbounded_send(PresentationMessage::RequestPresent)
414            .expect("send failed");
415    }
416
417    // Supports the implementation of fuchsia.ui.pointerinjector.configurator.Setup.GetViewRefs()
418    fn get_pointerinjection_view_refs(&self) -> (ui_views::ViewRef, ui_views::ViewRef) {
419        (
420            scenic::duplicate_view_ref(&self.context_view_ref).expect("failed to copy ViewRef"),
421            scenic::duplicate_view_ref(&self.target_view_ref).expect("failed to copy ViewRef"),
422        )
423    }
424
425    /// Sets the position of the cursor in the current scene. If no cursor has been created it will
426    /// create one using default settings.
427    ///
428    /// # Parameters
429    /// - `position_physical_px`: A [`Position`] struct representing the cursor position, in physical
430    ///   pixels.
431    ///
432    /// # Notes
433    /// If a custom cursor has not been set using `set_cursor_image` or `set_cursor_shape` a default
434    /// cursor will be created and added to the scene.  The implementation of the `SceneManager` trait
435    /// is responsible for translating the raw input position into "pips".
436    fn set_cursor_position(&self, position_physical_px: Position) {
437        if let Some(cursor_transform_id) = self.cursor_transform_id {
438            let position_logical = position_physical_px / self.device_pixel_ratio;
439            let x =
440                position_logical.x.round() as i32 - physical_cursor_size(CURSOR_HOTSPOT.0) as i32;
441            let y =
442                position_logical.y.round() as i32 - physical_cursor_size(CURSOR_HOTSPOT.1) as i32;
443            self.root_flatland
444                .flatland
445                .set_translation(&cursor_transform_id, &fmath::Vec_ { x, y })
446                .expect("fidl error");
447            self.root_flatland_presentation_sender
448                .unbounded_send(PresentationMessage::RequestPresent)
449                .expect("send failed");
450        }
451    }
452
453    /// Sets the visibility of the cursor in the current scene. The cursor is visible by default.
454    ///
455    /// # Parameters
456    /// - `visible`: Boolean value indicating if the cursor should be visible.
457    fn set_cursor_visibility(&self, visible: bool) {
458        if let Some(cursor_transform_id) = self.cursor_transform_id {
459            if self.cursor_visibility.get() != visible {
460                self.cursor_visibility.set(visible);
461                let flatland = &self.root_flatland.flatland;
462                if visible {
463                    flatland
464                        .add_child(&self.root_flatland.root_transform_id, &cursor_transform_id)
465                        .expect("failed to add cursor to scene");
466                } else {
467                    flatland
468                        .remove_child(&self.root_flatland.root_transform_id, &cursor_transform_id)
469                        .expect("failed to remove cursor from scene");
470                }
471                self.root_flatland_presentation_sender
472                    .unbounded_send(PresentationMessage::RequestPresent)
473                    .expect("send failed");
474            }
475        }
476    }
477
478    /// Input pipeline handlers such as TouchInjectorHandler require the display size in order to be
479    /// instantiated.  This method exposes that information.
480    fn get_pointerinjection_display_size(&self) -> Size {
481        // Input pipeline expects size in physical pixels.
482        self.display_metrics.size_in_pixels()
483    }
484
485    // Support the hanging get implementation of
486    // fuchsia.ui.pointerinjector.configurator.Setup.WatchViewport().
487    fn get_pointerinjector_viewport_watcher_subscription(&self) -> InjectorViewportSubscriber {
488        self.viewport_hanging_get.borrow_mut().new_subscriber()
489    }
490
491    fn get_display_metrics(&self) -> &DisplayMetrics {
492        &self.display_metrics
493    }
494
495    fn manage_task(&self, task: fasync::Task<()>) {
496        self._tasks.borrow_mut().push(task);
497    }
498}
499
500const ROOT_VIEW_DEBUG_NAME: &str = "SceneManager Display";
501const POINTER_INJECTOR_DEBUG_NAME: &str = "SceneManager PointerInjector";
502const SCENE_DEBUG_NAME: &str = "SceneManager Scene";
503const ROOT_VIEW_PRESENT_TRACING_NAME: &CStr = c"Flatland::PerAppPresent[SceneManager Display]";
504const POINTER_INJECTOR_PRESENT_TRACING_NAME: &CStr =
505    c"Flatland::PerAppPresent[SceneManager PointerInjector]";
506const SCENE_TRACING_NAME: &CStr = c"Flatland::PerAppPresent[SceneManager Scene]";
507
508impl SceneManager {
509    #[allow(clippy::vec_init_then_push, reason = "mass allow for https://fxbug.dev/381896734")]
510    pub async fn new(
511        display: ui_comp::FlatlandDisplayProxy,
512        singleton_display_info: singleton_display::InfoProxy,
513        root_flatland: ui_comp::FlatlandProxy,
514        pointerinjector_flatland: ui_comp::FlatlandProxy,
515        scene_flatland: ui_comp::FlatlandProxy,
516        a11y_view_provider: Option<a11y_scene::ProviderProxy>,
517        display_rotation: u64,
518        display_pixel_density: Option<f32>,
519        viewing_distance: Option<ViewingDistance>,
520    ) -> Result<Self, Error> {
521        // If scenic closes, all the Scenic connections become invalid. This task exits the
522        // process in response.
523        let mut tasks = vec![start_exit_on_scenic_closed_task(display.clone())];
524
525        let mut id_generator = scenic::flatland::IdGenerator::new();
526
527        // Generate unique transform/content IDs that will be used to create the sub-scenegraphs
528        // in the Flatland instances managed by SceneManager.
529        let pointerinjector_viewport_transform_id = id_generator.next_transform_id();
530        let pointerinjector_viewport_content_id = id_generator.next_content_id();
531
532        root_flatland.set_debug_name(ROOT_VIEW_DEBUG_NAME)?;
533        pointerinjector_flatland.set_debug_name(POINTER_INJECTOR_DEBUG_NAME)?;
534        scene_flatland.set_debug_name(SCENE_DEBUG_NAME)?;
535
536        let root_view_creation_pair = scenic::flatland::ViewCreationTokenPair::new()?;
537        let root_flatland = FlatlandInstance::new(
538            root_flatland,
539            root_view_creation_pair.view_creation_token,
540            &mut id_generator,
541        )?;
542
543        let pointerinjector_view_creation_pair = scenic::flatland::ViewCreationTokenPair::new()?;
544        let pointerinjector_flatland = FlatlandInstance::new(
545            pointerinjector_flatland,
546            pointerinjector_view_creation_pair.view_creation_token,
547            &mut id_generator,
548        )?;
549
550        let scene_view_creation_pair = scenic::flatland::ViewCreationTokenPair::new()?;
551        let scene_flatland = FlatlandInstance::new(
552            scene_flatland,
553            scene_view_creation_pair.view_creation_token,
554            &mut id_generator,
555        )?;
556
557        // Create display metrics, and set the device pixel ratio of FlatlandDisplay.
558        let info = singleton_display_info.get_metrics().await?;
559        let extent_in_px =
560            info.extent_in_px.ok_or_else(|| anyhow::anyhow!("Did not receive display size"))?;
561        let display_metrics = DisplayMetrics::new(
562            Size { width: extent_in_px.width as f32, height: extent_in_px.height as f32 },
563            display_pixel_density,
564            viewing_distance,
565            None,
566        );
567
568        display.set_device_pixel_ratio(&fmath::VecF {
569            x: display_metrics.pixels_per_pip(),
570            y: display_metrics.pixels_per_pip(),
571        })?;
572
573        // Connect the FlatlandDisplay to |root_flatland|'s view.
574        {
575            // We don't need to watch the child view, since we also own it. So, we discard the
576            // client end of the the channel pair.
577            let (_, child_view_watcher_request) = create_proxy::<ui_comp::ChildViewWatcherMarker>();
578
579            display.set_content(
580                root_view_creation_pair.viewport_creation_token,
581                child_view_watcher_request,
582            )?;
583        }
584
585        // Obtain layout info from FlatlandDisplay. Logical size may be different from the
586        // display size if DPR is applied.
587        let layout_info = root_flatland.parent_viewport_watcher.get_layout().await?;
588        let root_viewport_size = layout_info
589            .logical_size
590            .ok_or_else(|| anyhow::anyhow!("Did not receive layout info from the display"))?;
591
592        let (
593            display_rotation_enum,
594            injector_viewport_translation,
595            flip_injector_viewport_dimensions,
596        ) = match display_rotation % 360 {
597            0 => Ok((ui_comp::Orientation::Ccw0Degrees, math::Vec_ { x: 0, y: 0 }, false)),
598            90 => Ok((
599                // Rotation is specified in the opposite winding direction to the
600                // specified |display_rotation| value. Winding in the opposite direction is equal
601                // to -90 degrees, which is equivalent to 270.
602                ui_comp::Orientation::Ccw270Degrees,
603                math::Vec_ { x: root_viewport_size.width as i32, y: 0 },
604                true,
605            )),
606            180 => Ok((
607                ui_comp::Orientation::Ccw180Degrees,
608                math::Vec_ {
609                    x: root_viewport_size.width as i32,
610                    y: root_viewport_size.height as i32,
611                },
612                false,
613            )),
614            270 => Ok((
615                // Rotation is specified in the opposite winding direction to the
616                // specified |display_rotation| value. Winding in the opposite direction is equal
617                // to -270 degrees, which is equivalent to 90.
618                ui_comp::Orientation::Ccw90Degrees,
619                math::Vec_ { x: 0, y: root_viewport_size.height as i32 },
620                true,
621            )),
622            _ => Err(anyhow::anyhow!("Invalid display rotation; must be {{0,90,180,270}}")),
623        }?;
624        let client_viewport_size = match flip_injector_viewport_dimensions {
625            true => {
626                math::SizeU { width: root_viewport_size.height, height: root_viewport_size.width }
627            }
628            false => {
629                math::SizeU { width: root_viewport_size.width, height: root_viewport_size.height }
630            }
631        };
632
633        // Create the pointerinjector view and embed it as a child of the root view.
634        {
635            let flatland = &root_flatland.flatland;
636            flatland.create_transform(&pointerinjector_viewport_transform_id)?;
637            flatland.add_child(
638                &root_flatland.root_transform_id,
639                &pointerinjector_viewport_transform_id,
640            )?;
641            flatland
642                .set_orientation(&pointerinjector_viewport_transform_id, display_rotation_enum)?;
643            flatland.set_translation(
644                &pointerinjector_viewport_transform_id,
645                &injector_viewport_translation,
646            )?;
647
648            let link_properties = ui_comp::ViewportProperties {
649                logical_size: Some(client_viewport_size),
650                ..Default::default()
651            };
652
653            let (_, child_view_watcher_request) = create_proxy::<ui_comp::ChildViewWatcherMarker>();
654
655            flatland.create_viewport(
656                &pointerinjector_viewport_content_id,
657                pointerinjector_view_creation_pair.viewport_creation_token,
658                &link_properties,
659                child_view_watcher_request,
660            )?;
661            flatland.set_content(
662                &pointerinjector_viewport_transform_id,
663                &pointerinjector_viewport_content_id,
664            )?;
665        }
666
667        let mut a11y_view_watcher: Option<ui_comp::ChildViewWatcherProxy> = None;
668        match a11y_view_provider {
669            Some(a11y_view_provider) => {
670                let a11y_view_creation_pair = scenic::flatland::ViewCreationTokenPair::new()?;
671
672                // Bridge the pointerinjector and a11y Flatland instances.
673                a11y_view_watcher = Some(
674                    setup_child_view(
675                        &pointerinjector_flatland,
676                        a11y_view_creation_pair.viewport_creation_token,
677                        &mut id_generator,
678                        client_viewport_size,
679                    )
680                    .await?,
681                );
682
683                // Request for the a11y manager to create its view.
684                a11y_view_provider.create_view(
685                    a11y_view_creation_pair.view_creation_token,
686                    scene_view_creation_pair.viewport_creation_token,
687                )?;
688            }
689            None => {
690                // Bridge the pointerinjector and scene Flatland instances. This skips the A11y View.
691                let _ = setup_child_view(
692                    &pointerinjector_flatland,
693                    scene_view_creation_pair.viewport_creation_token,
694                    &mut id_generator,
695                    client_viewport_size,
696                )
697                .await?;
698            }
699        }
700
701        // Start Present() loops for both Flatland instances, and request that both be presented.
702        let (root_flatland_presentation_sender, root_receiver) = unbounded();
703        tasks.push(start_flatland_presentation_loop(
704            root_receiver,
705            Arc::downgrade(&root_flatland.flatland),
706            ROOT_VIEW_DEBUG_NAME.to_string(),
707        ));
708        let (pointerinjector_flatland_presentation_sender, pointerinjector_receiver) = unbounded();
709        tasks.push(start_flatland_presentation_loop(
710            pointerinjector_receiver,
711            Arc::downgrade(&pointerinjector_flatland.flatland),
712            POINTER_INJECTOR_DEBUG_NAME.to_string(),
713        ));
714        let (scene_flatland_presentation_sender, scene_receiver) = unbounded();
715        tasks.push(start_flatland_presentation_loop(
716            scene_receiver,
717            Arc::downgrade(&scene_flatland.flatland),
718            SCENE_DEBUG_NAME.to_string(),
719        ));
720
721        let mut pingback_channels = Vec::new();
722        pingback_channels.push(request_present_with_pingback(&root_flatland_presentation_sender)?);
723        pingback_channels
724            .push(request_present_with_pingback(&pointerinjector_flatland_presentation_sender)?);
725        pingback_channels.push(request_present_with_pingback(&scene_flatland_presentation_sender)?);
726
727        if let Some(a11y_view_watcher) = a11y_view_watcher {
728            // Wait for a11y view to attach before proceeding.
729            let a11y_view_status = a11y_view_watcher.get_status().await?;
730            match a11y_view_status {
731                ui_comp::ChildViewStatus::ContentHasPresented => {}
732            }
733        }
734
735        // Read device pixel ratio from layout info.
736        let device_pixel_ratio = display_metrics.pixels_per_pip();
737        let viewport_hanging_get: Rc<RefCell<InjectorViewportHangingGet>> =
738            create_viewport_hanging_get({
739                InjectorViewportSpec {
740                    width: display_metrics.width_in_pixels() as f32,
741                    height: display_metrics.height_in_pixels() as f32,
742                    scale: 1. / device_pixel_ratio,
743                    x_offset: 0.,
744                    y_offset: 0.,
745                }
746            });
747        let viewport_publisher =
748            Rc::new(RefCell::new(viewport_hanging_get.borrow_mut().new_publisher()));
749
750        let context_view_ref = scenic::duplicate_view_ref(&root_flatland.view_ref)?;
751        let target_view_ref = scenic::duplicate_view_ref(&pointerinjector_flatland.view_ref)?;
752
753        // Wait for all pingbacks to ensure the scene is fully set up before returning.
754        for receiver in pingback_channels {
755            _ = receiver.await;
756        }
757
758        Ok(SceneManager {
759            _display: display,
760            client_viewport_size,
761            root_flatland,
762            _pointerinjector_flatland: pointerinjector_flatland,
763            scene_flatland,
764            context_view_ref,
765            target_view_ref,
766            root_flatland_presentation_sender,
767            _pointerinjector_flatland_presentation_sender:
768                pointerinjector_flatland_presentation_sender,
769            scene_flatland_presentation_sender,
770            scene_root_viewport_ids: RefCell::new(None),
771            id_generator: RefCell::new(id_generator),
772            viewport_hanging_get,
773            _viewport_publisher: viewport_publisher,
774            cursor_transform_id: None,
775            cursor_visibility: Cell::new(true),
776            display_metrics,
777            device_pixel_ratio,
778            set_root_view_lock: futures::lock::Mutex::new(()),
779            _tasks: RefCell::new(tasks),
780        })
781    }
782
783    async fn set_root_view_internal(
784        &self,
785        viewport_creation_token: ui_views::ViewportCreationToken,
786    ) -> Result<ui_views::ViewRef> {
787        // Remove any existing viewport.
788        {
789            let mut scene_root_viewport_ids = self.scene_root_viewport_ids.borrow_mut();
790            if let Some(ids) = &*scene_root_viewport_ids {
791                let flatland = &self.scene_flatland.flatland;
792                flatland
793                    .set_content(&ids.transform_id, &ContentId { value: 0 })
794                    .context("could not set content")?;
795                flatland.remove_child(&self.scene_flatland.root_transform_id, &ids.transform_id)?;
796                flatland
797                    .release_transform(&ids.transform_id)
798                    .context("could not release transform")?;
799                let _ = flatland.release_viewport(&ids.content_id);
800            }
801            *scene_root_viewport_ids = None;
802        }
803
804        // Create new viewport.
805        let ids = {
806            let mut id_generator = self.id_generator.borrow_mut();
807            TransformContentIdPair {
808                transform_id: id_generator.next_transform_id(),
809                content_id: id_generator.next_content_id(),
810            }
811        };
812        let (child_view_watcher, child_view_watcher_request) =
813            create_proxy::<ui_comp::ChildViewWatcherMarker>();
814        {
815            let flatland = &self.scene_flatland.flatland;
816            let viewport_properties = ui_comp::ViewportProperties {
817                logical_size: Some(self.client_viewport_size),
818                ..Default::default()
819            };
820            flatland.create_viewport(
821                &ids.content_id,
822                viewport_creation_token,
823                &viewport_properties,
824                child_view_watcher_request,
825            )?;
826            flatland.create_transform(&ids.transform_id).context("could not create transform")?;
827            flatland.add_child(&self.scene_flatland.root_transform_id, &ids.transform_id)?;
828            flatland
829                .set_content(&ids.transform_id, &ids.content_id)
830                .context("could not set content #2")?;
831        }
832        *self.scene_root_viewport_ids.borrow_mut() = Some(ids);
833
834        // Present the previous scene graph mutations.  This MUST be done before awaiting the result
835        // of get_view_ref() below, because otherwise the view won't become attached to the global
836        // scene graph topology, and the awaited ViewRef will never come.
837        let mut pingback_channels = Vec::new();
838        pingback_channels.push(
839            request_present_with_pingback(&self.scene_flatland_presentation_sender)
840                .context("could not request present with pingback")?,
841        );
842
843        let _child_status = child_view_watcher
844            .get_status()
845            .on_timeout(fasync::MonotonicInstant::after(DEFAULT_VIEW_CONNECTION_TIMEOUT), || {
846                make_timeout_error("fuchsia.ui.composition.ChildViewWatcher")
847            })
848            .await
849            .context("could not call get_status")?;
850        let child_view_ref = child_view_watcher
851            .get_view_ref()
852            .on_timeout(fasync::MonotonicInstant::after(DEFAULT_VIEW_CONNECTION_TIMEOUT), || {
853                make_timeout_error("fuchsia.ui.composition.ChildViewWatcher")
854            })
855            .await
856            .context("could not get view_ref")?;
857        let child_view_ref_copy =
858            scenic::duplicate_view_ref(&child_view_ref).context("could not duplicate view_ref")?;
859
860        let request_focus_result = self
861            .root_flatland
862            .focuser
863            .request_focus(child_view_ref)
864            .on_timeout(fasync::MonotonicInstant::after(DEFAULT_VIEW_CONNECTION_TIMEOUT), || {
865                make_timeout_error("fuchsia.ui.views.Focuser")
866            })
867            .await;
868        match request_focus_result {
869            Err(e) => warn!("Request focus failed with err: {}", e),
870            Ok(Err(value)) => warn!("Request focus failed with err: {:?}", value),
871            Ok(_) => {}
872        }
873        pingback_channels.push(
874            request_present_with_pingback(&self.root_flatland_presentation_sender)
875                .context("could not request present with pingback #2")?,
876        );
877
878        // Wait for all pingbacks to ensure the scene is fully set up before returning.
879        for receiver in pingback_channels {
880            _ = receiver.await;
881        }
882
883        Ok(child_view_ref_copy)
884    }
885}
886
887fn make_timeout_error<T>(protocol_name: &'static str) -> Result<T, fidl::Error> {
888    Err(fidl::Error::ClientChannelClosed { epitaph: fidl::Epitaph::PeerClosed, protocol_name })
889}
890
891pub fn create_viewport_hanging_get(
892    initial_spec: InjectorViewportSpec,
893) -> Rc<RefCell<InjectorViewportHangingGet>> {
894    let notify_fn: InjectorViewportChangeFn = Box::new(|viewport_spec, responder| {
895        if let Err(fidl_error) = responder.send(&(*viewport_spec).into()) {
896            info!("Viewport hanging get notification, FIDL error: {}", fidl_error);
897        }
898        // TODO(https://fxbug.dev/42168817): the HangingGet docs don't explain what value to return.
899        true
900    });
901
902    Rc::new(RefCell::new(hanging_get::HangingGet::new(initial_spec, notify_fn)))
903}
904
905pub fn start_exit_on_scenic_closed_task(
906    flatland_proxy: ui_comp::FlatlandDisplayProxy,
907) -> fasync::Task<()> {
908    fasync::Task::local(async move {
909        let _ = flatland_proxy.on_closed().await;
910        info!("Scenic died, closing SceneManager too.");
911        process::exit(1);
912    })
913}
914
915pub fn start_flatland_presentation_loop(
916    mut receiver: PresentationReceiver,
917    weak_flatland: Weak<ui_comp::FlatlandProxy>,
918    debug_name: String,
919) -> fasync::Task<()> {
920    fasync::Task::local(async move {
921        let mut present_count = 0;
922        let scheduler = ThroughputScheduler::new();
923        let mut flatland_event_stream = {
924            if let Some(flatland) = weak_flatland.upgrade() {
925                flatland.take_event_stream()
926            } else {
927                warn!(
928                    "Failed to upgrade Flatand weak ref; exiting presentation loop for {debug_name}"
929                );
930                return;
931            }
932        };
933
934        let mut channels_awaiting_pingback = VecDeque::from([Vec::new()]);
935
936        loop {
937            futures::select! {
938                    message = receiver.next() => {
939                        match message {
940                            Some(PresentationMessage::RequestPresent) => {
941                                scheduler.request_present();
942                            }
943                            Some(PresentationMessage::RequestPresentWithPingback(channel)) => {
944                                channels_awaiting_pingback.back_mut().unwrap().push(channel);
945                                scheduler.request_present();
946                            }
947                            None => {}
948                        }
949                    }
950                    flatland_event = flatland_event_stream.next() => {
951                        match flatland_event {
952                            Some(Ok(ui_comp::FlatlandEvent::OnNextFrameBegin{ values })) => {
953                                trace::duration!("scene_manager", "SceneManager::OnNextFrameBegin",
954                                                 "debug_name" => &*debug_name);
955                                let credits = values
956                                              .additional_present_credits
957                                              .expect("Present credits must exist");
958                                let infos = values
959                                    .future_presentation_infos
960                                    .expect("Future presentation infos must exist")
961                                    .iter()
962                                    .map(
963                                    |x| PresentationInfo{
964                                        latch_point: zx::MonotonicInstant::from_nanos(x.latch_point.unwrap()),
965                                        presentation_time: zx::MonotonicInstant::from_nanos(
966                                                            x.presentation_time.unwrap())
967                                    })
968                                    .collect();
969                                scheduler.on_next_frame_begin(credits, infos);
970                            }
971                            Some(Ok(ui_comp::FlatlandEvent::OnFramePresented{ frame_presented_info })) => {
972                                trace::duration!("scene_manager", "SceneManager::OnFramePresented",
973                                                 "debug_name" => &*debug_name);
974                                let actual_presentation_time =
975                                    zx::MonotonicInstant::from_nanos(frame_presented_info.actual_presentation_time);
976                                let presented_infos: Vec<PresentedInfo> =
977                                    frame_presented_info.presentation_infos
978                                    .into_iter()
979                                    .map(|x| x.into())
980                                    .collect();
981
982                                // Pingbacks for presented updates. For each presented frame, drain all
983                                // of the corresponding pingback channels
984                                for _ in 0..presented_infos.len() {
985                                    for channel in channels_awaiting_pingback.pop_back().unwrap() {
986                                        _ = channel.send(());
987                                    }
988                                }
989
990                                scheduler.on_frame_presented(actual_presentation_time, presented_infos);
991                            }
992                            Some(Ok(ui_comp::FlatlandEvent::OnError{ error })) => {
993                                error!(
994                                    "Received FlatlandError code: {}; exiting listener loop for {debug_name}",
995                                    error.into_primitive()
996                                );
997                                return;
998                            }
999                            _ => {}
1000                        }
1001                    }
1002                    present_parameters = scheduler.wait_to_update().fuse() => {
1003                        trace::duration!("scene_manager", "SceneManager::Present",
1004                                         "debug_name" => &*debug_name);
1005
1006                        match debug_name.as_str() {
1007                            ROOT_VIEW_DEBUG_NAME => {
1008                                trace::flow_begin!("gfx", ROOT_VIEW_PRESENT_TRACING_NAME, present_count.into());
1009                            }
1010                            POINTER_INJECTOR_DEBUG_NAME => {
1011                                trace::flow_begin!("gfx", POINTER_INJECTOR_PRESENT_TRACING_NAME, present_count.into());
1012                            }
1013                            SCENE_DEBUG_NAME => {
1014                                trace::flow_begin!("gfx", SCENE_TRACING_NAME, present_count.into());
1015                            }
1016                            _ => {
1017                                warn!("SceneManager::Present with unknown debug_name {:?}", debug_name);
1018                            }
1019                        }
1020                        present_count += 1;
1021                        channels_awaiting_pingback.push_front(Vec::new());
1022                        if let Some(flatland) = weak_flatland.upgrade() {
1023                            flatland
1024                                .present(present_parameters.into())
1025                                .expect("Present failed for {debug_name}");
1026                        } else {
1027                            warn!(
1028                                "Failed to upgrade Flatand weak ref; exiting listener loop for {debug_name}"
1029                            );
1030                            return;
1031                        }
1032                    }
1033            }
1034        }
1035    })
1036}
1037
1038pub fn handle_pointer_injector_configuration_setup_request_stream(
1039    mut request_stream: PointerInjectorConfigurationSetupRequestStream,
1040    scene_manager: Rc<dyn SceneManagerTrait>,
1041) -> fasync::Task<()> {
1042    fasync::Task::local(async move {
1043        let subscriber = scene_manager.get_pointerinjector_viewport_watcher_subscription();
1044
1045        loop {
1046            let request = request_stream.try_next().await;
1047            match request {
1048                Ok(Some(PointerInjectorConfigurationSetupRequest::GetViewRefs { responder })) => {
1049                    let (context_view_ref, target_view_ref) =
1050                        scene_manager.get_pointerinjection_view_refs();
1051                    if let Err(e) = responder.send(context_view_ref, target_view_ref) {
1052                        warn!("Failed to send GetViewRefs() response: {}", e);
1053                    }
1054                }
1055                Ok(Some(PointerInjectorConfigurationSetupRequest::WatchViewport { responder })) => {
1056                    if let Err(e) = subscriber.register(responder) {
1057                        warn!("Failed to register WatchViewport() subscriber: {}", e);
1058                    }
1059                }
1060                Ok(None) => {
1061                    return;
1062                }
1063                Err(e) => {
1064                    error!("Error obtaining SetupRequest: {}", e);
1065                    return;
1066                }
1067            }
1068        }
1069    })
1070}