Skip to main content

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