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, HandleBased, 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(Event::from_handle(their_event.into_handle()), &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            self.display
592                .coordinator
593                .set_display_layers(
594                    &self.display.display_id.into(),
595                    &[self.display.layer_id.into()],
596                )
597                .expect("set_display_layers");
598
599            let (_, wait_event_id) =
600                *self.display_resources().wait_events.get(&prepared).expect("wait event");
601
602            let image_id = DisplayImageId(prepared);
603            self.display
604                .coordinator
605                .set_layer_image2(
606                    &self.display.layer_id.into(),
607                    &image_id.into(),
608                    &wait_event_id.into(),
609                )
610                .expect("Frame::present() set_layer_image2");
611
612            self.last_config_stamp += 1;
613            let stamp = ConfigStamp { value: self.last_config_stamp };
614            let req = CoordinatorCommitConfigRequest { stamp: Some(stamp), ..Default::default() };
615
616            self.display.coordinator.commit_config(req).expect("Frame::present() commit_config");
617
618            self.display_resources().busy_images.push_back(BusyImage {
619                stamp,
620                view_key,
621                image_id,
622                collection_id,
623            });
624
625            self.display_resources().frame_set.mark_presented(prepared);
626            self.presented = Some(prepared);
627        }
628    }
629
630    fn handle_focus(
631        &mut self,
632        view_details: &ViewDetails,
633        view_assistant: &mut ViewAssistantPtr,
634        focus: bool,
635    ) {
636        let mut direct_context = self.make_context(view_details, None);
637        view_assistant
638            .handle_focus_event(&mut direct_context, focus)
639            .unwrap_or_else(|e| panic!("handle_focus error: {:?}", e));
640    }
641
642    fn convert_user_input_message(
643        &mut self,
644        _view_details: &ViewDetails,
645        _message: UserInputMessage,
646    ) -> Result<Vec<crate::input::Event>, Error> {
647        bail!("convert_user_input_message not used for display_direct.")
648    }
649
650    fn inspect_event(&mut self, view_details: &ViewDetails, event: &crate::input::Event) {
651        match &event.event_type {
652            input::EventType::Mouse(mouse_event) => {
653                self.mouse_cursor_position = Some(mouse_event.location);
654                self.app_sender
655                    .unbounded_send(MessageInternal::RequestRender(view_details.key))
656                    .expect("unbounded_send");
657            }
658            _ => (),
659        };
660    }
661
662    fn image_freed(&mut self, image_id: u64, collection_id: u32) {
663        if BufferCollectionId(collection_id as u64) == self.collection_id {
664            instant!(
665                c"gfx",
666                c"DisplayDirectViewStrategy::image_freed",
667                fuchsia_trace::Scope::Process,
668                "image_freed" => format!("{}", image_id).as_str()
669            );
670            if let Some(display_resources) = self.display_resources.as_mut() {
671                display_resources.frame_set.mark_done_presenting(image_id);
672            }
673        }
674    }
675
676    fn ownership_changed(&mut self, owned: bool) {
677        if !owned {
678            let timer = fasync::Timer::new(fuchsia_async::MonotonicInstant::after(
679                self.display_resource_release_delay.into(),
680            ));
681            let timer_sender = self.app_sender.clone();
682            let task = fasync::Task::local(async move {
683                timer.await;
684                timer_sender
685                    .unbounded_send(MessageInternal::DropDisplayResources)
686                    .expect("unbounded_send");
687            });
688            self.drop_display_resources_task = Some(task);
689        } else {
690            self.drop_display_resources_task = None;
691        }
692    }
693
694    fn drop_display_resources(&mut self) {
695        let task = self.drop_display_resources_task.take();
696        if task.is_some() {
697            instant!(
698                c"gfx",
699                c"DisplayDirectViewStrategy::drop_display_resources",
700                fuchsia_trace::Scope::Process,
701                "" => ""
702            );
703            self.display_resources = None;
704        }
705    }
706
707    async fn handle_display_coordinator_listener_request(
708        &mut self,
709        event: CoordinatorListenerRequest,
710    ) {
711        match event {
712            CoordinatorListenerRequest::OnVsync {
713                timestamp,
714                cookie,
715                displayed_config_stamp,
716                ..
717            } => {
718                duration!("gfx", "DisplayDirectViewStrategy::OnVsync");
719                let vsync_interval = MonotonicDuration::from_nanos(
720                    1_000_000_000_000 / self.display.info.modes[0].refresh_rate_millihertz as i64,
721                );
722                self.handle_vsync_parameters_changed(timestamp, vsync_interval);
723                if cookie.value != INVALID_DISP_ID {
724                    self.display
725                        .coordinator
726                        .acknowledge_vsync(cookie.value)
727                        .expect("acknowledge_vsync");
728                }
729
730                let signal_sender = self.app_sender.clone();
731
732                // Busy images are stamped with monotonically increasing values (because the last
733                // stamp added to the deque is always greater than the previous).  So when we see a
734                // vsync stamp, all images with a *strictly-lesser* stamp are now available for
735                // reuse (images with an *equal* stamp are the ones currently displayed on-screen,
736                // so can't be reused yet).
737                if let Some(display_resources) = self.display_resources.as_mut() {
738                    let busy_images = &mut display_resources.busy_images;
739                    while !busy_images.is_empty() {
740                        let front = &busy_images.front().unwrap();
741                        if displayed_config_stamp.value <= front.stamp.value {
742                            break;
743                        }
744
745                        signal_sender
746                            .unbounded_send(MessageInternal::ImageFreed(
747                                front.view_key,
748                                front.image_id.0,
749                                front.collection_id.0 as u32,
750                            ))
751                            .expect("unbounded_send");
752
753                        busy_images.pop_front();
754                    }
755                }
756
757                signal_sender
758                    .unbounded_send(MessageInternal::Render(self.key))
759                    .expect("unbounded_send");
760            }
761            CoordinatorListenerRequest::OnDisplaysChanged { .. } => {
762                eprintln!("Carnelian ignoring CoordinatorListenerRequest::OnDisplaysChanged");
763            }
764            CoordinatorListenerRequest::OnClientOwnershipChange { has_ownership, .. } => {
765                eprintln!(
766                    "Carnelian ignoring CoordinatorListenerRequest::OnClientOwnershipChange (value: {})",
767                    has_ownership
768                );
769            }
770            _ => (),
771        }
772    }
773
774    fn is_hosted_on_display(&self, display_id: DisplayId) -> bool {
775        self.display.display_id == display_id
776    }
777
778    fn close(&mut self) {
779        self.display
780            .coordinator
781            .release_buffer_collection(&self.collection_id.into())
782            .expect("release_buffer_collection");
783    }
784}