Skip to main content

jay_config/
video.rs

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