i_slint_backend_linuxkms/
display.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4use i_slint_core::api::PhysicalSize;
5
6#[allow(unused)]
7pub trait Presenter {
8    // Present updated front-buffer to the screen
9    fn present(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
10}
11
12#[cfg(any(feature = "renderer-skia-opengl", feature = "renderer-femtovg"))]
13pub mod gbmdisplay;
14#[cfg(any(
15    feature = "renderer-skia-opengl",
16    feature = "renderer-skia-vulkan",
17    feature = "renderer-software"
18))]
19pub mod swdisplay;
20#[cfg(feature = "renderer-skia-vulkan")]
21pub mod vulkandisplay;
22
23/// This enum describes the way the output is supposed to be rotated to simulate
24/// a screen rotation. This is implemented entirely inside the actual renderer.
25#[non_exhaustive]
26#[derive(Default, Copy, Clone, Eq, PartialEq, Debug)]
27pub enum RenderingRotation {
28    /// No rotation
29    #[default]
30    NoRotation,
31    /// Rotate 90° to the right
32    Rotate90,
33    /// 180° rotation (upside-down)
34    Rotate180,
35    /// Rotate 90° to the left
36    Rotate270,
37}
38
39impl TryFrom<&str> for RenderingRotation {
40    type Error = String;
41
42    fn try_from(value: &str) -> Result<Self, Self::Error> {
43        let angle: usize = value.parse().map_err(|_| {
44            format!("Invalid value for rotation. Must be unsigned integral, found {value}")
45        })?;
46        Ok(match angle {
47            0 => Self::NoRotation,
48            90 => Self::Rotate90,
49            180 => Self::Rotate180,
50            270 => Self::Rotate270,
51            _ => {
52                return Err(format!(
53                    "Invalid value for rotation. Must be one of 0, 90, 180, or 270"
54                ))
55            }
56        })
57    }
58}
59
60impl RenderingRotation {
61    pub fn screen_size_to_rotated_window_size(&self, screen_size: PhysicalSize) -> PhysicalSize {
62        match self {
63            RenderingRotation::NoRotation | RenderingRotation::Rotate180 => screen_size,
64            RenderingRotation::Rotate90 | RenderingRotation::Rotate270 => {
65                PhysicalSize::new(screen_size.height, screen_size.width)
66            }
67        }
68    }
69
70    pub fn degrees(&self) -> f32 {
71        match self {
72            RenderingRotation::NoRotation => 0.,
73            RenderingRotation::Rotate90 => 90.,
74            RenderingRotation::Rotate180 => 180.,
75            RenderingRotation::Rotate270 => 270.,
76        }
77    }
78
79    #[allow(unused)]
80    pub fn translation_after_rotation(&self, screen_size: PhysicalSize) -> (f32, f32) {
81        match self {
82            RenderingRotation::NoRotation => (0., 0.),
83            RenderingRotation::Rotate90 => (0., -(screen_size.width as f32)),
84            RenderingRotation::Rotate180 => {
85                (-(screen_size.width as f32), -(screen_size.height as f32))
86            }
87            RenderingRotation::Rotate270 => (-(screen_size.height as f32), 0.),
88        }
89    }
90}
91
92#[cfg(any(
93    feature = "renderer-skia-vulkan",
94    feature = "renderer-software",
95    feature = "renderer-skia-opengl"
96))]
97pub(crate) mod noop_presenter {
98    use std::sync::Arc;
99
100    // Used when the underlying renderer/display takes care of the presentation to the display
101    // and (hopefully) implements vsync.
102    pub(crate) struct NoopPresenter {}
103
104    impl NoopPresenter {
105        pub(crate) fn new() -> Arc<Self> {
106            Arc::new(Self {})
107        }
108    }
109
110    impl crate::display::Presenter for NoopPresenter {
111        fn present(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
112            Ok(())
113        }
114    }
115}