jay_config/video.rs
1//! Tools for configuring graphics cards and monitors.
2
3use {
4 crate::{
5 _private::WireMode,
6 Direction, 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 EOTF of the connector.
277 ///
278 /// By default, the default values are used which usually means sRGB color space with
279 /// gamma22 EOTF.
280 ///
281 /// If the output supports it, HDR10 can be enabled by setting the color space to
282 /// BT.2020 and the EOTF to PQ.
283 ///
284 /// Note that some displays might ignore incompatible settings.
285 pub fn set_colors(self, color_space: ColorSpace, eotf: Eotf) {
286 get!().connector_set_colors(self, color_space, eotf);
287 }
288
289 /// Sets the space in which blending is performed for this output.
290 ///
291 /// The default is [`BlendSpace::SRGB`]
292 pub fn set_blend_space(self, blend_space: BlendSpace) {
293 get!().connector_set_blend_space(self, blend_space);
294 }
295
296 /// Sets the brightness of the output.
297 ///
298 /// By default or when `brightness` is `None`, the brightness depends on the
299 /// EOTF:
300 ///
301 /// - [`Eotf::DEFAULT`]: The maximum brightness of the output.
302 /// - [`Eotf::PQ`]: 203 cd/m^2.
303 ///
304 /// This should only be used with the PQ transfer function. If the default transfer
305 /// function is used, you should instead calibrate the hardware directly.
306 ///
307 /// When used with the default transfer function, the default brightness is anchored
308 /// at 80 cd/m^2. That is, setting this to 40 cd/m^2 makes everything appear half as
309 /// bright as normal and creates 50% HDR headroom.
310 ///
311 /// This has no effect unless the vulkan renderer is used.
312 pub fn set_brightness(self, brightness: Option<f64>) {
313 get!().connector_set_brightness(self, brightness);
314 }
315
316 /// Get the currently visible/active workspace.
317 ///
318 /// If this connector is not connected, or is there no active workspace, returns a
319 /// workspace whose `exists()` returns false.
320 pub fn active_workspace(self) -> Workspace {
321 get!(Workspace(0)).get_connector_active_workspace(self)
322 }
323
324 /// Get all workspaces on this connector.
325 ///
326 /// If this connector is not connected, returns an empty list.
327 pub fn workspaces(self) -> Vec<Workspace> {
328 get!().get_connector_workspaces(self)
329 }
330
331 /// Find the closest connector in the given direction.
332 ///
333 /// Uses center-to-center distance calculation and prefers outputs better aligned
334 /// with the movement axis.
335 ///
336 /// If no connector exists in the given direction, returns a connector whose
337 /// `exists()` returns false.
338 pub fn connector_in_direction(self, direction: Direction) -> Connector {
339 get!(Connector(0)).get_connector_in_direction(self, direction)
340 }
341
342 /// Configures whether the display primaries are used.
343 ///
344 /// By default, Jay pretends that the display uses sRGB primaries. This is also how
345 /// most other systems behave. In reality, most displays use a much larger gamut. For
346 /// example, they advertise that they support 95% of the DCI-P3 gamut. If the display
347 /// is interpreting colors in their native gamut, then colors will appear more
348 /// saturated than their specification.
349 ///
350 /// If this is set to `true`, Jay assumes that the display uses the primaries
351 /// advertised in its EDID. This might produce more accurate colors while also
352 /// allowing color-managed applications to use the full gamut of the display.
353 ///
354 /// This setting has no effect when the display is explicitly operating in a wide
355 /// color space.
356 ///
357 /// The default is `false`.
358 pub fn set_use_native_gamut(self, use_native_gamut: bool) {
359 get!().connector_set_use_native_gamut(self, use_native_gamut);
360 }
361}
362
363/// Returns all available DRM devices.
364pub fn drm_devices() -> Vec<DrmDevice> {
365 get!().drm_devices()
366}
367
368/// Sets the callback to be called when a new DRM device appears.
369pub fn on_new_drm_device<F: FnMut(DrmDevice) + 'static>(f: F) {
370 get!().on_new_drm_device(f)
371}
372
373/// Sets the callback to be called when a DRM device is removed.
374pub fn on_drm_device_removed<F: FnMut(DrmDevice) + 'static>(f: F) {
375 get!().on_del_drm_device(f)
376}
377
378/// Sets the callback to be called when a new connector appears.
379pub fn on_new_connector<F: FnMut(Connector) + 'static>(f: F) {
380 get!().on_new_connector(f)
381}
382
383/// Sets the callback to be called when a connector becomes connected to an output device.
384pub fn on_connector_connected<F: FnMut(Connector) + 'static>(f: F) {
385 get!().on_connector_connected(f)
386}
387
388/// Sets the callback to be called when a connector is disconnected from an output device.
389pub fn on_connector_disconnected<F: FnMut(Connector) + 'static>(f: F) {
390 get!().on_connector_disconnected(f)
391}
392
393/// Sets the callback to be called when the graphics of the compositor have been initialized.
394///
395/// This callback is only invoked once during the lifetime of the compositor. This is a good place
396/// to auto start graphical applications.
397pub fn on_graphics_initialized<F: FnOnce() + 'static>(f: F) {
398 get!().on_graphics_initialized(f)
399}
400
401pub fn connectors() -> Vec<Connector> {
402 get!().connectors(None)
403}
404
405/// Returns the connector with the given id.
406///
407/// The linux kernel identifies connectors by a (type, idx) tuple, e.g., `DP-0`.
408/// If the connector does not exist at the time this function is called, a sentinel value is
409/// returned. This can be checked by calling `exists()` on the returned connector.
410///
411/// The `id` argument can either be an explicit tuple, e.g. `(CON_DISPLAY_PORT, 0)`, or a string
412/// that can be parsed to such a tuple, e.g. `"DP-0"`.
413///
414/// The following string prefixes exist:
415///
416/// - `DP`
417/// - `eDP`
418/// - `HDMI-A`
419/// - `HDMI-B`
420/// - `EmbeddedWindow` - this is an implementation detail of the compositor and used if it
421/// runs as an embedded application.
422/// - `VGA`
423/// - `DVI-I`
424/// - `DVI-D`
425/// - `DVI-A`
426/// - `Composite`
427/// - `SVIDEO`
428/// - `LVDS`
429/// - `Component`
430/// - `DIN`
431/// - `TV`
432/// - `Virtual`
433/// - `DSI`
434/// - `DPI`
435/// - `Writeback`
436/// - `SPI`
437/// - `USB`
438pub fn get_connector(id: impl ToConnectorId) -> Connector {
439 let (ty, idx) = match id.to_connector_id() {
440 Ok(id) => id,
441 Err(e) => {
442 log::error!("{}", e);
443 return Connector(0);
444 }
445 };
446 get!(Connector(0)).get_connector(ty, idx)
447}
448
449/// A type that can be converted to a `(ConnectorType, idx)` tuple.
450pub trait ToConnectorId {
451 fn to_connector_id(&self) -> Result<(ConnectorType, u32), String>;
452}
453
454impl ToConnectorId for (ConnectorType, u32) {
455 fn to_connector_id(&self) -> Result<(ConnectorType, u32), String> {
456 Ok(*self)
457 }
458}
459
460impl ToConnectorId for &'_ str {
461 fn to_connector_id(&self) -> Result<(ConnectorType, u32), String> {
462 let pairs = [
463 ("DP-", CON_DISPLAY_PORT),
464 ("eDP-", CON_EDP),
465 ("HDMI-A-", CON_HDMIA),
466 ("HDMI-B-", CON_HDMIB),
467 ("EmbeddedWindow-", CON_EMBEDDED_WINDOW),
468 ("VGA-", CON_VGA),
469 ("DVI-I-", CON_DVII),
470 ("DVI-D-", CON_DVID),
471 ("DVI-A-", CON_DVIA),
472 ("Composite-", CON_COMPOSITE),
473 ("SVIDEO-", CON_SVIDEO),
474 ("LVDS-", CON_LVDS),
475 ("Component-", CON_COMPONENT),
476 ("DIN-", CON_9PIN_DIN),
477 ("TV-", CON_TV),
478 ("Virtual-", CON_VIRTUAL),
479 ("DSI-", CON_DSI),
480 ("DPI-", CON_DPI),
481 ("Writeback-", CON_WRITEBACK),
482 ("SPI-", CON_SPI),
483 ("USB-", CON_USB),
484 ];
485 for (prefix, ty) in pairs {
486 if let Some(suffix) = self.strip_prefix(prefix)
487 && let Ok(idx) = u32::from_str(suffix)
488 {
489 return Ok((ty, idx));
490 }
491 }
492 Err(format!("`{}` is not a valid connector identifier", self))
493 }
494}
495
496/// Module containing all known connector types.
497pub mod connector_type {
498 use serde::{Deserialize, Serialize};
499
500 /// The type of a connector.
501 #[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
502 pub struct ConnectorType(pub u32);
503
504 pub const CON_UNKNOWN: ConnectorType = ConnectorType(0);
505 pub const CON_VGA: ConnectorType = ConnectorType(1);
506 pub const CON_DVII: ConnectorType = ConnectorType(2);
507 pub const CON_DVID: ConnectorType = ConnectorType(3);
508 pub const CON_DVIA: ConnectorType = ConnectorType(4);
509 pub const CON_COMPOSITE: ConnectorType = ConnectorType(5);
510 pub const CON_SVIDEO: ConnectorType = ConnectorType(6);
511 pub const CON_LVDS: ConnectorType = ConnectorType(7);
512 pub const CON_COMPONENT: ConnectorType = ConnectorType(8);
513 pub const CON_9PIN_DIN: ConnectorType = ConnectorType(9);
514 pub const CON_DISPLAY_PORT: ConnectorType = ConnectorType(10);
515 pub const CON_HDMIA: ConnectorType = ConnectorType(11);
516 pub const CON_HDMIB: ConnectorType = ConnectorType(12);
517 pub const CON_TV: ConnectorType = ConnectorType(13);
518 pub const CON_EDP: ConnectorType = ConnectorType(14);
519 pub const CON_VIRTUAL: ConnectorType = ConnectorType(15);
520 pub const CON_DSI: ConnectorType = ConnectorType(16);
521 pub const CON_DPI: ConnectorType = ConnectorType(17);
522 pub const CON_WRITEBACK: ConnectorType = ConnectorType(18);
523 pub const CON_SPI: ConnectorType = ConnectorType(19);
524 pub const CON_USB: ConnectorType = ConnectorType(20);
525 pub const CON_EMBEDDED_WINDOW: ConnectorType = ConnectorType(u32::MAX);
526}
527
528/// A *Direct Rendering Manager* (DRM) device.
529///
530/// It's easiest to think of a DRM device as a graphics card.
531/// There are also DRM devices that are emulated in software but you are unlikely to encounter
532/// those accidentally.
533#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
534pub struct DrmDevice(pub u64);
535
536impl DrmDevice {
537 /// Returns the connectors of this device.
538 pub fn connectors(self) -> Vec<Connector> {
539 get!().connectors(Some(self))
540 }
541
542 /// Returns the devnode of this device.
543 ///
544 /// E.g. `/dev/dri/card0`.
545 pub fn devnode(self) -> String {
546 get!().drm_device_devnode(self)
547 }
548
549 /// Returns the syspath of this device.
550 ///
551 /// E.g. `/sys/devices/pci0000:00/0000:00:03.1/0000:07:00.0`.
552 pub fn syspath(self) -> String {
553 get!().drm_device_syspath(self)
554 }
555
556 /// Returns the vendor of this device.
557 ///
558 /// E.g. `Advanced Micro Devices, Inc. [AMD/ATI]`.
559 pub fn vendor(self) -> String {
560 get!().drm_device_vendor(self)
561 }
562
563 /// Returns the model of this device.
564 ///
565 /// E.g. `Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 570 Armor 8G OC)`.
566 pub fn model(self) -> String {
567 get!().drm_device_model(self)
568 }
569
570 /// Returns the PIC ID of this device.
571 ///
572 /// E.g. `1002:67DF`.
573 pub fn pci_id(self) -> PciId {
574 get!().drm_device_pci_id(self)
575 }
576
577 /// Makes this device the render device.
578 pub fn make_render_device(self) {
579 get!().make_render_device(self);
580 }
581
582 /// Sets the preferred graphics API for this device.
583 ///
584 /// If the API cannot be used, the compositor will try other APIs.
585 pub fn set_gfx_api(self, gfx_api: GfxApi) {
586 get!().set_gfx_api(Some(self), gfx_api);
587 }
588
589 /// Enables or disables direct scanout of client surfaces for this device.
590 pub fn set_direct_scanout_enabled(self, enabled: bool) {
591 get!().set_direct_scanout_enabled(Some(self), enabled);
592 }
593
594 /// Sets the flip margin of this device.
595 ///
596 /// This is duration between the compositor initiating a page flip and the output's
597 /// vblank event. This determines the minimum input latency. The default is 1.5 ms.
598 ///
599 /// Note that if the margin is too small, the compositor will dynamically increase it.
600 pub fn set_flip_margin(self, margin: Duration) {
601 get!().set_flip_margin(self, margin);
602 }
603}
604
605/// A graphics API.
606#[non_exhaustive]
607#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
608pub enum GfxApi {
609 OpenGl,
610 Vulkan,
611}
612
613/// Sets the default graphics API.
614///
615/// If the API cannot be used, the compositor will try other APIs.
616///
617/// This setting can be overwritten per-device with [DrmDevice::set_gfx_api].
618///
619/// This call has no effect on devices that have already been initialized.
620pub fn set_gfx_api(gfx_api: GfxApi) {
621 get!().set_gfx_api(None, gfx_api);
622}
623
624/// Enables or disables direct scanout of client surfaces.
625///
626/// The default is `true`.
627///
628/// This setting can be overwritten per-device with [DrmDevice::set_direct_scanout_enabled].
629pub fn set_direct_scanout_enabled(enabled: bool) {
630 get!().set_direct_scanout_enabled(None, enabled);
631}
632
633/// A transformation.
634#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
635pub enum Transform {
636 /// No transformation.
637 #[default]
638 None,
639 /// Rotate 90 degrees counter-clockwise.
640 Rotate90,
641 /// Rotate 180 degrees counter-clockwise.
642 Rotate180,
643 /// Rotate 270 degrees counter-clockwise.
644 Rotate270,
645 /// Flip around the vertical axis.
646 Flip,
647 /// Flip around the vertical axis, then rotate 90 degrees counter-clockwise.
648 FlipRotate90,
649 /// Flip around the vertical axis, then rotate 180 degrees counter-clockwise.
650 FlipRotate180,
651 /// Flip around the vertical axis, then rotate 270 degrees counter-clockwise.
652 FlipRotate270,
653}
654
655/// The VRR mode of a connector.
656#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
657pub struct VrrMode(pub u32);
658
659impl VrrMode {
660 /// VRR is never enabled.
661 pub const NEVER: Self = Self(0);
662 /// VRR is always enabled.
663 pub const ALWAYS: Self = Self(1);
664 /// VRR is enabled when one or more applications are displayed fullscreen.
665 pub const VARIANT_1: Self = Self(2);
666 /// VRR is enabled when a single application is displayed fullscreen.
667 pub const VARIANT_2: Self = Self(3);
668 /// VRR is enabled when a single game or video is displayed fullscreen.
669 pub const VARIANT_3: Self = Self(4);
670}
671
672/// Sets the default VRR mode.
673///
674/// This setting can be overwritten on a per-connector basis with [Connector::set_vrr_mode].
675pub fn set_vrr_mode(mode: VrrMode) {
676 get!().set_vrr_mode(None, mode)
677}
678
679/// Sets the VRR cursor refresh rate.
680///
681/// Limits the rate at which cursors are updated on screen when VRR is active.
682///
683/// Setting this to infinity disables the limiter.
684///
685/// This setting can be overwritten on a per-connector basis with [Connector::set_vrr_cursor_hz].
686pub fn set_vrr_cursor_hz(hz: f64) {
687 get!().set_vrr_cursor_hz(None, hz)
688}
689
690/// The tearing mode of a connector.
691#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
692pub struct TearingMode(pub u32);
693
694impl TearingMode {
695 /// Tearing is never enabled.
696 pub const NEVER: Self = Self(0);
697 /// Tearing is always enabled.
698 pub const ALWAYS: Self = Self(1);
699 /// Tearing is enabled when one or more applications are displayed fullscreen.
700 pub const VARIANT_1: Self = Self(2);
701 /// Tearing is enabled when a single application is displayed fullscreen.
702 pub const VARIANT_2: Self = Self(3);
703 /// Tearing is enabled when a single application is displayed fullscreen and the
704 /// application has requested tearing.
705 ///
706 /// This is the default.
707 pub const VARIANT_3: Self = Self(4);
708}
709
710/// Sets the default tearing mode.
711///
712/// This setting can be overwritten on a per-connector basis with [Connector::set_tearing_mode].
713pub fn set_tearing_mode(mode: TearingMode) {
714 get!().set_tearing_mode(None, mode)
715}
716
717/// A graphics format.
718#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
719pub struct Format(pub u32);
720
721impl Format {
722 pub const ARGB8888: Self = Self(0);
723 pub const XRGB8888: Self = Self(1);
724 pub const ABGR8888: Self = Self(2);
725 pub const XBGR8888: Self = Self(3);
726 pub const R8: Self = Self(4);
727 pub const GR88: Self = Self(5);
728 pub const RGB888: Self = Self(6);
729 pub const BGR888: Self = Self(7);
730 pub const RGBA4444: Self = Self(8);
731 pub const RGBX4444: Self = Self(9);
732 pub const BGRA4444: Self = Self(10);
733 pub const BGRX4444: Self = Self(11);
734 pub const RGB565: Self = Self(12);
735 pub const BGR565: Self = Self(13);
736 pub const RGBA5551: Self = Self(14);
737 pub const RGBX5551: Self = Self(15);
738 pub const BGRA5551: Self = Self(16);
739 pub const BGRX5551: Self = Self(17);
740 pub const ARGB1555: Self = Self(18);
741 pub const XRGB1555: Self = Self(19);
742 pub const ARGB2101010: Self = Self(20);
743 pub const XRGB2101010: Self = Self(21);
744 pub const ABGR2101010: Self = Self(22);
745 pub const XBGR2101010: Self = Self(23);
746 pub const ABGR16161616: Self = Self(24);
747 pub const XBGR16161616: Self = Self(25);
748 pub const ABGR16161616F: Self = Self(26);
749 pub const XBGR16161616F: Self = Self(27);
750 pub const BGR161616: Self = Self(28);
751 pub const R16F: Self = Self(29);
752 pub const GR1616F: Self = Self(30);
753 pub const BGR161616F: Self = Self(31);
754 pub const R32F: Self = Self(32);
755 pub const GR3232F: Self = Self(33);
756 pub const BGR323232F: Self = Self(34);
757 pub const ABGR32323232F: Self = Self(35);
758}
759
760/// A color space.
761#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
762pub struct ColorSpace(pub u32);
763
764impl ColorSpace {
765 /// The default color space (usually sRGB).
766 pub const DEFAULT: Self = Self(0);
767 /// The BT.2020 color space.
768 pub const BT2020: Self = Self(1);
769}
770
771/// An electro-optical transfer function (EOTF).
772#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
773pub struct Eotf(pub u32);
774
775#[deprecated = "use the Eotf type instead"]
776pub type TransferFunction = Eotf;
777
778impl Eotf {
779 /// The default EOTF (usually gamma22).
780 pub const DEFAULT: Self = Self(0);
781 /// The PQ EOTF.
782 pub const PQ: Self = Self(1);
783}
784
785/// A space in which color blending is performed.
786#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
787pub struct BlendSpace(pub u32);
788
789impl BlendSpace {
790 /// The sRGB blend space with sRGB primaries and gamma22 transfer function. This is
791 /// the classic desktop blend space.
792 pub const SRGB: Self = Self(0);
793 /// The linear blend space performs blending in linear space, which is more physically
794 /// correct but leads to much lighter output when blending light and dark colors.
795 pub const LINEAR: Self = Self(1);
796}