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::err_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
193    /// ID of the framebuffer that has been prepared for presentation.
194    prepared: Option<ImageId>,
195
196    /// ID of the framebuffer submitted in the most recent present call.
197    presented: Option<ImageId>,
198}
199
200impl DisplayDirectViewStrategy {
201    pub async fn new(
202        key: ViewKey,
203        coordinator: CoordinatorProxyPtr,
204        app_sender: UnboundedSender<MessageInternal>,
205        info: fidl_fuchsia_hardware_display::Info,
206        preferred_size: IntSize,
207    ) -> Result<ViewStrategyPtr, Error> {
208        let app_config = Config::get();
209        let collection_id = next_collection_id();
210        let render_frame_count = app_config.buffer_count.unwrap_or(RENDER_FRAME_COUNT);
211
212        // Find first mode with the preferred size. Use preferred mode if not found.
213        let mode_idx = info
214            .modes
215            .iter()
216            .position(|mode| {
217                let size = size2(mode.active_area.width, mode.active_area.height).to_i32();
218                size == preferred_size
219            })
220            .unwrap_or(0);
221
222        let mut display = Display::new(coordinator, info.id.into(), info).await?;
223
224        if mode_idx != 0 {
225            display.set_mode(mode_idx)?;
226        }
227        display.create_layer().await?;
228
229        let display_resources = Self::allocate_display_resources(
230            collection_id,
231            display.size(),
232            display.pixel_format(),
233            render_frame_count,
234            &display,
235        )
236        .await?;
237
238        app_sender.unbounded_send(MessageInternal::Render(key)).expect("unbounded_send");
239        app_sender.unbounded_send(MessageInternal::Focus(key, true)).expect("unbounded_send");
240
241        Ok(Box::new(Self {
242            key,
243            display,
244            app_sender,
245            display_rotation: app_config.display_rotation,
246            display_resources: Some(display_resources),
247            drop_display_resources_task: None,
248            display_resource_release_delay: app_config.display_resource_release_delay,
249            vsync_phase: MonotonicInstant::get(),
250            vsync_interval: MonotonicDuration::from_millis(16),
251            mouse_cursor_position: None,
252            collection_id,
253            render_frame_count,
254            last_config_stamp: INVALID_CONFIG_STAMP_VALUE,
255            prepared: None,
256            presented: None,
257        }))
258    }
259
260    fn make_context(
261        &mut self,
262        view_details: &ViewDetails,
263        image_id: Option<ImageId>,
264    ) -> ViewAssistantContext {
265        let time_now = MonotonicInstant::get();
266        // |interval_offset| is the offset from |time_now| to the next multiple
267        // of vsync interval after vsync phase, possibly negative if in the past.
268        let mut interval_offset = MonotonicDuration::from_nanos(
269            (self.vsync_phase.into_nanos() - time_now.into_nanos())
270                % self.vsync_interval.into_nanos(),
271        );
272        // Unless |time_now| is exactly on the interval, adjust forward to the next
273        // vsync after |time_now|.
274        if interval_offset != MonotonicDuration::from_nanos(0) && self.vsync_phase < time_now {
275            interval_offset += self.vsync_interval;
276        }
277
278        let display_rotation = self.display_rotation;
279        let app_sender = self.app_sender.clone();
280        let mouse_cursor_position = self.mouse_cursor_position.clone();
281        let (image_index, actual_image_id) = image_id
282            .and_then(|available| {
283                Some((
284                    *self.display_resources().image_indexes.get(&available).expect("image_index"),
285                    available,
286                ))
287            })
288            .unwrap_or_default();
289
290        ViewAssistantContext {
291            key: view_details.key,
292            size: match display_rotation {
293                DisplayRotation::Deg0 | DisplayRotation::Deg180 => view_details.physical_size,
294                DisplayRotation::Deg90 | DisplayRotation::Deg270 => {
295                    size2(view_details.physical_size.height, view_details.physical_size.width)
296                }
297            },
298            metrics: view_details.metrics,
299            presentation_time: time_now + interval_offset,
300            buffer_count: None,
301            image_id: actual_image_id,
302            image_index: image_index,
303            app_sender,
304            mouse_cursor_position,
305            display_info: Some(DisplayInfo::from(&self.display.info)),
306        }
307    }
308
309    async fn allocate_display_resources(
310        collection_id: BufferCollectionId,
311        size: IntSize,
312        pixel_format: display_utils::PixelFormat,
313        render_frame_count: usize,
314        display: &Display,
315    ) -> Result<DisplayResources, Error> {
316        let app_config = Config::get();
317        let use_spinel = app_config.use_spinel;
318
319        ensure!(use_spinel == false, "Spinel support is disabled");
320
321        let display_rotation = app_config.display_rotation;
322        let unsize = size.floor().to_u32();
323
324        let usage = if use_spinel { FrameUsage::Gpu } else { FrameUsage::Cpu };
325        let mut buffer_allocator = BufferCollectionAllocator::new(
326            unsize.width,
327            unsize.height,
328            pixel_format.into(),
329            usage,
330            render_frame_count,
331        )?;
332
333        buffer_allocator.set_name(100, "CarnelianDirect")?;
334
335        let context_token = buffer_allocator.duplicate_token().await?;
336        let context = RenderContext {
337            inner: ContextInner::Forma(generic::Forma::new_context(
338                context_token,
339                unsize,
340                display_rotation,
341            )),
342        };
343
344        let coordinator_token = buffer_allocator.duplicate_token().await?;
345        // Sysmem token channels serve both sysmem(1) and sysmem2, so we can convert here until
346        // display has an import_buffer_collection that takes a sysmem2 token.
347        display
348            .coordinator
349            .import_buffer_collection(&collection_id.into(), coordinator_token)
350            .await?
351            .map_err(zx::Status::err_from_raw)?;
352        display
353            .coordinator
354            .set_buffer_collection_constraints(
355                &collection_id.into(),
356                &ImageBufferUsage {
357                    tiling_type: fidl_fuchsia_hardware_display_types::IMAGE_TILING_TYPE_LINEAR,
358                },
359            )
360            .await?
361            .map_err(zx::Status::err_from_raw)?;
362
363        let buffers = buffer_allocator
364            .allocate_buffers(true)
365            .await
366            .context(format!("view: {:?} allocate_buffers", display.display_id))?;
367
368        ensure!(
369            buffers.settings.as_ref().unwrap().image_format_constraints.is_some(),
370            "No image format constraints"
371        );
372        ensure!(
373            buffers
374                .settings
375                .as_ref()
376                .unwrap()
377                .image_format_constraints
378                .as_ref()
379                .unwrap()
380                .pixel_format_modifier
381                .is_some(),
382            "Sysmem will always set pixel_format_modifier"
383        );
384        ensure!(
385            buffers.buffers.as_ref().unwrap().len() == render_frame_count,
386            "Buffers do not match frame count"
387        );
388
389        let image_tiling_type = match buffers
390            .settings
391            .as_ref()
392            .unwrap()
393            .image_format_constraints
394            .as_ref()
395            .unwrap()
396            .pixel_format_modifier
397            .as_ref()
398            .unwrap()
399        {
400            fidl_fuchsia_images2::PixelFormatModifier::IntelI915XTiled => 1,
401            fidl_fuchsia_images2::PixelFormatModifier::IntelI915YTiled => 2,
402            _ => fidl_fuchsia_hardware_display_types::IMAGE_TILING_TYPE_LINEAR,
403        };
404
405        let image_metadata = ImageMetadata {
406            dimensions: fidl_fuchsia_math::SizeU { width: unsize.width, height: unsize.height },
407            tiling_type: image_tiling_type,
408        };
409
410        let mut image_ids = BTreeSet::new();
411        let mut image_indexes = BTreeMap::new();
412        let mut wait_events = WaitEvents::new();
413        let buffer_count = buffers.buffers.as_ref().unwrap().len();
414        for index in 0..buffer_count as usize {
415            let uindex = index as u32;
416            let image_id = next_image_id();
417            let display_image_id = DisplayImageId(image_id);
418            display
419                .coordinator
420                .import_image(
421                    &image_metadata,
422                    &collection_id.into(),
423                    uindex,
424                    &display_image_id.into(),
425                )
426                .await
427                .context("FIDL coordinator import_image")?
428                .map_err(zx::Status::err_from_raw)
429                .context("import image error")?;
430
431            image_ids.insert(image_id as u64);
432            image_indexes.insert(image_id as u64, uindex);
433
434            let (event, event_id) = create_and_import_event(&display.coordinator).await?;
435            wait_events.insert(image_id as ImageId, (event, event_id));
436        }
437
438        let frame_set = FrameSet::new(image_ids);
439
440        display.coordinator.set_layer_primary_config(&display.layer_id.into(), &image_metadata)?;
441
442        Ok(DisplayResources {
443            frame_set,
444            image_indexes,
445            context,
446            wait_events,
447            busy_images: VecDeque::new(),
448        })
449    }
450
451    async fn maybe_reallocate_display_resources(&mut self) -> Result<(), Error> {
452        if self.display_resources.is_none() {
453            instant!(
454                c"gfx",
455                c"DisplayDirectViewStrategy::allocate_display_resources",
456                fuchsia_trace::Scope::Process,
457                "" => ""
458            );
459            self.collection_id = next_collection_id();
460            self.prepared = None;
461            self.presented = None;
462            self.display_resources = Some(
463                Self::allocate_display_resources(
464                    self.collection_id,
465                    self.display.size(),
466                    self.display.pixel_format(),
467                    self.render_frame_count,
468                    &self.display,
469                )
470                .await?,
471            );
472        }
473        Ok(())
474    }
475
476    fn display_resources(&mut self) -> &mut DisplayResources {
477        self.display_resources.as_mut().expect("display_resources")
478    }
479
480    fn update_image(
481        &mut self,
482        view_details: &ViewDetails,
483        view_assistant: &mut ViewAssistantPtr,
484        image: u64,
485    ) {
486        instant!(
487            c"gfx",
488            c"DisplayDirectViewStrategy::update_image",
489            fuchsia_trace::Scope::Process,
490            "image" => format!("{}", image).as_str()
491        );
492        let (event, _) = self.display_resources().wait_events.get(&image).expect("wait event");
493        let buffer_ready_event =
494            event.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("duplicate_handle");
495        let direct_context = self.make_context(view_details, Some(image));
496
497        view_assistant
498            .render(&mut self.display_resources().context, buffer_ready_event, &direct_context)
499            .unwrap_or_else(|e| panic!("Update error: {:?}", e));
500    }
501
502    fn handle_vsync_parameters_changed(
503        &mut self,
504        phase: MonotonicInstant,
505        interval: MonotonicDuration,
506    ) {
507        self.vsync_phase = phase;
508        self.vsync_interval = interval;
509    }
510}
511
512#[async_trait(?Send)]
513impl ViewStrategy for DisplayDirectViewStrategy {
514    fn initial_metrics(&self) -> Size {
515        size2(1.0, 1.0)
516    }
517
518    fn initial_physical_size(&self) -> Size {
519        self.display.size().to_f32()
520    }
521
522    fn initial_logical_size(&self) -> Size {
523        self.display.size().to_f32()
524    }
525
526    fn create_view_assistant_context(&self, view_details: &ViewDetails) -> ViewAssistantContext {
527        ViewAssistantContext {
528            key: view_details.key,
529            size: match self.display_rotation {
530                DisplayRotation::Deg0 | DisplayRotation::Deg180 => view_details.physical_size,
531                DisplayRotation::Deg90 | DisplayRotation::Deg270 => {
532                    size2(view_details.physical_size.height, view_details.physical_size.width)
533                }
534            },
535            metrics: view_details.metrics,
536            presentation_time: Default::default(),
537            buffer_count: None,
538            image_id: Default::default(),
539            image_index: Default::default(),
540            app_sender: self.app_sender.clone(),
541            mouse_cursor_position: self.mouse_cursor_position.clone(),
542            display_info: Some(DisplayInfo::from(&self.display.info)),
543        }
544    }
545
546    fn setup(&mut self, view_details: &ViewDetails, view_assistant: &mut ViewAssistantPtr) {
547        if let Some(available) = self.display_resources().frame_set.take_image() {
548            let direct_context = self.make_context(view_details, Some(available));
549            view_assistant
550                .setup(&direct_context)
551                .unwrap_or_else(|e| panic!("Setup error: {:?}", e));
552            self.display_resources().frame_set.return_image(available);
553        }
554    }
555
556    async fn render(
557        &mut self,
558        view_details: &ViewDetails,
559        view_assistant: &mut ViewAssistantPtr,
560    ) -> bool {
561        duration!("gfx", "DisplayDirectViewStrategy::update");
562        self.maybe_reallocate_display_resources()
563            .await
564            .expect("maybe_reallocate_display_resources");
565
566        let prepared_image: Option<ImageId> =
567            self.display_resources().frame_set.take_image().or_else(|| {
568                // If there is only one render framebuffer, we always use that
569                // framebuffer, even if it's being presented.
570                if self.render_frame_count == 1 { self.presented } else { None }
571            });
572
573        if let Some(prepared_image) = prepared_image {
574            self.update_image(view_details, view_assistant, prepared_image);
575            self.prepared = Some(prepared_image);
576            true
577        } else {
578            false
579        }
580    }
581
582    fn present(&mut self, view_details: &ViewDetails) {
583        duration!("gfx", "DisplayDirectViewStrategy::present");
584
585        let image_to_present = self.prepared.take();
586        if let Some(image_to_present) = image_to_present {
587            instant!(
588                c"gfx",
589                c"DisplayDirectViewStrategy::present",
590                fuchsia_trace::Scope::Process,
591                "image_to_present" => format!("{}", image_to_present).as_str()
592            );
593            let collection_id = self.collection_id;
594            let view_key = view_details.key;
595
596            let layers = &[self.display.layer_id.into()];
597            if layers.len() as u32 > self.display.info.max_layer_count {
598                panic!(
599                    "Hardware layer limit ({}) is insufficient for Carnelian (requested {})",
600                    self.display.info.max_layer_count,
601                    layers.len()
602                );
603            }
604
605            self.display
606                .coordinator
607                .set_display_layers(&self.display.display_id.into(), layers)
608                .expect("set_display_layers");
609
610            let (_, wait_event_id) =
611                *self.display_resources().wait_events.get(&image_to_present).expect("wait event");
612
613            let image_id = DisplayImageId(image_to_present);
614            self.display
615                .coordinator
616                .set_layer_image2(
617                    &self.display.layer_id.into(),
618                    &image_id.into(),
619                    &wait_event_id.into(),
620                )
621                .expect("Frame::present() set_layer_image2");
622
623            self.last_config_stamp += 1;
624            let stamp = ConfigStamp { value: self.last_config_stamp };
625            let req = CoordinatorCommitConfigRequest { stamp: Some(stamp), ..Default::default() };
626
627            self.display.coordinator.commit_config(req).expect("Frame::present() commit_config");
628
629            if self.render_frame_count > 1 {
630                self.display_resources().busy_images.push_back(BusyImage {
631                    stamp,
632                    view_key,
633                    image_id,
634                    collection_id,
635                });
636            }
637            self.presented = Some(image_to_present);
638        }
639    }
640
641    fn handle_focus(
642        &mut self,
643        view_details: &ViewDetails,
644        view_assistant: &mut ViewAssistantPtr,
645        focus: bool,
646    ) {
647        let mut direct_context = self.make_context(view_details, None);
648        view_assistant
649            .handle_focus_event(&mut direct_context, focus)
650            .unwrap_or_else(|e| panic!("handle_focus error: {:?}", e));
651    }
652
653    fn convert_user_input_message(
654        &mut self,
655        _view_details: &ViewDetails,
656        _message: UserInputMessage,
657    ) -> Result<Vec<crate::input::Event>, Error> {
658        bail!("convert_user_input_message not used for display_direct.")
659    }
660
661    fn inspect_event(&mut self, view_details: &ViewDetails, event: &crate::input::Event) {
662        match &event.event_type {
663            input::EventType::Mouse(mouse_event) => {
664                self.mouse_cursor_position = Some(mouse_event.location);
665                self.app_sender
666                    .unbounded_send(MessageInternal::RequestRender(view_details.key))
667                    .expect("unbounded_send");
668            }
669            _ => (),
670        };
671    }
672
673    fn image_freed(&mut self, image_id: u64, collection_id: u32) {
674        if BufferCollectionId(collection_id as u64) == self.collection_id {
675            instant!(
676                c"gfx",
677                c"DisplayDirectViewStrategy::image_freed",
678                fuchsia_trace::Scope::Process,
679                "image_freed" => format!("{}", image_id).as_str()
680            );
681            if let Some(display_resources) = self.display_resources.as_mut() {
682                display_resources.frame_set.return_image(image_id);
683            }
684        }
685    }
686
687    fn ownership_changed(&mut self, owned: bool) {
688        if !owned {
689            let timer = fasync::Timer::new(fuchsia_async::MonotonicInstant::after(
690                self.display_resource_release_delay.into(),
691            ));
692            let timer_sender = self.app_sender.clone();
693            let task = fasync::Task::local(async move {
694                timer.await;
695                timer_sender
696                    .unbounded_send(MessageInternal::DropDisplayResources)
697                    .expect("unbounded_send");
698            });
699            self.drop_display_resources_task = Some(task);
700        } else {
701            self.drop_display_resources_task = None;
702        }
703    }
704
705    fn drop_display_resources(&mut self) {
706        let task = self.drop_display_resources_task.take();
707        if task.is_some() {
708            instant!(
709                c"gfx",
710                c"DisplayDirectViewStrategy::drop_display_resources",
711                fuchsia_trace::Scope::Process,
712                "" => ""
713            );
714            self.prepared = None;
715            self.presented = None;
716            self.display_resources = None;
717        }
718    }
719
720    async fn handle_display_coordinator_listener_request(
721        &mut self,
722        event: CoordinatorListenerRequest,
723    ) {
724        match event {
725            CoordinatorListenerRequest::OnVsync {
726                timestamp,
727                cookie,
728                displayed_config_stamp,
729                ..
730            } => {
731                duration!("gfx", "DisplayDirectViewStrategy::OnVsync");
732                let vsync_interval = MonotonicDuration::from_nanos(
733                    1_000_000_000_000 / self.display.info.modes[0].refresh_rate_millihertz as i64,
734                );
735                self.handle_vsync_parameters_changed(timestamp, vsync_interval);
736                if cookie.value != INVALID_DISP_ID {
737                    self.display
738                        .coordinator
739                        .acknowledge_vsync(cookie.value)
740                        .expect("acknowledge_vsync");
741                }
742
743                let signal_sender = self.app_sender.clone();
744
745                // Busy images are stamped with monotonically increasing values (because the last
746                // stamp added to the deque is always greater than the previous).  So when we see a
747                // vsync stamp, all images with a *strictly-lesser* stamp are now available for
748                // reuse (images with an *equal* stamp are the ones currently displayed on-screen,
749                // so can't be reused yet).
750                if let Some(display_resources) = self.display_resources.as_mut() {
751                    let busy_images = &mut display_resources.busy_images;
752                    while !busy_images.is_empty() {
753                        let front = &busy_images.front().unwrap();
754                        if displayed_config_stamp.value <= front.stamp.value {
755                            break;
756                        }
757
758                        signal_sender
759                            .unbounded_send(MessageInternal::ImageFreed(
760                                front.view_key,
761                                front.image_id.0,
762                                front.collection_id.0 as u32,
763                            ))
764                            .expect("unbounded_send");
765
766                        busy_images.pop_front();
767                    }
768                }
769
770                signal_sender
771                    .unbounded_send(MessageInternal::Render(self.key))
772                    .expect("unbounded_send");
773            }
774            CoordinatorListenerRequest::OnDisplaysChanged { .. } => {
775                eprintln!("Carnelian ignoring CoordinatorListenerRequest::OnDisplaysChanged");
776            }
777            CoordinatorListenerRequest::OnClientOwnershipChange { has_ownership, .. } => {
778                eprintln!(
779                    "Carnelian ignoring CoordinatorListenerRequest::OnClientOwnershipChange (value: {})",
780                    has_ownership
781                );
782            }
783            _ => (),
784        }
785    }
786
787    fn is_hosted_on_display(&self, display_id: DisplayId) -> bool {
788        self.display.display_id == display_id
789    }
790
791    fn close(&mut self) {
792        self.display
793            .coordinator
794            .release_buffer_collection(&self.collection_id.into())
795            .expect("release_buffer_collection");
796    }
797}