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