Skip to main content

carnelian/view/strategies/
display_direct.rs

1// Copyright 2021 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::app::strategies::framebuffer::{CoordinatorProxyPtr, DisplayId};
6use crate::app::{Config, MessageInternal};
7use crate::drawing::DisplayRotation;
8use crate::render::generic::{self, Backend};
9use crate::render::{Context as RenderContext, ContextInner};
10use crate::view::strategies::base::{ViewStrategy, ViewStrategyPtr};
11use crate::view::{
12    DisplayInfo, UserInputMessage, ViewAssistantContext, ViewAssistantPtr, ViewDetails,
13};
14use crate::{IntPoint, IntSize, Size, ViewKey, input};
15use anyhow::{Context, Error, bail, ensure};
16use async_trait::async_trait;
17use display_utils::{
18    BufferCollectionId, EventId, INVALID_LAYER_ID, ImageId as DisplayImageId, LayerId, PixelFormat,
19};
20use euclid::size2;
21use fidl_fuchsia_hardware_display::{
22    ConfigStamp, CoordinatorCommitConfigRequest, CoordinatorListenerRequest, CoordinatorProxy,
23    INVALID_CONFIG_STAMP_VALUE,
24};
25use fidl_fuchsia_hardware_display_types::{INVALID_DISP_ID, ImageBufferUsage, ImageMetadata};
26use fuchsia_async::{self as fasync};
27use fuchsia_framebuffer::sysmem::BufferCollectionAllocator;
28use fuchsia_framebuffer::{FrameSet, FrameUsage, ImageId};
29use fuchsia_trace::{duration, instant};
30use futures::channel::mpsc::UnboundedSender;
31use std::collections::{BTreeMap, BTreeSet, VecDeque};
32use std::sync::atomic::{AtomicU64, Ordering};
33use zx::{Event, MonotonicDuration, MonotonicInstant, Status};
34
35type WaitEvents = BTreeMap<ImageId, (Event, EventId)>;
36
37struct BusyImage {
38    stamp: ConfigStamp,
39    view_key: ViewKey,
40    image_id: DisplayImageId,
41    collection_id: BufferCollectionId,
42}
43
44#[derive(Default)]
45struct CollectionIdGenerator {}
46
47impl Iterator for CollectionIdGenerator {
48    type Item = BufferCollectionId;
49
50    fn next(&mut self) -> Option<BufferCollectionId> {
51        static NEXT_ID_VALUE: AtomicU64 = AtomicU64::new(100);
52        // NEXT_ID_VALUE only increments so it only requires atomicity, and we
53        // can use Relaxed order.
54        let value = NEXT_ID_VALUE.fetch_add(1, Ordering::Relaxed);
55        // fetch_add wraps on overflow, which we'll use as a signal
56        // that this generator is out of ids.
57        if value == 0 { None } else { Some(BufferCollectionId(value)) }
58    }
59}
60fn next_collection_id() -> BufferCollectionId {
61    CollectionIdGenerator::default().next().expect("collection_id")
62}
63
64#[derive(Default)]
65struct ImageIdGenerator {}
66
67impl Iterator for ImageIdGenerator {
68    type Item = u64;
69
70    fn next(&mut self) -> Option<u64> {
71        static NEXT_ID: AtomicU64 = AtomicU64::new(1);
72        // NEXT_ID only increments so it only requires atomicity, and we can
73        // use Relaxed order.
74        let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
75        // fetch_add wraps on overflow, which we'll use as a signal
76        // that this generator is out of ids.
77        if id == 0 { None } else { Some(id) }
78    }
79}
80fn next_image_id() -> u64 {
81    ImageIdGenerator::default().next().expect("image_id")
82}
83
84#[derive(Default)]
85struct LayerIdGenerator {}
86
87impl Iterator for LayerIdGenerator {
88    type Item = LayerId;
89
90    fn next(&mut self) -> Option<LayerId> {
91        static NEXT_ID_VALUE: AtomicU64 = AtomicU64::new(1);
92        // NEXT_ID_VALUE only increments so it only requires atomicity, and we
93        // can use Relaxed order.
94        let value = NEXT_ID_VALUE.fetch_add(1, Ordering::Relaxed);
95        // fetch_add wraps on overflow, which we'll use as a signal
96        // that this generator is out of ids.
97        if value == 0 { None } else { Some(LayerId(value)) }
98    }
99}
100fn next_layer_id() -> LayerId {
101    LayerIdGenerator::default().next().expect("layer_id")
102}
103
104async fn create_and_import_event(
105    coordinator: &CoordinatorProxy,
106) -> Result<(Event, EventId), Error> {
107    let event = Event::create();
108
109    let their_event = event.duplicate_handle(zx::Rights::SAME_RIGHTS)?;
110    let event_id_value = event.koid()?.raw_koid();
111    let event_id = EventId(event_id_value);
112    coordinator.import_event(their_event, &event_id.into())?;
113    Ok((event, event_id))
114}
115
116fn size_from_info(info: &fidl_fuchsia_hardware_display::Info, mode_idx: usize) -> IntSize {
117    let mode = &info.modes[mode_idx];
118    size2(mode.active_area.width, mode.active_area.height).to_i32()
119}
120
121#[derive(Debug, Clone)]
122pub struct Display {
123    pub coordinator: CoordinatorProxyPtr,
124    pub display_id: DisplayId,
125    pub info: fidl_fuchsia_hardware_display::Info,
126    pub layer_id: LayerId,
127    pub mode_idx: usize,
128}
129
130impl Display {
131    pub async fn new(
132        coordinator: CoordinatorProxyPtr,
133        display_id: DisplayId,
134        info: fidl_fuchsia_hardware_display::Info,
135    ) -> Result<Self, Error> {
136        Ok(Self { coordinator, display_id, info, layer_id: INVALID_LAYER_ID, mode_idx: 0 })
137    }
138
139    pub fn set_mode(&mut self, mode_idx: usize) -> Result<(), Error> {
140        self.coordinator.set_display_mode(&self.info.id, &self.info.modes[mode_idx])?;
141        self.mode_idx = mode_idx;
142        Ok(())
143    }
144
145    pub async fn create_layer(&mut self) -> Result<(), Error> {
146        let layer_id = next_layer_id();
147        let result = self.coordinator.create_layer(&layer_id.into()).await?;
148        match result {
149            Ok(()) => {
150                self.layer_id = layer_id.into();
151                Ok(())
152            }
153            Err(status) => {
154                bail!("Display::new(): failed to create layer {}", Status::from_raw(status))
155            }
156        }
157    }
158
159    pub fn size(&self) -> IntSize {
160        size_from_info(&self.info, self.mode_idx)
161    }
162
163    pub fn pixel_format(&self) -> PixelFormat {
164        self.info.pixel_format[0].into()
165    }
166}
167
168struct DisplayResources {
169    pub frame_set: FrameSet,
170    pub image_indexes: BTreeMap<ImageId, u32>,
171    pub context: RenderContext,
172    pub wait_events: WaitEvents,
173    pub busy_images: VecDeque<BusyImage>,
174}
175
176const RENDER_FRAME_COUNT: usize = 2;
177
178pub(crate) struct DisplayDirectViewStrategy {
179    key: ViewKey,
180    display: Display,
181    app_sender: UnboundedSender<MessageInternal>,
182    display_rotation: DisplayRotation,
183    display_resources: Option<DisplayResources>,
184    drop_display_resources_task: Option<fasync::Task<()>>,
185    display_resource_release_delay: std::time::Duration,
186    vsync_phase: MonotonicInstant,
187    vsync_interval: MonotonicDuration,
188    mouse_cursor_position: Option<IntPoint>,
189    pub collection_id: BufferCollectionId,
190    render_frame_count: usize,
191    last_config_stamp: u64,
192    presented: Option<u64>,
193}
194
195impl DisplayDirectViewStrategy {
196    pub async fn new(
197        key: ViewKey,
198        coordinator: CoordinatorProxyPtr,
199        app_sender: UnboundedSender<MessageInternal>,
200        info: fidl_fuchsia_hardware_display::Info,
201        preferred_size: IntSize,
202    ) -> Result<ViewStrategyPtr, Error> {
203        let app_config = Config::get();
204        let collection_id = next_collection_id();
205        let render_frame_count = app_config.buffer_count.unwrap_or(RENDER_FRAME_COUNT);
206
207        // Find first mode with the preferred size. Use preferred mode if not found.
208        let mode_idx = info
209            .modes
210            .iter()
211            .position(|mode| {
212                let size = size2(mode.active_area.width, mode.active_area.height).to_i32();
213                size == preferred_size
214            })
215            .unwrap_or(0);
216
217        let mut display = Display::new(coordinator, info.id.into(), info).await?;
218
219        if mode_idx != 0 {
220            display.set_mode(mode_idx)?;
221        }
222        display.create_layer().await?;
223
224        let display_resources = Self::allocate_display_resources(
225            collection_id,
226            display.size(),
227            display.pixel_format(),
228            render_frame_count,
229            &display,
230        )
231        .await?;
232
233        app_sender.unbounded_send(MessageInternal::Render(key)).expect("unbounded_send");
234        app_sender.unbounded_send(MessageInternal::Focus(key, true)).expect("unbounded_send");
235
236        Ok(Box::new(Self {
237            key,
238            display,
239            app_sender,
240            display_rotation: app_config.display_rotation,
241            display_resources: Some(display_resources),
242            drop_display_resources_task: None,
243            display_resource_release_delay: app_config.display_resource_release_delay,
244            vsync_phase: MonotonicInstant::get(),
245            vsync_interval: MonotonicDuration::from_millis(16),
246            mouse_cursor_position: None,
247            collection_id,
248            render_frame_count,
249            last_config_stamp: INVALID_CONFIG_STAMP_VALUE,
250            presented: None,
251        }))
252    }
253
254    fn make_context(
255        &mut self,
256        view_details: &ViewDetails,
257        image_id: Option<ImageId>,
258    ) -> ViewAssistantContext {
259        let time_now = MonotonicInstant::get();
260        // |interval_offset| is the offset from |time_now| to the next multiple
261        // of vsync interval after vsync phase, possibly negative if in the past.
262        let mut interval_offset = MonotonicDuration::from_nanos(
263            (self.vsync_phase.into_nanos() - time_now.into_nanos())
264                % self.vsync_interval.into_nanos(),
265        );
266        // Unless |time_now| is exactly on the interval, adjust forward to the next
267        // vsync after |time_now|.
268        if interval_offset != MonotonicDuration::from_nanos(0) && self.vsync_phase < time_now {
269            interval_offset += self.vsync_interval;
270        }
271
272        let display_rotation = self.display_rotation;
273        let app_sender = self.app_sender.clone();
274        let mouse_cursor_position = self.mouse_cursor_position.clone();
275        let (image_index, actual_image_id) = image_id
276            .and_then(|available| {
277                Some((
278                    *self.display_resources().image_indexes.get(&available).expect("image_index"),
279                    available,
280                ))
281            })
282            .unwrap_or_default();
283
284        ViewAssistantContext {
285            key: view_details.key,
286            size: match display_rotation {
287                DisplayRotation::Deg0 | DisplayRotation::Deg180 => view_details.physical_size,
288                DisplayRotation::Deg90 | DisplayRotation::Deg270 => {
289                    size2(view_details.physical_size.height, view_details.physical_size.width)
290                }
291            },
292            metrics: view_details.metrics,
293            presentation_time: time_now + interval_offset,
294            buffer_count: None,
295            image_id: actual_image_id,
296            image_index: image_index,
297            app_sender,
298            mouse_cursor_position,
299            display_info: Some(DisplayInfo::from(&self.display.info)),
300        }
301    }
302
303    async fn allocate_display_resources(
304        collection_id: BufferCollectionId,
305        size: IntSize,
306        pixel_format: display_utils::PixelFormat,
307        render_frame_count: usize,
308        display: &Display,
309    ) -> Result<DisplayResources, Error> {
310        let app_config = Config::get();
311        let use_spinel = app_config.use_spinel;
312
313        ensure!(use_spinel == false, "Spinel support is disabled");
314
315        let display_rotation = app_config.display_rotation;
316        let unsize = size.floor().to_u32();
317
318        let usage = if use_spinel { FrameUsage::Gpu } else { FrameUsage::Cpu };
319        let mut buffer_allocator = BufferCollectionAllocator::new(
320            unsize.width,
321            unsize.height,
322            pixel_format.into(),
323            usage,
324            render_frame_count,
325        )?;
326
327        buffer_allocator.set_name(100, "CarnelianDirect")?;
328
329        let context_token = buffer_allocator.duplicate_token().await?;
330        let context = RenderContext {
331            inner: ContextInner::Forma(generic::Forma::new_context(
332                context_token,
333                unsize,
334                display_rotation,
335            )),
336        };
337
338        let coordinator_token = buffer_allocator.duplicate_token().await?;
339        // Sysmem token channels serve both sysmem(1) and sysmem2, so we can convert here until
340        // display has an import_buffer_collection that takes a sysmem2 token.
341        display
342            .coordinator
343            .import_buffer_collection(&collection_id.into(), coordinator_token)
344            .await?
345            .map_err(zx::Status::from_raw)?;
346        display
347            .coordinator
348            .set_buffer_collection_constraints(
349                &collection_id.into(),
350                &ImageBufferUsage {
351                    tiling_type: fidl_fuchsia_hardware_display_types::IMAGE_TILING_TYPE_LINEAR,
352                },
353            )
354            .await?
355            .map_err(zx::Status::from_raw)?;
356
357        let buffers = buffer_allocator
358            .allocate_buffers(true)
359            .await
360            .context(format!("view: {:?} allocate_buffers", display.display_id))?;
361
362        ensure!(
363            buffers.settings.as_ref().unwrap().image_format_constraints.is_some(),
364            "No image format constraints"
365        );
366        ensure!(
367            buffers
368                .settings
369                .as_ref()
370                .unwrap()
371                .image_format_constraints
372                .as_ref()
373                .unwrap()
374                .pixel_format_modifier
375                .is_some(),
376            "Sysmem will always set pixel_format_modifier"
377        );
378        ensure!(
379            buffers.buffers.as_ref().unwrap().len() == render_frame_count,
380            "Buffers do not match frame count"
381        );
382
383        let image_tiling_type = match buffers
384            .settings
385            .as_ref()
386            .unwrap()
387            .image_format_constraints
388            .as_ref()
389            .unwrap()
390            .pixel_format_modifier
391            .as_ref()
392            .unwrap()
393        {
394            fidl_fuchsia_images2::PixelFormatModifier::IntelI915XTiled => 1,
395            fidl_fuchsia_images2::PixelFormatModifier::IntelI915YTiled => 2,
396            _ => fidl_fuchsia_hardware_display_types::IMAGE_TILING_TYPE_LINEAR,
397        };
398
399        let image_metadata = ImageMetadata {
400            dimensions: fidl_fuchsia_math::SizeU { width: unsize.width, height: unsize.height },
401            tiling_type: image_tiling_type,
402        };
403
404        let mut image_ids = BTreeSet::new();
405        let mut image_indexes = BTreeMap::new();
406        let mut wait_events = WaitEvents::new();
407        let buffer_count = buffers.buffers.as_ref().unwrap().len();
408        for index in 0..buffer_count as usize {
409            let uindex = index as u32;
410            let image_id = next_image_id();
411            let display_image_id = DisplayImageId(image_id);
412            display
413                .coordinator
414                .import_image(
415                    &image_metadata,
416                    &collection_id.into(),
417                    uindex,
418                    &display_image_id.into(),
419                )
420                .await
421                .context("FIDL coordinator import_image")?
422                .map_err(zx::Status::from_raw)
423                .context("import image error")?;
424
425            image_ids.insert(image_id as u64);
426            image_indexes.insert(image_id as u64, uindex);
427
428            let (event, event_id) = create_and_import_event(&display.coordinator).await?;
429            wait_events.insert(image_id as ImageId, (event, event_id));
430        }
431
432        let frame_set = FrameSet::new(collection_id, image_ids);
433
434        display.coordinator.set_layer_primary_config(&display.layer_id.into(), &image_metadata)?;
435
436        Ok(DisplayResources {
437            frame_set,
438            image_indexes,
439            context,
440            wait_events,
441            busy_images: VecDeque::new(),
442        })
443    }
444
445    async fn maybe_reallocate_display_resources(&mut self) -> Result<(), Error> {
446        if self.display_resources.is_none() {
447            instant!(
448                c"gfx",
449                c"DisplayDirectViewStrategy::allocate_display_resources",
450                fuchsia_trace::Scope::Process,
451                "" => ""
452            );
453            self.collection_id = next_collection_id();
454            self.presented = None;
455            self.display_resources = Some(
456                Self::allocate_display_resources(
457                    self.collection_id,
458                    self.display.size(),
459                    self.display.pixel_format(),
460                    self.render_frame_count,
461                    &self.display,
462                )
463                .await?,
464            );
465        }
466        Ok(())
467    }
468
469    fn display_resources(&mut self) -> &mut DisplayResources {
470        self.display_resources.as_mut().expect("display_resources")
471    }
472
473    fn update_image(
474        &mut self,
475        view_details: &ViewDetails,
476        view_assistant: &mut ViewAssistantPtr,
477        image: u64,
478    ) {
479        instant!(
480            c"gfx",
481            c"DisplayDirectViewStrategy::update_image",
482            fuchsia_trace::Scope::Process,
483            "image" => format!("{}", image).as_str()
484        );
485        let (event, _) = self.display_resources().wait_events.get(&image).expect("wait event");
486        let buffer_ready_event =
487            event.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("duplicate_handle");
488        let direct_context = self.make_context(view_details, Some(image));
489
490        view_assistant
491            .render(&mut self.display_resources().context, buffer_ready_event, &direct_context)
492            .unwrap_or_else(|e| panic!("Update error: {:?}", e));
493    }
494
495    fn handle_vsync_parameters_changed(
496        &mut self,
497        phase: MonotonicInstant,
498        interval: MonotonicDuration,
499    ) {
500        self.vsync_phase = phase;
501        self.vsync_interval = interval;
502    }
503}
504
505#[async_trait(?Send)]
506impl ViewStrategy for DisplayDirectViewStrategy {
507    fn initial_metrics(&self) -> Size {
508        size2(1.0, 1.0)
509    }
510
511    fn initial_physical_size(&self) -> Size {
512        self.display.size().to_f32()
513    }
514
515    fn initial_logical_size(&self) -> Size {
516        self.display.size().to_f32()
517    }
518
519    fn create_view_assistant_context(&self, view_details: &ViewDetails) -> ViewAssistantContext {
520        ViewAssistantContext {
521            key: view_details.key,
522            size: match self.display_rotation {
523                DisplayRotation::Deg0 | DisplayRotation::Deg180 => view_details.physical_size,
524                DisplayRotation::Deg90 | DisplayRotation::Deg270 => {
525                    size2(view_details.physical_size.height, view_details.physical_size.width)
526                }
527            },
528            metrics: view_details.metrics,
529            presentation_time: Default::default(),
530            buffer_count: None,
531            image_id: Default::default(),
532            image_index: Default::default(),
533            app_sender: self.app_sender.clone(),
534            mouse_cursor_position: self.mouse_cursor_position.clone(),
535            display_info: Some(DisplayInfo::from(&self.display.info)),
536        }
537    }
538
539    fn setup(&mut self, view_details: &ViewDetails, view_assistant: &mut ViewAssistantPtr) {
540        if let Some(available) = self.display_resources().frame_set.get_available_image() {
541            let direct_context = self.make_context(view_details, Some(available));
542            view_assistant
543                .setup(&direct_context)
544                .unwrap_or_else(|e| panic!("Setup error: {:?}", e));
545            self.display_resources().frame_set.return_image(available);
546        }
547    }
548
549    async fn render(
550        &mut self,
551        view_details: &ViewDetails,
552        view_assistant: &mut ViewAssistantPtr,
553    ) -> bool {
554        duration!("gfx", "DisplayDirectViewStrategy::update");
555        self.maybe_reallocate_display_resources()
556            .await
557            .expect("maybe_reallocate_display_resources");
558        if let Some(available) = self.display_resources().frame_set.get_available_image() {
559            self.update_image(view_details, view_assistant, available);
560            self.display_resources().frame_set.mark_prepared(available);
561            true
562        } else {
563            if self.render_frame_count == 1 {
564                if let Some(presented) = self.presented {
565                    self.update_image(view_details, view_assistant, presented);
566                    true
567                } else {
568                    false
569                }
570            } else {
571                false
572            }
573        }
574    }
575
576    fn present(&mut self, view_details: &ViewDetails) {
577        duration!("gfx", "DisplayDirectViewStrategy::present");
578
579        if self.render_frame_count == 1 && self.presented.is_some() {
580            return;
581        }
582        if let Some(prepared) = self.display_resources().frame_set.prepared {
583            instant!(
584                c"gfx",
585                c"DisplayDirectViewStrategy::present",
586                fuchsia_trace::Scope::Process,
587                "prepared" => format!("{}", prepared).as_str()
588            );
589            let collection_id = self.collection_id;
590            let view_key = view_details.key;
591
592            let layers = &[self.display.layer_id.into()];
593            if layers.len() as u32 > self.display.info.max_layer_count {
594                panic!(
595                    "Hardware layer limit ({}) is insufficient for Carnelian (requested {})",
596                    self.display.info.max_layer_count,
597                    layers.len()
598                );
599            }
600
601            self.display
602                .coordinator
603                .set_display_layers(&self.display.display_id.into(), layers)
604                .expect("set_display_layers");
605
606            let (_, wait_event_id) =
607                *self.display_resources().wait_events.get(&prepared).expect("wait event");
608
609            let image_id = DisplayImageId(prepared);
610            self.display
611                .coordinator
612                .set_layer_image2(
613                    &self.display.layer_id.into(),
614                    &image_id.into(),
615                    &wait_event_id.into(),
616                )
617                .expect("Frame::present() set_layer_image2");
618
619            self.last_config_stamp += 1;
620            let stamp = ConfigStamp { value: self.last_config_stamp };
621            let req = CoordinatorCommitConfigRequest { stamp: Some(stamp), ..Default::default() };
622
623            self.display.coordinator.commit_config(req).expect("Frame::present() commit_config");
624
625            self.display_resources().busy_images.push_back(BusyImage {
626                stamp,
627                view_key,
628                image_id,
629                collection_id,
630            });
631
632            self.display_resources().frame_set.mark_presented(prepared);
633            self.presented = Some(prepared);
634        }
635    }
636
637    fn handle_focus(
638        &mut self,
639        view_details: &ViewDetails,
640        view_assistant: &mut ViewAssistantPtr,
641        focus: bool,
642    ) {
643        let mut direct_context = self.make_context(view_details, None);
644        view_assistant
645            .handle_focus_event(&mut direct_context, focus)
646            .unwrap_or_else(|e| panic!("handle_focus error: {:?}", e));
647    }
648
649    fn convert_user_input_message(
650        &mut self,
651        _view_details: &ViewDetails,
652        _message: UserInputMessage,
653    ) -> Result<Vec<crate::input::Event>, Error> {
654        bail!("convert_user_input_message not used for display_direct.")
655    }
656
657    fn inspect_event(&mut self, view_details: &ViewDetails, event: &crate::input::Event) {
658        match &event.event_type {
659            input::EventType::Mouse(mouse_event) => {
660                self.mouse_cursor_position = Some(mouse_event.location);
661                self.app_sender
662                    .unbounded_send(MessageInternal::RequestRender(view_details.key))
663                    .expect("unbounded_send");
664            }
665            _ => (),
666        };
667    }
668
669    fn image_freed(&mut self, image_id: u64, collection_id: u32) {
670        if BufferCollectionId(collection_id as u64) == self.collection_id {
671            instant!(
672                c"gfx",
673                c"DisplayDirectViewStrategy::image_freed",
674                fuchsia_trace::Scope::Process,
675                "image_freed" => format!("{}", image_id).as_str()
676            );
677            if let Some(display_resources) = self.display_resources.as_mut() {
678                display_resources.frame_set.mark_done_presenting(image_id);
679            }
680        }
681    }
682
683    fn ownership_changed(&mut self, owned: bool) {
684        if !owned {
685            let timer = fasync::Timer::new(fuchsia_async::MonotonicInstant::after(
686                self.display_resource_release_delay.into(),
687            ));
688            let timer_sender = self.app_sender.clone();
689            let task = fasync::Task::local(async move {
690                timer.await;
691                timer_sender
692                    .unbounded_send(MessageInternal::DropDisplayResources)
693                    .expect("unbounded_send");
694            });
695            self.drop_display_resources_task = Some(task);
696        } else {
697            self.drop_display_resources_task = None;
698        }
699    }
700
701    fn drop_display_resources(&mut self) {
702        let task = self.drop_display_resources_task.take();
703        if task.is_some() {
704            instant!(
705                c"gfx",
706                c"DisplayDirectViewStrategy::drop_display_resources",
707                fuchsia_trace::Scope::Process,
708                "" => ""
709            );
710            self.display_resources = None;
711        }
712    }
713
714    async fn handle_display_coordinator_listener_request(
715        &mut self,
716        event: CoordinatorListenerRequest,
717    ) {
718        match event {
719            CoordinatorListenerRequest::OnVsync {
720                timestamp,
721                cookie,
722                displayed_config_stamp,
723                ..
724            } => {
725                duration!("gfx", "DisplayDirectViewStrategy::OnVsync");
726                let vsync_interval = MonotonicDuration::from_nanos(
727                    1_000_000_000_000 / self.display.info.modes[0].refresh_rate_millihertz as i64,
728                );
729                self.handle_vsync_parameters_changed(timestamp, vsync_interval);
730                if cookie.value != INVALID_DISP_ID {
731                    self.display
732                        .coordinator
733                        .acknowledge_vsync(cookie.value)
734                        .expect("acknowledge_vsync");
735                }
736
737                let signal_sender = self.app_sender.clone();
738
739                // Busy images are stamped with monotonically increasing values (because the last
740                // stamp added to the deque is always greater than the previous).  So when we see a
741                // vsync stamp, all images with a *strictly-lesser* stamp are now available for
742                // reuse (images with an *equal* stamp are the ones currently displayed on-screen,
743                // so can't be reused yet).
744                if let Some(display_resources) = self.display_resources.as_mut() {
745                    let busy_images = &mut display_resources.busy_images;
746                    while !busy_images.is_empty() {
747                        let front = &busy_images.front().unwrap();
748                        if displayed_config_stamp.value <= front.stamp.value {
749                            break;
750                        }
751
752                        signal_sender
753                            .unbounded_send(MessageInternal::ImageFreed(
754                                front.view_key,
755                                front.image_id.0,
756                                front.collection_id.0 as u32,
757                            ))
758                            .expect("unbounded_send");
759
760                        busy_images.pop_front();
761                    }
762                }
763
764                signal_sender
765                    .unbounded_send(MessageInternal::Render(self.key))
766                    .expect("unbounded_send");
767            }
768            CoordinatorListenerRequest::OnDisplaysChanged { .. } => {
769                eprintln!("Carnelian ignoring CoordinatorListenerRequest::OnDisplaysChanged");
770            }
771            CoordinatorListenerRequest::OnClientOwnershipChange { has_ownership, .. } => {
772                eprintln!(
773                    "Carnelian ignoring CoordinatorListenerRequest::OnClientOwnershipChange (value: {})",
774                    has_ownership
775                );
776            }
777            _ => (),
778        }
779    }
780
781    fn is_hosted_on_display(&self, display_id: DisplayId) -> bool {
782        self.display.display_id == display_id
783    }
784
785    fn close(&mut self) {
786        self.display
787            .coordinator
788            .release_buffer_collection(&self.collection_id.into())
789            .expect("release_buffer_collection");
790    }
791}