Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stabilize full-screen rotation in the renderer #5372

Closed
ogoffart opened this issue Jun 8, 2024 · 1 comment · Fixed by #5377
Closed

Stabilize full-screen rotation in the renderer #5372

ogoffart opened this issue Jun 8, 2024 · 1 comment · Fixed by #5377
Labels
a:renderer-software Software Renderer (mO,bF) api Changes or additions to APIs rfc Request for comments: proposals for changes

Comments

@ogoffart
Copy link
Member

ogoffart commented Jun 8, 2024

We've had an implementation of full screen rotation in the software renderer since Slint 1.3 (IIRC) but it remained experimental.
It's time to stabilize it.

Use cases

  • Have the screen rotated when the shared buffer is in shared memory and there is no hardware rotation
  • On low-level hardware with line by line renderer, it is possible to instruct the renderer to render from left to right or right to left or bottom to top, so that it is possible to simulate a transition between screen in the right direction.

Current API

  • Rust RenderingRotation enum

/// This enum describes the rotation that should be applied to the contents rendered by the software renderer.
///
/// Argument to be passed in [`SoftwareRenderer::set_rendering_rotation`].
#[non_exhaustive]
#[derive(Default, Copy, Clone, Eq, PartialEq, Debug)]
pub enum RenderingRotation {
/// No rotation
#[default]
NoRotation,
/// Rotate 90° to the right
Rotate90,
/// 180° rotation (upside-down)
Rotate180,
/// Rotate 90° to the left
Rotate270,
}

  • Getter an setter in SoftwareRenderer
impl SoftwareRenderer {
    /// Set how the window need to be rotated in the buffer.
    ///
    /// This is typically used to implement screen rotation in software
    pub fn set_rendering_rotation(&self, rotation: RenderingRotation) { ... }

    /// Return the current rotation. See [`Self::set_rendering_rotation()`]
    pub fn rendering_rotation(&self) -> RenderingRotation { ... }
}
  • Similar API in C++ (in class SoftwareRenderer)

/// This enum describes the rotation that is applied to the buffer when rendering.
/// To be used in set_rendering_rotation()
enum class RenderingRotation {
/// No rotation
NoRotation = 0,
/// Rotate 90° to the left
Rotate90 = 90,
/// 180° rotation (upside-down)
Rotate180 = 180,
/// Rotate 90° to the right
Rotate270 = 270,
};
/// Set how the window need to be rotated in the buffer.
///
/// This is typically used to implement screen rotation in software
void set_rendering_rotation(RenderingRotation rotation)
{

  • The FemtoVG and Skia renderer also have support for rotation, but it's different:

pub trait FemtoVGRendererExt {
fn render_transformed_with_post_callback(
&self,
rotation_angle_degrees: f32,
translation: (f32, f32),
surface_size: i_slint_core::api::PhysicalSize,
post_render_cb: Option<&dyn Fn(&mut dyn ItemRenderer)>,
) -> Result<(), i_slint_core::platform::PlatformError>;

Options

We could stabilize the API as is. But the questions are:

Should the rotation be a property of the Window instead of the Renderer?

It would make sense to have that a property of the Window. In that case, the physical size might be the transposed of the logical size. But this also make the conversion of a physical point to logical point more difficult for the event handler and such as they need to know not only the scale factor, but the rotation and size of the window.

Right now with the current experimental API, it's impossible to implement rotation in the winit back-end for example, because the physical size of the window has to match what's reported to the window manager. and therefore that's the size of the buffer. But the Slint's width and height are linked to the window's logical size and must be transposed.

A proposed API would be:

  • A WindowEvent to rotate the window
  • The conversion between physical and logical size/position needs to take a window reference instead of a scale factor.
  • A getter in the window for the rotation

Then the renderer would use the window rotation when rendering.

This is a bit more complicated than the current implementation (bugger API surface change).
The question is whether this is something we want to support (rotation on backend that have a window manager and need to also rotate between physical and logical window coordinate). Every use is limited for backend with full screen rotation where the window don't really play a role.

Should the rotation be an option given in an overload to the render function instead of as a state in the renderer?

Since we need to give the right kind of buffer to the render function (height×width instead of width×height), it is really a property of the render function rather than a state in the renderer. itself. We could have an overload with a RenderOptions struct (but not sure what else would go in there. buffer age? extra dirty region? extra clip?). Or a render_with_rotation
The statefull API means we need to use interior mutability and that the user must ensure that the right state when doing rotation. But it is otherwise easy to use.

Does that mean we'll also do the same for femtovg and skia if we stabilize that?

@ogoffart ogoffart added rfc Request for comments: proposals for changes a:renderer-software Software Renderer (mO,bF) api Changes or additions to APIs labels Jun 8, 2024
@tronical
Copy link
Member

We discussed this and concluded that we'll keep the RenderingRotation enum and in the software renderer keep the set_rendering_rotation()/rendering_rotation() functions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a:renderer-software Software Renderer (mO,bF) api Changes or additions to APIs rfc Request for comments: proposals for changes
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants