Skip to main content

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, ClientPriority as FidlClientPriority,
9    EventId as FidlEventId, ImageId as FidlImageId, Info, LayerId as FidlLayerId,
10    TEST_UTILITY_CLIENT_PRIORITY_VALUE as FidlTestUtilityClientPriorityValue,
11};
12use fidl_fuchsia_hardware_display_types::{
13    AlphaMode, Color as FidlColor, DisplayId as FidlDisplayId, INVALID_DISP_ID,
14};
15use fuchsia_async::OnSignals;
16use std::fmt;
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/// Strongly typed wrapper around a client priority.
135#[derive(Clone, Copy, Debug, Eq, PartialEq)]
136pub struct ClientPriority(pub u32);
137
138impl From<FidlClientPriority> for ClientPriority {
139    fn from(fidl_client_priority: FidlClientPriority) -> Self {
140        ClientPriority(fidl_client_priority.value)
141    }
142}
143
144impl From<ClientPriority> for FidlClientPriority {
145    fn from(client_priority: ClientPriority) -> Self {
146        FidlClientPriority { value: client_priority.0 }
147    }
148}
149
150/// The priority level used by display test utilities.
151pub const TEST_UTILITY_CLIENT_PRIORITY: ClientPriority =
152    ClientPriority(FidlTestUtilityClientPriorityValue);
153
154/// Enhances the `fuchsia.hardware.display.Info` FIDL struct.
155#[derive(Clone, Debug)]
156pub struct DisplayInfo(pub Info);
157
158impl DisplayInfo {
159    /// Returns the ID for this display.
160    pub fn id(&self) -> DisplayId {
161        self.0.id.into()
162    }
163}
164
165/// Custom user-friendly format representation.
166impl fmt::Display for DisplayInfo {
167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168        writeln!(f, "Display (id: {})", self.0.id.value)?;
169        writeln!(f, "\tManufacturer Name: \"{}\"", self.0.manufacturer_name)?;
170        writeln!(f, "\tMonitor Name: \"{}\"", self.0.monitor_name)?;
171        writeln!(f, "\tMonitor Serial: \"{}\"", self.0.monitor_serial)?;
172        writeln!(
173            f,
174            "\tPhysical Dimensions: {}mm x {}mm",
175            self.0.horizontal_size_mm, self.0.vertical_size_mm
176        )?;
177
178        writeln!(f, "\tPixel Formats:")?;
179        for (i, format) in self.0.pixel_format.iter().map(PixelFormat::from).enumerate() {
180            writeln!(f, "\t\t{}:\t{}", i, format)?;
181        }
182
183        writeln!(f, "\tDisplay Modes:")?;
184        for (i, mode) in self.0.modes.iter().enumerate() {
185            writeln!(
186                f,
187                "\t\t{}:\t{:.2} Hz @ {}x{}",
188                i,
189                (mode.refresh_rate_millihertz as f32) / 1000.,
190                mode.active_area.width,
191                mode.active_area.height
192            )?;
193        }
194
195        write!(f, "")
196    }
197}
198
199/// A zircon event that has been registered with the display driver.
200pub struct Event {
201    id: EventId,
202    event: zx::Event,
203}
204
205impl Event {
206    pub(crate) fn new(id: EventId, event: zx::Event) -> Event {
207        Event { id, event }
208    }
209
210    /// Returns the ID for this event.
211    pub fn id(&self) -> EventId {
212        self.id
213    }
214
215    /// Returns a future that completes when the event has been signaled.
216    pub async fn wait(&self) -> Result<()> {
217        OnSignals::new(&self.event, zx::Signals::EVENT_SIGNALED).await?;
218        self.event.as_handle_ref().signal(zx::Signals::EVENT_SIGNALED, zx::Signals::NONE)?;
219        Ok(())
220    }
221
222    /// Signals the event.
223    pub fn signal(&self) -> Result<()> {
224        self.event.as_handle_ref().signal(zx::Signals::NONE, zx::Signals::EVENT_SIGNALED)?;
225        Ok(())
226    }
227}
228
229/// Represents the alpha blending configuration for a layer.
230#[derive(Clone, Copy, Debug, PartialEq)]
231pub struct Alpha {
232    /// The blending mode to use.
233    pub mode: AlphaMode,
234    /// The constant alpha value to apply, in the range [0.0, 1.0].
235    pub val: f32,
236}
237
238/// Enhances the `fuchsia.hardware.display.typers.Color` FIDL struct.
239#[derive(Clone, Copy, Debug, PartialEq)]
240pub struct Color {
241    /// The format of `bytes`.
242    pub format: PixelFormat,
243
244    /// The constant color, represented as one pixel using `format`.
245    pub bytes: [u8; 8],
246}
247
248impl From<FidlColor> for Color {
249    fn from(fidl_color: FidlColor) -> Self {
250        Color { format: fidl_color.format.into(), bytes: fidl_color.bytes }
251    }
252}
253
254impl From<&FidlColor> for Color {
255    fn from(fidl_color: &FidlColor) -> Self {
256        Self::from(*fidl_color)
257    }
258}
259
260impl From<Color> for FidlColor {
261    fn from(color: Color) -> Self {
262        FidlColor { format: color.format.into(), bytes: color.bytes }
263    }
264}
265
266impl From<&Color> for FidlColor {
267    fn from(color: &Color) -> Self {
268        Self::from(*color)
269    }
270}
271
272#[cfg(test)]
273mod tests {
274    use super::*;
275    use fidl_fuchsia_images2::PixelFormat as FidlPixelFormat;
276    use googletest::prelude::*;
277
278    #[gtest]
279    #[fuchsia::test]
280    fn layer_id_from_fidl_layer_id() {
281        expect_eq!(LayerId(1), LayerId::from(FidlLayerId { value: 1 }));
282        expect_eq!(LayerId(2), LayerId::from(FidlLayerId { value: 2 }));
283        const LARGE: u64 = 1 << 63;
284        expect_eq!(LayerId(LARGE), LayerId::from(FidlLayerId { value: LARGE }));
285        expect_eq!(INVALID_LAYER_ID, LayerId::from(FidlLayerId { value: INVALID_DISP_ID }));
286    }
287
288    #[gtest]
289    #[fuchsia::test]
290    fn fidl_layer_id_from_layer_id() {
291        expect_eq!(FidlLayerId { value: 1 }, FidlLayerId::from(LayerId(1)));
292        expect_eq!(FidlLayerId { value: 2 }, FidlLayerId::from(LayerId(2)));
293        const LARGE: u64 = 1 << 63;
294        expect_eq!(FidlLayerId { value: LARGE }, FidlLayerId::from(LayerId(LARGE)));
295        expect_eq!(FidlLayerId { value: INVALID_DISP_ID }, FidlLayerId::from(INVALID_LAYER_ID));
296    }
297
298    #[gtest]
299    #[fuchsia::test]
300    fn fidl_layer_id_to_layer_id() {
301        expect_eq!(LayerId(1), FidlLayerId { value: 1 }.into());
302        expect_eq!(LayerId(2), FidlLayerId { value: 2 }.into());
303        const LARGE: u64 = 1 << 63;
304        expect_eq!(LayerId(LARGE), FidlLayerId { value: LARGE }.into());
305        expect_eq!(INVALID_LAYER_ID, FidlLayerId { value: INVALID_DISP_ID }.into());
306    }
307
308    #[gtest]
309    #[fuchsia::test]
310    fn layer_id_to_fidl_layer_id() {
311        expect_eq!(FidlLayerId { value: 1 }, LayerId(1).into());
312        expect_eq!(FidlLayerId { value: 2 }, LayerId(2).into());
313        const LARGE: u64 = 1 << 63;
314        expect_eq!(FidlLayerId { value: LARGE }, LayerId(LARGE).into());
315        expect_eq!(FidlLayerId { value: INVALID_DISP_ID }, INVALID_LAYER_ID.into());
316    }
317
318    #[gtest]
319    #[fuchsia::test]
320    fn layer_id_default() {
321        let default: LayerId = Default::default();
322        expect_eq!(default, INVALID_LAYER_ID);
323    }
324
325    #[gtest]
326    #[fuchsia::test]
327    fn display_id_from_fidl_display_id() {
328        expect_eq!(DisplayId(1), DisplayId::from(FidlDisplayId { value: 1 }));
329        expect_eq!(DisplayId(2), DisplayId::from(FidlDisplayId { value: 2 }));
330        const LARGE: u64 = 1 << 63;
331        expect_eq!(DisplayId(LARGE), DisplayId::from(FidlDisplayId { value: LARGE }));
332        expect_eq!(INVALID_DISPLAY_ID, DisplayId::from(FidlDisplayId { value: INVALID_DISP_ID }));
333    }
334
335    #[gtest]
336    #[fuchsia::test]
337    fn fidl_display_id_from_display_id() {
338        expect_eq!(FidlDisplayId { value: 1 }, FidlDisplayId::from(DisplayId(1)));
339        expect_eq!(FidlDisplayId { value: 2 }, FidlDisplayId::from(DisplayId(2)));
340        const LARGE: u64 = 1 << 63;
341        expect_eq!(FidlDisplayId { value: LARGE }, FidlDisplayId::from(DisplayId(LARGE)));
342        expect_eq!(
343            FidlDisplayId { value: INVALID_DISP_ID },
344            FidlDisplayId::from(INVALID_DISPLAY_ID)
345        );
346    }
347
348    #[gtest]
349    #[fuchsia::test]
350    fn fidl_display_id_to_display_id() {
351        expect_eq!(DisplayId(1), FidlDisplayId { value: 1 }.into());
352        expect_eq!(DisplayId(2), FidlDisplayId { value: 2 }.into());
353        const LARGE: u64 = 1 << 63;
354        expect_eq!(DisplayId(LARGE), FidlDisplayId { value: LARGE }.into());
355        expect_eq!(INVALID_DISPLAY_ID, FidlDisplayId { value: INVALID_DISP_ID }.into());
356    }
357
358    #[gtest]
359    #[fuchsia::test]
360    fn display_id_to_fidl_display_id() {
361        expect_eq!(FidlDisplayId { value: 1 }, DisplayId(1).into());
362        expect_eq!(FidlDisplayId { value: 2 }, DisplayId(2).into());
363        const LARGE: u64 = 1 << 63;
364        expect_eq!(FidlDisplayId { value: LARGE }, DisplayId(LARGE).into());
365        expect_eq!(FidlDisplayId { value: INVALID_DISP_ID }, INVALID_DISPLAY_ID.into());
366    }
367
368    #[gtest]
369    #[fuchsia::test]
370    fn display_id_default() {
371        let default: DisplayId = Default::default();
372        expect_eq!(default, INVALID_DISPLAY_ID);
373    }
374
375    #[gtest]
376    #[fuchsia::test]
377    fn buffer_collection_id_from_fidl_buffer_collection_id() {
378        expect_eq!(
379            BufferCollectionId(1),
380            BufferCollectionId::from(FidlBufferCollectionId { value: 1 })
381        );
382        expect_eq!(
383            BufferCollectionId(2),
384            BufferCollectionId::from(FidlBufferCollectionId { value: 2 })
385        );
386        const LARGE: u64 = 1 << 63;
387        expect_eq!(
388            BufferCollectionId(LARGE),
389            BufferCollectionId::from(FidlBufferCollectionId { value: LARGE })
390        );
391    }
392
393    #[gtest]
394    #[fuchsia::test]
395    fn fidl_buffer_collection_id_from_buffer_collection_id() {
396        expect_eq!(
397            FidlBufferCollectionId { value: 1 },
398            FidlBufferCollectionId::from(BufferCollectionId(1))
399        );
400        expect_eq!(
401            FidlBufferCollectionId { value: 2 },
402            FidlBufferCollectionId::from(BufferCollectionId(2))
403        );
404        const LARGE: u64 = 1 << 63;
405        expect_eq!(
406            FidlBufferCollectionId { value: LARGE },
407            FidlBufferCollectionId::from(BufferCollectionId(LARGE))
408        );
409    }
410
411    #[gtest]
412    #[fuchsia::test]
413    fn fidl_buffer_collection_id_to_buffer_collection_id() {
414        expect_eq!(BufferCollectionId(1), FidlBufferCollectionId { value: 1 }.into());
415        expect_eq!(BufferCollectionId(2), FidlBufferCollectionId { value: 2 }.into());
416        const LARGE: u64 = 1 << 63;
417        expect_eq!(BufferCollectionId(LARGE), FidlBufferCollectionId { value: LARGE }.into());
418    }
419
420    #[gtest]
421    #[fuchsia::test]
422    fn buffer_collection_id_to_fidl_buffer_collection_id() {
423        expect_eq!(FidlBufferCollectionId { value: 1 }, BufferCollectionId(1).into());
424        expect_eq!(FidlBufferCollectionId { value: 2 }, BufferCollectionId(2).into());
425        const LARGE: u64 = 1 << 63;
426        expect_eq!(FidlBufferCollectionId { value: LARGE }, BufferCollectionId(LARGE).into());
427    }
428
429    #[gtest]
430    #[fuchsia::test]
431    fn event_id_from_fidl_event_id() {
432        expect_eq!(EventId(1), EventId::from(FidlEventId { value: 1 }));
433        expect_eq!(EventId(2), EventId::from(FidlEventId { value: 2 }));
434        const LARGE: u64 = 1 << 63;
435        expect_eq!(EventId(LARGE), EventId::from(FidlEventId { value: LARGE }));
436        expect_eq!(INVALID_EVENT_ID, EventId::from(FidlEventId { value: INVALID_DISP_ID }));
437    }
438
439    #[gtest]
440    #[fuchsia::test]
441    fn fidl_event_id_from_event_id() {
442        expect_eq!(FidlEventId { value: 1 }, FidlEventId::from(EventId(1)));
443        expect_eq!(FidlEventId { value: 2 }, FidlEventId::from(EventId(2)));
444        const LARGE: u64 = 1 << 63;
445        expect_eq!(FidlEventId { value: LARGE }, FidlEventId::from(EventId(LARGE)));
446        expect_eq!(FidlEventId { value: INVALID_DISP_ID }, FidlEventId::from(INVALID_EVENT_ID));
447    }
448
449    #[gtest]
450    #[fuchsia::test]
451    fn fidl_event_id_to_event_id() {
452        expect_eq!(EventId(1), FidlEventId { value: 1 }.into());
453        expect_eq!(EventId(2), FidlEventId { value: 2 }.into());
454        const LARGE: u64 = 1 << 63;
455        expect_eq!(EventId(LARGE), FidlEventId { value: LARGE }.into());
456        expect_eq!(INVALID_EVENT_ID, FidlEventId { value: INVALID_DISP_ID }.into());
457    }
458
459    #[gtest]
460    #[fuchsia::test]
461    fn event_id_to_fidl_event_id() {
462        expect_eq!(FidlEventId { value: 1 }, EventId(1).into());
463        expect_eq!(FidlEventId { value: 2 }, EventId(2).into());
464        const LARGE: u64 = 1 << 63;
465        expect_eq!(FidlEventId { value: LARGE }, EventId(LARGE).into());
466        expect_eq!(FidlEventId { value: INVALID_DISP_ID }, INVALID_EVENT_ID.into());
467    }
468
469    #[gtest]
470    #[fuchsia::test]
471    fn event_id_default() {
472        let default: EventId = Default::default();
473        expect_eq!(default, INVALID_EVENT_ID);
474    }
475
476    #[gtest]
477    #[fuchsia::test]
478    fn image_id_from_fidl_image_id() {
479        expect_eq!(ImageId(1), ImageId::from(FidlImageId { value: 1 }));
480        expect_eq!(ImageId(2), ImageId::from(FidlImageId { value: 2 }));
481        const LARGE: u64 = 1 << 63;
482        expect_eq!(ImageId(LARGE), ImageId::from(FidlImageId { value: LARGE }));
483        expect_eq!(INVALID_IMAGE_ID, ImageId::from(FidlImageId { value: INVALID_DISP_ID }));
484    }
485
486    #[gtest]
487    #[fuchsia::test]
488    fn fidl_image_id_from_image_id() {
489        expect_eq!(FidlImageId { value: 1 }, FidlImageId::from(ImageId(1)));
490        expect_eq!(FidlImageId { value: 2 }, FidlImageId::from(ImageId(2)));
491        const LARGE: u64 = 1 << 63;
492        expect_eq!(FidlImageId { value: LARGE }, FidlImageId::from(ImageId(LARGE)));
493        expect_eq!(FidlImageId { value: INVALID_DISP_ID }, FidlImageId::from(INVALID_IMAGE_ID));
494    }
495
496    #[gtest]
497    #[fuchsia::test]
498    fn fidl_image_id_to_image_id() {
499        expect_eq!(ImageId(1), FidlImageId { value: 1 }.into());
500        expect_eq!(ImageId(2), FidlImageId { value: 2 }.into());
501        const LARGE: u64 = 1 << 63;
502        expect_eq!(ImageId(LARGE), FidlImageId { value: LARGE }.into());
503        expect_eq!(INVALID_IMAGE_ID, FidlImageId { value: INVALID_DISP_ID }.into());
504    }
505
506    #[gtest]
507    #[fuchsia::test]
508    fn image_id_to_fidl_image_id() {
509        expect_eq!(FidlImageId { value: 1 }, ImageId(1).into());
510        expect_eq!(FidlImageId { value: 2 }, ImageId(2).into());
511        const LARGE: u64 = 1 << 63;
512        expect_eq!(FidlImageId { value: LARGE }, ImageId(LARGE).into());
513        expect_eq!(FidlImageId { value: INVALID_DISP_ID }, INVALID_IMAGE_ID.into());
514    }
515
516    #[gtest]
517    #[fuchsia::test]
518    fn image_id_default() {
519        let default: ImageId = Default::default();
520        expect_eq!(default, INVALID_IMAGE_ID);
521    }
522
523    #[gtest]
524    #[fuchsia::test]
525    fn color_from_fidl_color() {
526        expect_eq!(
527            Color {
528                format: PixelFormat::R8G8B8A8,
529                bytes: [0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]
530            },
531            Color::from(FidlColor {
532                format: FidlPixelFormat::R8G8B8A8,
533                bytes: [0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48],
534            })
535        );
536    }
537
538    #[gtest]
539    #[fuchsia::test]
540    fn fidl_color_from_color() {
541        expect_eq!(
542            FidlColor {
543                format: FidlPixelFormat::R8G8B8A8,
544                bytes: [0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]
545            },
546            FidlColor::from(Color {
547                format: PixelFormat::R8G8B8A8,
548                bytes: [0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48],
549            })
550        );
551    }
552
553    #[gtest]
554    #[fuchsia::test]
555    fn fidl_color_to_color() {
556        expect_eq!(
557            Color {
558                format: PixelFormat::R8G8B8A8,
559                bytes: [0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]
560            },
561            FidlColor {
562                format: FidlPixelFormat::R8G8B8A8,
563                bytes: [0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]
564            }
565            .into()
566        );
567    }
568
569    #[gtest]
570    #[fuchsia::test]
571    fn color_to_fidl_color() {
572        expect_eq!(
573            FidlColor {
574                format: FidlPixelFormat::R8G8B8A8,
575                bytes: [0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]
576            },
577            Color {
578                format: PixelFormat::R8G8B8A8,
579                bytes: [0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48]
580            }
581            .into()
582        );
583    }
584}