jay_config/
video.rs

1//! Tools for configuring graphics cards and monitors.
2
3use {
4    crate::{
5        _private::WireMode,
6        PciId, Workspace,
7        video::connector_type::{
8            CON_9PIN_DIN, CON_COMPONENT, CON_COMPOSITE, CON_DISPLAY_PORT, CON_DPI, CON_DSI,
9            CON_DVIA, CON_DVID, CON_DVII, CON_EDP, CON_EMBEDDED_WINDOW, CON_HDMIA, CON_HDMIB,
10            CON_LVDS, CON_SPI, CON_SVIDEO, CON_TV, CON_UNKNOWN, CON_USB, CON_VGA, CON_VIRTUAL,
11            CON_WRITEBACK, ConnectorType,
12        },
13    },
14    serde::{Deserialize, Serialize},
15    std::{str::FromStr, time::Duration},
16};
17
18/// The mode of a connector.
19///
20/// Currently a mode consists of three properties:
21///
22/// - width in pixels
23/// - height in pixels
24/// - refresh rate in mhz.
25#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
26pub struct Mode {
27    pub(crate) width: i32,
28    pub(crate) height: i32,
29    pub(crate) refresh_millihz: u32,
30}
31
32impl Mode {
33    /// Returns the width of the mode.
34    pub fn width(&self) -> i32 {
35        self.width
36    }
37
38    /// Returns the height of the mode.
39    pub fn height(&self) -> i32 {
40        self.height
41    }
42
43    /// Returns the refresh rate of the mode in mhz.
44    ///
45    /// For a 60hz monitor, this function would return 60_000.
46    pub fn refresh_rate(&self) -> u32 {
47        self.refresh_millihz
48    }
49
50    pub(crate) fn zeroed() -> Self {
51        Self {
52            width: 0,
53            height: 0,
54            refresh_millihz: 0,
55        }
56    }
57}
58
59/// A connector that is potentially connected to an output device.
60///
61/// A connector is the part that sticks out of your graphics card. A graphics card usually
62/// has many connectors but one few of them are actually connected to a monitor.
63#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
64pub struct Connector(pub u64);
65
66impl Connector {
67    /// Returns whether this connector existed at the time `get_connector` was called.
68    ///
69    /// This only implies existence at the time `get_connector` was called. Even if this
70    /// function returns true, the connector might since have disappeared.
71    pub fn exists(self) -> bool {
72        self.0 != 0
73    }
74
75    /// Returns whether the connector is connected to an output device.
76    pub fn connected(self) -> bool {
77        if !self.exists() {
78            return false;
79        }
80        get!(false).connector_connected(self)
81    }
82
83    /// Returns the scale of the currently connected monitor.
84    pub fn scale(self) -> f64 {
85        if !self.exists() {
86            return 1.0;
87        }
88        get!(1.0).connector_get_scale(self)
89    }
90
91    /// Sets the scale to use for the currently connected monitor.
92    pub fn set_scale(self, scale: f64) {
93        if !self.exists() {
94            return;
95        }
96        log::info!("setting scale to {}", scale);
97        get!().connector_set_scale(self, scale);
98    }
99
100    /// Returns the connector type.
101    pub fn ty(self) -> ConnectorType {
102        if !self.exists() {
103            return CON_UNKNOWN;
104        }
105        get!(CON_UNKNOWN).connector_type(self)
106    }
107
108    /// Returns the current mode of the connector.
109    pub fn mode(self) -> Mode {
110        if !self.exists() {
111            return Mode::zeroed();
112        }
113        get!(Mode::zeroed()).connector_mode(self)
114    }
115
116    /// Tries to set the mode of the connector.
117    ///
118    /// If the refresh rate is not specified, tries to use the first mode with the given
119    /// width and height.
120    ///
121    /// The default mode is the first mode advertised by the connector. This is usually
122    /// the native mode.
123    pub fn set_mode(self, width: i32, height: i32, refresh_millihz: Option<u32>) {
124        if !self.exists() {
125            log::warn!("set_mode called on a connector that does not exist");
126            return;
127        }
128        let refresh_millihz = match refresh_millihz {
129            Some(r) => r,
130            _ => match self
131                .modes()
132                .iter()
133                .find(|m| m.width == width && m.height == height)
134            {
135                Some(m) => m.refresh_millihz,
136                _ => {
137                    log::warn!("Could not find any mode with width {width} and height {height}");
138                    return;
139                }
140            },
141        };
142        get!().connector_set_mode(
143            self,
144            WireMode {
145                width,
146                height,
147                refresh_millihz,
148            },
149        )
150    }
151
152    /// Returns the available modes of the connector.
153    pub fn modes(self) -> Vec<Mode> {
154        if !self.exists() {
155            return Vec::new();
156        }
157        get!(Vec::new()).connector_modes(self)
158    }
159
160    /// Returns the logical width of the connector.
161    ///
162    /// The returned value will be different from `mode().width()` if the scale is not 1.
163    pub fn width(self) -> i32 {
164        get!().connector_size(self).0
165    }
166
167    /// Returns the logical height of the connector.
168    ///
169    /// The returned value will be different from `mode().height()` if the scale is not 1.
170    pub fn height(self) -> i32 {
171        get!().connector_size(self).1
172    }
173
174    /// Returns the refresh rate in mhz of the current mode of the connector.
175    ///
176    /// This is a shortcut for `mode().refresh_rate()`.
177    pub fn refresh_rate(self) -> u32 {
178        self.mode().refresh_millihz
179    }
180
181    /// Retrieves the position of the output in the global compositor space.
182    pub fn position(self) -> (i32, i32) {
183        if !self.connected() {
184            return (0, 0);
185        }
186        get!().connector_get_position(self)
187    }
188
189    /// Sets the position of the connector in the global compositor space.
190    ///
191    /// `x` and `y` must be non-negative and must not exceed a currently unspecified limit.
192    /// Any reasonable values for `x` and `y` should work.
193    ///
194    /// This function allows the connector to overlap with other connectors, however, such
195    /// configurations are not supported and might result in unexpected behavior.
196    pub fn set_position(self, x: i32, y: i32) {
197        if !self.exists() {
198            log::warn!("set_position called on a connector that does not exist");
199            return;
200        }
201        get!().connector_set_position(self, x, y);
202    }
203
204    /// Enables or disables the connector.
205    ///
206    /// By default, all connectors are enabled.
207    pub fn set_enabled(self, enabled: bool) {
208        if !self.exists() {
209            log::warn!("set_enabled called on a connector that does not exist");
210            return;
211        }
212        get!().connector_set_enabled(self, enabled);
213    }
214
215    /// Sets the transformation to apply to the content of this connector.
216    pub fn set_transform(self, transform: Transform) {
217        if !self.exists() {
218            log::warn!("set_transform called on a connector that does not exist");
219            return;
220        }
221        get!().connector_set_transform(self, transform);
222    }
223
224    pub fn name(self) -> String {
225        if !self.exists() {
226            return String::new();
227        }
228        get!(String::new()).connector_get_name(self)
229    }
230
231    pub fn model(self) -> String {
232        if !self.exists() {
233            return String::new();
234        }
235        get!(String::new()).connector_get_model(self)
236    }
237
238    pub fn manufacturer(self) -> String {
239        if !self.exists() {
240            return String::new();
241        }
242        get!(String::new()).connector_get_manufacturer(self)
243    }
244
245    pub fn serial_number(self) -> String {
246        if !self.exists() {
247            return String::new();
248        }
249        get!(String::new()).connector_get_serial_number(self)
250    }
251
252    /// Sets the VRR mode.
253    pub fn set_vrr_mode(self, mode: VrrMode) {
254        get!().set_vrr_mode(Some(self), mode)
255    }
256
257    /// Sets the VRR cursor refresh rate.
258    ///
259    /// Limits the rate at which cursors are updated on screen when VRR is active.
260    ///
261    /// Setting this to infinity disables the limiter.
262    pub fn set_vrr_cursor_hz(self, hz: f64) {
263        get!().set_vrr_cursor_hz(Some(self), hz)
264    }
265
266    /// Sets the tearing mode.
267    pub fn set_tearing_mode(self, mode: TearingMode) {
268        get!().set_tearing_mode(Some(self), mode)
269    }
270
271    /// Sets the format to use for framebuffers.
272    pub fn set_format(self, format: Format) {
273        get!().connector_set_format(self, format);
274    }
275
276    /// Sets the color space and transfer function of the connector.
277    ///
278    /// By default, the default values are used which usually means sRGB color space with
279    /// sRGB transfer function.
280    ///
281    /// If the output supports it, HDR10 can be enabled by setting the color space to
282    /// BT.2020 and the transfer function to PQ.
283    ///
284    /// Note that some displays might ignore incompatible settings.
285    pub fn set_colors(self, color_space: ColorSpace, transfer_function: TransferFunction) {
286        get!().connector_set_colors(self, color_space, transfer_function);
287    }
288
289    /// Sets the brightness of the output.
290    ///
291    /// By default or when `brightness` is `None`, the brightness depends on the
292    /// transfer function:
293    ///
294    /// - [`TransferFunction::DEFAULT`]: The maximum brightness of the output.
295    /// - [`TransferFunction::PQ`]: 203 cd/m^2.
296    ///
297    /// This should only be used with the PQ transfer function. If the default transfer
298    /// function is used, you should instead calibrate the hardware directly.
299    ///
300    /// This has no effect unless the vulkan renderer is used.
301    pub fn set_brightness(self, brightness: Option<f64>) {
302        get!().connector_set_brightness(self, brightness);
303    }
304
305    /// Get the currently visible/active workspace.
306    ///
307    /// If this connector is not connected, or is there no active workspace, returns a
308    /// workspace whose `exists()` returns false.
309    pub fn active_workspace(self) -> Workspace {
310        get!(Workspace(0)).get_connector_active_workspace(self)
311    }
312
313    /// Get all workspaces on this connector.
314    ///
315    /// If this connector is not connected, returns an empty list.
316    pub fn workspaces(self) -> Vec<Workspace> {
317        get!().get_connector_workspaces(self)
318    }
319}
320
321/// Returns all available DRM devices.
322pub fn drm_devices() -> Vec<DrmDevice> {
323    get!().drm_devices()
324}
325
326/// Sets the callback to be called when a new DRM device appears.
327pub fn on_new_drm_device<F: FnMut(DrmDevice) + 'static>(f: F) {
328    get!().on_new_drm_device(f)
329}
330
331/// Sets the callback to be called when a DRM device is removed.
332pub fn on_drm_device_removed<F: FnMut(DrmDevice) + 'static>(f: F) {
333    get!().on_del_drm_device(f)
334}
335
336/// Sets the callback to be called when a new connector appears.
337pub fn on_new_connector<F: FnMut(Connector) + 'static>(f: F) {
338    get!().on_new_connector(f)
339}
340
341/// Sets the callback to be called when a connector becomes connected to an output device.
342pub fn on_connector_connected<F: FnMut(Connector) + 'static>(f: F) {
343    get!().on_connector_connected(f)
344}
345
346/// Sets the callback to be called when a connector is disconnected from an output device.
347pub fn on_connector_disconnected<F: FnMut(Connector) + 'static>(f: F) {
348    get!().on_connector_disconnected(f)
349}
350
351/// Sets the callback to be called when the graphics of the compositor have been initialized.
352///
353/// This callback is only invoked once during the lifetime of the compositor. This is a good place
354/// to auto start graphical applications.
355pub fn on_graphics_initialized<F: FnOnce() + 'static>(f: F) {
356    get!().on_graphics_initialized(f)
357}
358
359pub fn connectors() -> Vec<Connector> {
360    get!().connectors(None)
361}
362
363/// Returns the connector with the given id.
364///
365/// The linux kernel identifies connectors by a (type, idx) tuple, e.g., `DP-0`.
366/// If the connector does not exist at the time this function is called, a sentinel value is
367/// returned. This can be checked by calling `exists()` on the returned connector.
368///
369/// The `id` argument can either be an explicit tuple, e.g. `(CON_DISPLAY_PORT, 0)`, or a string
370/// that can be parsed to such a tuple, e.g. `"DP-0"`.
371///
372/// The following string prefixes exist:
373///
374/// - `DP`
375/// - `eDP`
376/// - `HDMI-A`
377/// - `HDMI-B`
378/// - `EmbeddedWindow` - this is an implementation detail of the compositor and used if it
379///   runs as an embedded application.
380/// - `VGA`
381/// - `DVI-I`
382/// - `DVI-D`
383/// - `DVI-A`
384/// - `Composite`
385/// - `SVIDEO`
386/// - `LVDS`
387/// - `Component`
388/// - `DIN`
389/// - `TV`
390/// - `Virtual`
391/// - `DSI`
392/// - `DPI`
393/// - `Writeback`
394/// - `SPI`
395/// - `USB`
396pub fn get_connector(id: impl ToConnectorId) -> Connector {
397    let (ty, idx) = match id.to_connector_id() {
398        Ok(id) => id,
399        Err(e) => {
400            log::error!("{}", e);
401            return Connector(0);
402        }
403    };
404    get!(Connector(0)).get_connector(ty, idx)
405}
406
407/// A type that can be converted to a `(ConnectorType, idx)` tuple.
408pub trait ToConnectorId {
409    fn to_connector_id(&self) -> Result<(ConnectorType, u32), String>;
410}
411
412impl ToConnectorId for (ConnectorType, u32) {
413    fn to_connector_id(&self) -> Result<(ConnectorType, u32), String> {
414        Ok(*self)
415    }
416}
417
418impl ToConnectorId for &'_ str {
419    fn to_connector_id(&self) -> Result<(ConnectorType, u32), String> {
420        let pairs = [
421            ("DP-", CON_DISPLAY_PORT),
422            ("eDP-", CON_EDP),
423            ("HDMI-A-", CON_HDMIA),
424            ("HDMI-B-", CON_HDMIB),
425            ("EmbeddedWindow-", CON_EMBEDDED_WINDOW),
426            ("VGA-", CON_VGA),
427            ("DVI-I-", CON_DVII),
428            ("DVI-D-", CON_DVID),
429            ("DVI-A-", CON_DVIA),
430            ("Composite-", CON_COMPOSITE),
431            ("SVIDEO-", CON_SVIDEO),
432            ("LVDS-", CON_LVDS),
433            ("Component-", CON_COMPONENT),
434            ("DIN-", CON_9PIN_DIN),
435            ("TV-", CON_TV),
436            ("Virtual-", CON_VIRTUAL),
437            ("DSI-", CON_DSI),
438            ("DPI-", CON_DPI),
439            ("Writeback-", CON_WRITEBACK),
440            ("SPI-", CON_SPI),
441            ("USB-", CON_USB),
442        ];
443        for (prefix, ty) in pairs {
444            if let Some(suffix) = self.strip_prefix(prefix)
445                && let Ok(idx) = u32::from_str(suffix)
446            {
447                return Ok((ty, idx));
448            }
449        }
450        Err(format!("`{}` is not a valid connector identifier", self))
451    }
452}
453
454/// Module containing all known connector types.
455pub mod connector_type {
456    use serde::{Deserialize, Serialize};
457
458    /// The type of a connector.
459    #[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
460    pub struct ConnectorType(pub u32);
461
462    pub const CON_UNKNOWN: ConnectorType = ConnectorType(0);
463    pub const CON_VGA: ConnectorType = ConnectorType(1);
464    pub const CON_DVII: ConnectorType = ConnectorType(2);
465    pub const CON_DVID: ConnectorType = ConnectorType(3);
466    pub const CON_DVIA: ConnectorType = ConnectorType(4);
467    pub const CON_COMPOSITE: ConnectorType = ConnectorType(5);
468    pub const CON_SVIDEO: ConnectorType = ConnectorType(6);
469    pub const CON_LVDS: ConnectorType = ConnectorType(7);
470    pub const CON_COMPONENT: ConnectorType = ConnectorType(8);
471    pub const CON_9PIN_DIN: ConnectorType = ConnectorType(9);
472    pub const CON_DISPLAY_PORT: ConnectorType = ConnectorType(10);
473    pub const CON_HDMIA: ConnectorType = ConnectorType(11);
474    pub const CON_HDMIB: ConnectorType = ConnectorType(12);
475    pub const CON_TV: ConnectorType = ConnectorType(13);
476    pub const CON_EDP: ConnectorType = ConnectorType(14);
477    pub const CON_VIRTUAL: ConnectorType = ConnectorType(15);
478    pub const CON_DSI: ConnectorType = ConnectorType(16);
479    pub const CON_DPI: ConnectorType = ConnectorType(17);
480    pub const CON_WRITEBACK: ConnectorType = ConnectorType(18);
481    pub const CON_SPI: ConnectorType = ConnectorType(19);
482    pub const CON_USB: ConnectorType = ConnectorType(20);
483    pub const CON_EMBEDDED_WINDOW: ConnectorType = ConnectorType(u32::MAX);
484}
485
486/// A *Direct Rendering Manager* (DRM) device.
487///
488/// It's easiest to think of a DRM device as a graphics card.
489/// There are also DRM devices that are emulated in software but you are unlikely to encounter
490/// those accidentally.
491#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
492pub struct DrmDevice(pub u64);
493
494impl DrmDevice {
495    /// Returns the connectors of this device.
496    pub fn connectors(self) -> Vec<Connector> {
497        get!().connectors(Some(self))
498    }
499
500    /// Returns the devnode of this device.
501    ///
502    /// E.g. `/dev/dri/card0`.
503    pub fn devnode(self) -> String {
504        get!().drm_device_devnode(self)
505    }
506
507    /// Returns the syspath of this device.
508    ///
509    /// E.g. `/sys/devices/pci0000:00/0000:00:03.1/0000:07:00.0`.
510    pub fn syspath(self) -> String {
511        get!().drm_device_syspath(self)
512    }
513
514    /// Returns the vendor of this device.
515    ///
516    /// E.g. `Advanced Micro Devices, Inc. [AMD/ATI]`.
517    pub fn vendor(self) -> String {
518        get!().drm_device_vendor(self)
519    }
520
521    /// Returns the model of this device.
522    ///
523    /// E.g. `Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 570 Armor 8G OC)`.
524    pub fn model(self) -> String {
525        get!().drm_device_model(self)
526    }
527
528    /// Returns the PIC ID of this device.
529    ///
530    /// E.g. `1002:67DF`.
531    pub fn pci_id(self) -> PciId {
532        get!().drm_device_pci_id(self)
533    }
534
535    /// Makes this device the render device.
536    pub fn make_render_device(self) {
537        get!().make_render_device(self);
538    }
539
540    /// Sets the preferred graphics API for this device.
541    ///
542    /// If the API cannot be used, the compositor will try other APIs.
543    pub fn set_gfx_api(self, gfx_api: GfxApi) {
544        get!().set_gfx_api(Some(self), gfx_api);
545    }
546
547    /// Enables or disables direct scanout of client surfaces for this device.
548    pub fn set_direct_scanout_enabled(self, enabled: bool) {
549        get!().set_direct_scanout_enabled(Some(self), enabled);
550    }
551
552    /// Sets the flip margin of this device.
553    ///
554    /// This is duration between the compositor initiating a page flip and the output's
555    /// vblank event. This determines the minimum input latency. The default is 1.5 ms.
556    ///
557    /// Note that if the margin is too small, the compositor will dynamically increase it.
558    pub fn set_flip_margin(self, margin: Duration) {
559        get!().set_flip_margin(self, margin);
560    }
561}
562
563/// A graphics API.
564#[non_exhaustive]
565#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
566pub enum GfxApi {
567    OpenGl,
568    Vulkan,
569}
570
571/// Sets the default graphics API.
572///
573/// If the API cannot be used, the compositor will try other APIs.
574///
575/// This setting can be overwritten per-device with [DrmDevice::set_gfx_api].
576///
577/// This call has no effect on devices that have already been initialized.
578pub fn set_gfx_api(gfx_api: GfxApi) {
579    get!().set_gfx_api(None, gfx_api);
580}
581
582/// Enables or disables direct scanout of client surfaces.
583///
584/// The default is `true`.
585///
586/// This setting can be overwritten per-device with [DrmDevice::set_direct_scanout_enabled].
587pub fn set_direct_scanout_enabled(enabled: bool) {
588    get!().set_direct_scanout_enabled(None, enabled);
589}
590
591/// A transformation.
592#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
593pub enum Transform {
594    /// No transformation.
595    #[default]
596    None,
597    /// Rotate 90 degrees counter-clockwise.
598    Rotate90,
599    /// Rotate 180 degrees counter-clockwise.
600    Rotate180,
601    /// Rotate 270 degrees counter-clockwise.
602    Rotate270,
603    /// Flip around the vertical axis.
604    Flip,
605    /// Flip around the vertical axis, then rotate 90 degrees counter-clockwise.
606    FlipRotate90,
607    /// Flip around the vertical axis, then rotate 180 degrees counter-clockwise.
608    FlipRotate180,
609    /// Flip around the vertical axis, then rotate 270 degrees counter-clockwise.
610    FlipRotate270,
611}
612
613/// The VRR mode of a connector.
614#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
615pub struct VrrMode(pub u32);
616
617impl VrrMode {
618    /// VRR is never enabled.
619    pub const NEVER: Self = Self(0);
620    /// VRR is always enabled.
621    pub const ALWAYS: Self = Self(1);
622    /// VRR is enabled when one or more applications are displayed fullscreen.
623    pub const VARIANT_1: Self = Self(2);
624    /// VRR is enabled when a single application is displayed fullscreen.
625    pub const VARIANT_2: Self = Self(3);
626    /// VRR is enabled when a single game or video is displayed fullscreen.
627    pub const VARIANT_3: Self = Self(4);
628}
629
630/// Sets the default VRR mode.
631///
632/// This setting can be overwritten on a per-connector basis with [Connector::set_vrr_mode].
633pub fn set_vrr_mode(mode: VrrMode) {
634    get!().set_vrr_mode(None, mode)
635}
636
637/// Sets the VRR cursor refresh rate.
638///
639/// Limits the rate at which cursors are updated on screen when VRR is active.
640///
641/// Setting this to infinity disables the limiter.
642///
643/// This setting can be overwritten on a per-connector basis with [Connector::set_vrr_cursor_hz].
644pub fn set_vrr_cursor_hz(hz: f64) {
645    get!().set_vrr_cursor_hz(None, hz)
646}
647
648/// The tearing mode of a connector.
649#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
650pub struct TearingMode(pub u32);
651
652impl TearingMode {
653    /// Tearing is never enabled.
654    pub const NEVER: Self = Self(0);
655    /// Tearing is always enabled.
656    pub const ALWAYS: Self = Self(1);
657    /// Tearing is enabled when one or more applications are displayed fullscreen.
658    pub const VARIANT_1: Self = Self(2);
659    /// Tearing is enabled when a single application is displayed fullscreen.
660    pub const VARIANT_2: Self = Self(3);
661    /// Tearing is enabled when a single application is displayed fullscreen and the
662    /// application has requested tearing.
663    ///
664    /// This is the default.
665    pub const VARIANT_3: Self = Self(4);
666}
667
668/// Sets the default tearing mode.
669///
670/// This setting can be overwritten on a per-connector basis with [Connector::set_tearing_mode].
671pub fn set_tearing_mode(mode: TearingMode) {
672    get!().set_tearing_mode(None, mode)
673}
674
675/// A graphics format.
676#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
677pub struct Format(pub u32);
678
679impl Format {
680    pub const ARGB8888: Self = Self(0);
681    pub const XRGB8888: Self = Self(1);
682    pub const ABGR8888: Self = Self(2);
683    pub const XBGR8888: Self = Self(3);
684    pub const R8: Self = Self(4);
685    pub const GR88: Self = Self(5);
686    pub const RGB888: Self = Self(6);
687    pub const BGR888: Self = Self(7);
688    pub const RGBA4444: Self = Self(8);
689    pub const RGBX4444: Self = Self(9);
690    pub const BGRA4444: Self = Self(10);
691    pub const BGRX4444: Self = Self(11);
692    pub const RGB565: Self = Self(12);
693    pub const BGR565: Self = Self(13);
694    pub const RGBA5551: Self = Self(14);
695    pub const RGBX5551: Self = Self(15);
696    pub const BGRA5551: Self = Self(16);
697    pub const BGRX5551: Self = Self(17);
698    pub const ARGB1555: Self = Self(18);
699    pub const XRGB1555: Self = Self(19);
700    pub const ARGB2101010: Self = Self(20);
701    pub const XRGB2101010: Self = Self(21);
702    pub const ABGR2101010: Self = Self(22);
703    pub const XBGR2101010: Self = Self(23);
704    pub const ABGR16161616: Self = Self(24);
705    pub const XBGR16161616: Self = Self(25);
706    pub const ABGR16161616F: Self = Self(26);
707    pub const XBGR16161616F: Self = Self(27);
708}
709
710/// A color space.
711#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
712pub struct ColorSpace(pub u32);
713
714impl ColorSpace {
715    /// The default color space (usually sRGB).
716    pub const DEFAULT: Self = Self(0);
717    /// The BT.2020 color space.
718    pub const BT2020: Self = Self(1);
719}
720
721/// A transfer function.
722#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
723pub struct TransferFunction(pub u32);
724
725impl TransferFunction {
726    /// The default transfer function (usually sRGB).
727    pub const DEFAULT: Self = Self(0);
728    /// The PQ transfer function.
729    pub const PQ: Self = Self(1);
730}