display_utils/
types.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::error::Result;
6use crate::pixel_format::PixelFormat;
7use fidl_fuchsia_hardware_display::{
8    BufferCollectionId as FidlBufferCollectionId, EventId as FidlEventId, ImageId as FidlImageId,
9    Info, LayerId as FidlLayerId,
10};
11use fidl_fuchsia_hardware_display_types::{
12    Color as FidlColor, DisplayId as FidlDisplayId, INVALID_DISP_ID,
13};
14use fuchsia_async::OnSignals;
15use std::fmt;
16use zx::{self as zx, AsHandleRef};
17
18/// Strongly typed wrapper around a display ID.
19#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
20pub struct DisplayId(pub u64);
21
22/// Represents an invalid DisplayId value.
23pub const INVALID_DISPLAY_ID: DisplayId = DisplayId(INVALID_DISP_ID);
24
25impl Default for DisplayId {
26    fn default() -> Self {
27        INVALID_DISPLAY_ID
28    }
29}
30
31impl From<FidlDisplayId> for DisplayId {
32    fn from(fidl_display_id: FidlDisplayId) -> Self {
33        DisplayId(fidl_display_id.value)
34    }
35}
36
37impl From<DisplayId> for FidlDisplayId {
38    fn from(display_id: DisplayId) -> Self {
39        FidlDisplayId { value: display_id.0 }
40    }
41}
42
43/// Strongly typed wrapper around a display driver event ID.
44#[derive(Clone, Copy, Debug, Eq, PartialEq)]
45pub struct EventId(pub u64);
46
47/// Represents an invalid EventId value.
48pub const INVALID_EVENT_ID: EventId = EventId(INVALID_DISP_ID);
49
50impl Default for EventId {
51    fn default() -> Self {
52        INVALID_EVENT_ID
53    }
54}
55
56impl From<FidlEventId> for EventId {
57    fn from(fidl_event_id: FidlEventId) -> Self {
58        EventId(fidl_event_id.value)
59    }
60}
61
62impl From<EventId> for FidlEventId {
63    fn from(event_id: EventId) -> Self {
64        FidlEventId { value: event_id.0 }
65    }
66}
67
68/// Strongly typed wrapper around a display layer ID.
69#[derive(Clone, Copy, Debug, Eq, PartialEq)]
70pub struct LayerId(pub u64);
71
72/// Represents an invalid LayerId value.
73pub const INVALID_LAYER_ID: LayerId = LayerId(INVALID_DISP_ID);
74
75impl Default for LayerId {
76    fn default() -> Self {
77        INVALID_LAYER_ID
78    }
79}
80
81impl From<FidlLayerId> for LayerId {
82    fn from(fidl_layer_id: FidlLayerId) -> Self {
83        LayerId(fidl_layer_id.value)
84    }
85}
86
87impl From<LayerId> for FidlLayerId {
88    fn from(layer_id: LayerId) -> Self {
89        FidlLayerId { value: layer_id.0 }
90    }
91}
92
93/// Strongly typed wrapper around an image ID.
94#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
95pub struct ImageId(pub u64);
96
97/// Represents an invalid ImageId value.
98pub const INVALID_IMAGE_ID: ImageId = ImageId(INVALID_DISP_ID);
99
100impl Default for ImageId {
101    fn default() -> Self {
102        INVALID_IMAGE_ID
103    }
104}
105
106impl From<FidlImageId> for ImageId {
107    fn from(fidl_image_id: FidlImageId) -> Self {
108        ImageId(fidl_image_id.value)
109    }
110}
111
112impl From<ImageId> for FidlImageId {
113    fn from(image_id: ImageId) -> Self {
114        FidlImageId { value: image_id.0 }
115    }
116}
117
118/// Strongly typed wrapper around a sysmem buffer collection ID.
119#[derive(Clone, Copy, Debug, Eq, PartialEq)]
120pub struct BufferCollectionId(pub u64);
121
122impl From<FidlBufferCollectionId> for BufferCollectionId {
123    fn from(fidl_buffer_collection_id: FidlBufferCollectionId) -> Self {
124        BufferCollectionId(fidl_buffer_collection_id.value)
125    }
126}
127
128impl From<BufferCollectionId> for FidlBufferCollectionId {
129    fn from(buffer_collection_id: BufferCollectionId) -> Self {
130        FidlBufferCollectionId { value: buffer_collection_id.0 }
131    }
132}
133
134/// Enhances the `fuchsia.hardware.display.Info` FIDL struct.
135#[derive(Clone, Debug)]
136pub struct DisplayInfo(pub Info);
137
138impl DisplayInfo {
139    /// Returns the ID for this display.
140    pub fn id(&self) -> DisplayId {
141        self.0.id.into()
142    }
143}
144
145/// Custom user-friendly format representation.
146impl fmt::Display for DisplayInfo {
147    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148        writeln!(f, "Display (id: {})", self.0.id.value)?;
149        writeln!(f, "\tManufacturer Name: \"{}\"", self.0.manufacturer_name)?;
150        writeln!(f, "\tMonitor Name: \"{}\"", self.0.monitor_name)?;
151        writeln!(f, "\tMonitor Serial: \"{}\"", self.0.monitor_serial)?;
152        writeln!(
153            f,
154            "\tPhysical Dimensions: {}mm x {}mm",
155            self.0.horizontal_size_mm, self.0.vertical_size_mm
156        )?;
157
158        writeln!(f, "\tPixel Formats:")?;
159        for (i, format) in self.0.pixel_format.iter().map(PixelFormat::from).enumerate() {
160            writeln!(f, "\t\t{}:\t{}", i, format)?;
161        }
162
163        writeln!(f, "\tDisplay Modes:")?;
164        for (i, mode) in self.0.modes.iter().enumerate() {
165            writeln!(
166                f,
167                "\t\t{}:\t{:.2} Hz @ {}x{}",
168                i,
169                (mode.refresh_rate_millihertz as f32) / 1000.,
170                mode.active_area.width,
171                mode.active_area.height
172            )?;
173        }
174
175        write!(f, "")
176    }
177}
178
179/// A zircon event that has been registered with the display driver.
180pub struct Event {
181    id: EventId,
182    event: zx::Event,
183}
184
185impl Event {
186    pub(crate) fn new(id: EventId, event: zx::Event) -> Event {
187        Event { id, event }
188    }
189
190    /// Returns the ID for this event.
191    pub fn id(&self) -> EventId {
192        self.id
193    }
194
195    /// Returns a future that completes when the event has been signaled.
196    pub async fn wait(&self) -> Result<()> {
197        OnSignals::new(&self.event, zx::Signals::EVENT_SIGNALED).await?;
198        self.event.as_handle_ref().signal(zx::Signals::EVENT_SIGNALED, zx::Signals::NONE)?;
199        Ok(())
200    }
201
202    /// Signals the event.
203    pub fn signal(&self) -> Result<()> {
204        self.event.as_handle_ref().signal(zx::Signals::NONE, zx::Signals::EVENT_SIGNALED)?;
205        Ok(())
206    }
207}
208
209/// Enhances the `fuchsia.hardware.display.typers.Color` FIDL struct.
210#[derive(Clone, Copy, Debug, PartialEq)]
211pub struct Color {
212    /// The format of `bytes`.
213    pub format: PixelFormat,
214
215    /// The constant color, represented as one pixel using `format`.
216    pub bytes: [u8; 8],
217}
218
219impl From<FidlColor> for Color {
220    fn from(fidl_color: FidlColor) -> Self {
221        Color { format: fidl_color.format.into(), bytes: fidl_color.bytes }
222    }
223}
224
225impl From<&FidlColor> for Color {
226    fn from(fidl_color: &FidlColor) -> Self {
227        Self::from(*fidl_color)
228    }
229}
230
231impl From<Color> for FidlColor {
232    fn from(color: Color) -> Self {
233        FidlColor { format: color.format.into(), bytes: color.bytes }
234    }
235}
236
237impl From<&Color> for FidlColor {
238    fn from(color: &Color) -> Self {
239        Self::from(*color)
240    }
241}
242
243#[cfg(test)]
244mod tests {
245    use super::*;
246    use fidl_fuchsia_images2::PixelFormat as FidlPixelFormat;
247
248    #[fuchsia::test]
249    fn layer_id_from_fidl_layer_id() {
250        assert_eq!(LayerId(1), LayerId::from(FidlLayerId { value: 1 }));
251        assert_eq!(LayerId(2), LayerId::from(FidlLayerId { value: 2 }));
252        const LARGE: u64 = 1 << 63;
253        assert_eq!(LayerId(LARGE), LayerId::from(FidlLayerId { value: LARGE }));
254        assert_eq!(INVALID_LAYER_ID, LayerId::from(FidlLayerId { value: INVALID_DISP_ID }));
255    }
256
257    #[fuchsia::test]
258    fn fidl_layer_id_from_layer_id() {
259        assert_eq!(FidlLayerId { value: 1 }, FidlLayerId::from(LayerId(1)));
260        assert_eq!(FidlLayerId { value: 2 }, FidlLayerId::from(LayerId(2)));
261        const LARGE: u64 = 1 << 63;
262        assert_eq!(FidlLayerId { value: LARGE }, FidlLayerId::from(LayerId(LARGE)));
263        assert_eq!(FidlLayerId { value: INVALID_DISP_ID }, FidlLayerId::from(INVALID_LAYER_ID));
264    }
265
266    #[fuchsia::test]
267    fn fidl_layer_id_to_layer_id() {
268        assert_eq!(LayerId(1), FidlLayerId { value: 1 }.into());
269        assert_eq!(LayerId(2), FidlLayerId { value: 2 }.into());
270        const LARGE: u64 = 1 << 63;
271        assert_eq!(LayerId(LARGE), FidlLayerId { value: LARGE }.into());
272        assert_eq!(INVALID_LAYER_ID, FidlLayerId { value: INVALID_DISP_ID }.into());
273    }
274
275    #[fuchsia::test]
276    fn layer_id_to_fidl_layer_id() {
277        assert_eq!(FidlLayerId { value: 1 }, LayerId(1).into());
278        assert_eq!(FidlLayerId { value: 2 }, LayerId(2).into());
279        const LARGE: u64 = 1 << 63;
280        assert_eq!(FidlLayerId { value: LARGE }, LayerId(LARGE).into());
281        assert_eq!(FidlLayerId { value: INVALID_DISP_ID }, INVALID_LAYER_ID.into());
282    }
283
284    #[fuchsia::test]
285    fn layer_id_default() {
286        let default: LayerId = Default::default();
287        assert_eq!(default, INVALID_LAYER_ID);
288    }
289
290    #[fuchsia::test]
291    fn display_id_from_fidl_display_id() {
292        assert_eq!(DisplayId(1), DisplayId::from(FidlDisplayId { value: 1 }));
293        assert_eq!(DisplayId(2), DisplayId::from(FidlDisplayId { value: 2 }));
294        const LARGE: u64 = 1 << 63;
295        assert_eq!(DisplayId(LARGE), DisplayId::from(FidlDisplayId { value: LARGE }));
296        assert_eq!(INVALID_DISPLAY_ID, DisplayId::from(FidlDisplayId { value: INVALID_DISP_ID }));
297    }
298
299    #[fuchsia::test]
300    fn fidl_display_id_from_display_id() {
301        assert_eq!(FidlDisplayId { value: 1 }, FidlDisplayId::from(DisplayId(1)));
302        assert_eq!(FidlDisplayId { value: 2 }, FidlDisplayId::from(DisplayId(2)));
303        const LARGE: u64 = 1 << 63;
304        assert_eq!(FidlDisplayId { value: LARGE }, FidlDisplayId::from(DisplayId(LARGE)));
305        assert_eq!(
306            FidlDisplayId { value: INVALID_DISP_ID },
307            FidlDisplayId::from(INVALID_DISPLAY_ID)
308        );
309    }
310
311    #[fuchsia::test]
312    fn fidl_display_id_to_display_id() {
313        assert_eq!(DisplayId(1), FidlDisplayId { value: 1 }.into());
314        assert_eq!(DisplayId(2), FidlDisplayId { value: 2 }.into());
315        const LARGE: u64 = 1 << 63;
316        assert_eq!(DisplayId(LARGE), FidlDisplayId { value: LARGE }.into());
317        assert_eq!(INVALID_DISPLAY_ID, FidlDisplayId { value: INVALID_DISP_ID }.into());
318    }
319
320    #[fuchsia::test]
321    fn display_id_to_fidl_display_id() {
322        assert_eq!(FidlDisplayId { value: 1 }, DisplayId(1).into());
323        assert_eq!(FidlDisplayId { value: 2 }, DisplayId(2).into());
324        const LARGE: u64 = 1 << 63;
325        assert_eq!(FidlDisplayId { value: LARGE }, DisplayId(LARGE).into());
326        assert_eq!(FidlDisplayId { value: INVALID_DISP_ID }, INVALID_DISPLAY_ID.into());
327    }
328
329    #[fuchsia::test]
330    fn display_id_default() {
331        let default: DisplayId = Default::default();
332        assert_eq!(default, INVALID_DISPLAY_ID);
333    }
334
335    #[fuchsia::test]
336    fn buffer_collection_id_from_fidl_buffer_collection_id() {
337        assert_eq!(
338            BufferCollectionId(1),
339            BufferCollectionId::from(FidlBufferCollectionId { value: 1 })
340        );
341        assert_eq!(
342            BufferCollectionId(2),
343            BufferCollectionId::from(FidlBufferCollectionId { value: 2 })
344        );
345        const LARGE: u64 = 1 << 63;
346        assert_eq!(
347            BufferCollectionId(LARGE),
348            BufferCollectionId::from(FidlBufferCollectionId { value: LARGE })
349        );
350    }
351
352    #[fuchsia::test]
353    fn fidl_buffer_collection_id_from_buffer_collection_id() {
354        assert_eq!(
355            FidlBufferCollectionId { value: 1 },
356            FidlBufferCollectionId::from(BufferCollectionId(1))
357        );
358        assert_eq!(
359            FidlBufferCollectionId { value: 2 },
360            FidlBufferCollectionId::from(BufferCollectionId(2))
361        );
362        const LARGE: u64 = 1 << 63;
363        assert_eq!(
364            FidlBufferCollectionId { value: LARGE },
365            FidlBufferCollectionId::from(BufferCollectionId(LARGE))
366        );
367    }
368
369    #[fuchsia::test]
370    fn fidl_buffer_collection_id_to_buffer_collection_id() {
371        assert_eq!(BufferCollectionId(1), FidlBufferCollectionId { value: 1 }.into());
372        assert_eq!(BufferCollectionId(2), FidlBufferCollectionId { value: 2 }.into());
373        const LARGE: u64 = 1 << 63;
374        assert_eq!(BufferCollectionId(LARGE), FidlBufferCollectionId { value: LARGE }.into());
375    }
376
377    #[fuchsia::test]
378    fn buffer_collection_id_to_fidl_buffer_collection_id() {
379        assert_eq!(FidlBufferCollectionId { value: 1 }, BufferCollectionId(1).into());
380        assert_eq!(FidlBufferCollectionId { value: 2 }, BufferCollectionId(2).into());
381        const LARGE: u64 = 1 << 63;
382        assert_eq!(FidlBufferCollectionId { value: LARGE }, BufferCollectionId(LARGE).into());
383    }
384
385    #[fuchsia::test]
386    fn event_id_from_fidl_event_id() {
387        assert_eq!(EventId(1), EventId::from(FidlEventId { value: 1 }));
388        assert_eq!(EventId(2), EventId::from(FidlEventId { value: 2 }));
389        const LARGE: u64 = 1 << 63;
390        assert_eq!(EventId(LARGE), EventId::from(FidlEventId { value: LARGE }));
391        assert_eq!(INVALID_EVENT_ID, EventId::from(FidlEventId { value: INVALID_DISP_ID }));
392    }
393
394    #[fuchsia::test]
395    fn fidl_event_id_from_event_id() {
396        assert_eq!(FidlEventId { value: 1 }, FidlEventId::from(EventId(1)));
397        assert_eq!(FidlEventId { value: 2 }, FidlEventId::from(EventId(2)));
398        const LARGE: u64 = 1 << 63;
399        assert_eq!(FidlEventId { value: LARGE }, FidlEventId::from(EventId(LARGE)));
400        assert_eq!(FidlEventId { value: INVALID_DISP_ID }, FidlEventId::from(INVALID_EVENT_ID));
401    }
402
403    #[fuchsia::test]
404    fn fidl_event_id_to_event_id() {
405        assert_eq!(EventId(1), FidlEventId { value: 1 }.into());
406        assert_eq!(EventId(2), FidlEventId { value: 2 }.into());
407        const LARGE: u64 = 1 << 63;
408        assert_eq!(EventId(LARGE), FidlEventId { value: LARGE }.into());
409        assert_eq!(INVALID_EVENT_ID, FidlEventId { value: INVALID_DISP_ID }.into());
410    }
411
412    #[fuchsia::test]
413    fn event_id_to_fidl_event_id() {
414        assert_eq!(FidlEventId { value: 1 }, EventId(1).into());
415        assert_eq!(FidlEventId { value: 2 }, EventId(2).into());
416        const LARGE: u64 = 1 << 63;
417        assert_eq!(FidlEventId { value: LARGE }, EventId(LARGE).into());
418        assert_eq!(FidlEventId { value: INVALID_DISP_ID }, INVALID_EVENT_ID.into());
419    }
420
421    #[fuchsia::test]
422    fn event_id_default() {
423        let default: EventId = Default::default();
424        assert_eq!(default, INVALID_EVENT_ID);
425    }
426
427    #[fuchsia::test]
428    fn image_id_from_fidl_image_id() {
429        assert_eq!(ImageId(1), ImageId::from(FidlImageId { value: 1 }));
430        assert_eq!(ImageId(2), ImageId::from(FidlImageId { value: 2 }));
431        const LARGE: u64 = 1 << 63;
432        assert_eq!(ImageId(LARGE), ImageId::from(FidlImageId { value: LARGE }));
433        assert_eq!(INVALID_IMAGE_ID, ImageId::from(FidlImageId { value: INVALID_DISP_ID }));
434    }
435
436    #[fuchsia::test]
437    fn fidl_image_id_from_image_id() {
438        assert_eq!(FidlImageId { value: 1 }, FidlImageId::from(ImageId(1)));
439        assert_eq!(FidlImageId { value: 2 }, FidlImageId::from(ImageId(2)));
440        const LARGE: u64 = 1 << 63;
441        assert_eq!(FidlImageId { value: LARGE }, FidlImageId::from(ImageId(LARGE)));
442        assert_eq!(FidlImageId { value: INVALID_DISP_ID }, FidlImageId::from(INVALID_IMAGE_ID));
443    }
444
445    #[fuchsia::test]
446    fn fidl_image_id_to_image_id() {
447        assert_eq!(ImageId(1), FidlImageId { value: 1 }.into());
448        assert_eq!(ImageId(2), FidlImageId { value: 2 }.into());
449        const LARGE: u64 = 1 << 63;
450        assert_eq!(ImageId(LARGE), FidlImageId { value: LARGE }.into());
451        assert_eq!(INVALID_IMAGE_ID, FidlImageId { value: INVALID_DISP_ID }.into());
452    }
453
454    #[fuchsia::test]
455    fn image_id_to_fidl_image_id() {
456        assert_eq!(FidlImageId { value: 1 }, ImageId(1).into());
457        assert_eq!(FidlImageId { value: 2 }, ImageId(2).into());
458        const LARGE: u64 = 1 << 63;
459        assert_eq!(FidlImageId { value: LARGE }, ImageId(LARGE).into());
460        assert_eq!(FidlImageId { value: INVALID_DISP_ID }, INVALID_IMAGE_ID.into());
461    }
462
463    #[fuchsia::test]
464    fn image_id_default() {
465        let default: ImageId = Default::default();
466        assert_eq!(default, INVALID_IMAGE_ID);
467    }
468
469    #[fuchsia::test]
470    fn color_from_fidl_color() {
471        assert_eq!(
472            Color {
473                format: PixelFormat::R8G8B8A8,
474                bytes: [0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]
475            },
476            Color::from(FidlColor {
477                format: FidlPixelFormat::R8G8B8A8,
478                bytes: [0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48],
479            })
480        );
481    }
482
483    #[fuchsia::test]
484    fn fidl_color_from_color() {
485        assert_eq!(
486            FidlColor {
487                format: FidlPixelFormat::R8G8B8A8,
488                bytes: [0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]
489            },
490            FidlColor::from(Color {
491                format: PixelFormat::R8G8B8A8,
492                bytes: [0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48],
493            })
494        );
495    }
496
497    #[fuchsia::test]
498    fn fidl_color_to_color() {
499        assert_eq!(
500            Color {
501                format: PixelFormat::R8G8B8A8,
502                bytes: [0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]
503            },
504            FidlColor {
505                format: FidlPixelFormat::R8G8B8A8,
506                bytes: [0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]
507            }
508            .into()
509        );
510    }
511
512    #[fuchsia::test]
513    fn color_to_fidl_color() {
514        assert_eq!(
515            FidlColor {
516                format: FidlPixelFormat::R8G8B8A8,
517                bytes: [0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]
518            },
519            Color {
520                format: PixelFormat::R8G8B8A8,
521                bytes: [0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]
522            }
523            .into()
524        );
525    }
526}