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
4//! Delegate the rendering to the [`i_slint_core::software_renderer::SoftwareRenderer`]
5
6use i_slint_core::api::PhysicalSize as PhysicalWindowSize;
7use i_slint_core::platform::PlatformError;
8pub use i_slint_core::software_renderer::SoftwareRenderer;
9use i_slint_core::software_renderer::{PremultipliedRgbaColor, RepaintBufferType, TargetPixel};
10use std::rc::Rc;
11
12use crate::display::RenderingRotation;
13
14pub struct SoftwareRendererAdapter {
15 renderer: SoftwareRenderer,
16 display: Rc<dyn crate::display::swdisplay::SoftwareBufferDisplay>,
17 presenter: Rc<dyn crate::display::Presenter>,
18 size: PhysicalWindowSize,
19}
20
21#[repr(transparent)]
22#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
23struct DumbBufferPixelXrgb888(pub u32);
24
25impl From<DumbBufferPixelXrgb888> for PremultipliedRgbaColor {
26 #[inline]
27 fn from(pixel: DumbBufferPixelXrgb888) -> Self {
28 let v: u32 = pixel.0;
29 PremultipliedRgbaColor {
30 red: (v >> 16) as u8,
31 green: (v >> 8) as u8,
32 blue: (v >> 0) as u8,
33 alpha: (v >> 24) as u8,
34 }
35 }
36}
37
38impl From<PremultipliedRgbaColor> for DumbBufferPixelXrgb888 {
39 #[inline]
40 fn from(pixel: PremultipliedRgbaColor) -> Self {
41 Self(
42 (pixel.alpha as u32) << 24
43 | ((pixel.red as u32) << 16)
44 | ((pixel.green as u32) << 8)
45 | (pixel.blue as u32),
46 )
47 }
48}
49
50impl TargetPixel for DumbBufferPixelXrgb888 {
51 fn blend(&mut self, color: PremultipliedRgbaColor) {
52 let mut x: PremultipliedRgbaColor = PremultipliedRgbaColor::from(*self);
53 x.blend(color);
54 *self = x.into();
55 }
56
57 fn from_rgb(r: u8, g: u8, b: u8) -> Self {
58 Self(0xff000000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32))
59 }
60
61 fn background() -> Self {
62 Self(0)
63 }
64}
65
66impl SoftwareRendererAdapter {
67 pub fn new(
68 device_opener: &crate::DeviceOpener,
69 ) -> Result<Box<dyn crate::fullscreenwindowadapter::FullscreenRenderer>, PlatformError> {
70 let display: Rc = crate::display::swdisplay::new(device_opener)?;
71
72 let (width: u32, height: u32) = display.size();
73 let size: PhysicalSize = i_slint_core::api::PhysicalSize::new(width, height);
74
75 let renderer: Box = Box::new(Self {
76 renderer: SoftwareRenderer::new(),
77 display: display.clone(),
78 presenter: display.as_presenter(),
79 size,
80 });
81
82 eprintln!("Using Software renderer");
83
84 Ok(renderer)
85 }
86}
87
88impl crate::fullscreenwindowadapter::FullscreenRenderer for SoftwareRendererAdapter {
89 fn as_core_renderer(&self) -> &dyn i_slint_core::renderer::Renderer {
90 &self.renderer
91 }
92
93 fn render_and_present(
94 &self,
95 rotation: RenderingRotation,
96 _draw_mouse_cursor_callback: &dyn Fn(&mut dyn i_slint_core::item_rendering::ItemRenderer),
97 ) -> Result<(), PlatformError> {
98 self.display.map_back_buffer(&mut |pixels, age, format| {
99 self.renderer.set_repaint_buffer_type(match age {
100 1 => RepaintBufferType::ReusedBuffer,
101 2 => RepaintBufferType::SwappedBuffers,
102 _ => RepaintBufferType::NewBuffer,
103 });
104
105 self.renderer.set_rendering_rotation(match rotation {
106 RenderingRotation::NoRotation => {
107 i_slint_core::software_renderer::RenderingRotation::NoRotation
108 }
109 RenderingRotation::Rotate90 => {
110 i_slint_core::software_renderer::RenderingRotation::Rotate90
111 }
112 RenderingRotation::Rotate180 => {
113 i_slint_core::software_renderer::RenderingRotation::Rotate180
114 }
115 RenderingRotation::Rotate270 => {
116 i_slint_core::software_renderer::RenderingRotation::Rotate270
117 }
118 });
119
120 match format {
121 drm::buffer::DrmFourcc::Xrgb8888 => {
122 let buffer: &mut [DumbBufferPixelXrgb888] =
123 bytemuck::cast_slice_mut(pixels.as_mut());
124 self.renderer.render(buffer, self.size.width as usize);
125 }
126 drm::buffer::DrmFourcc::Rgb565 => {
127 let buffer: &mut [i_slint_core::software_renderer::Rgb565Pixel] =
128 bytemuck::cast_slice_mut(pixels.as_mut());
129 self.renderer.render(buffer, self.size.width as usize);
130 }
131 _ => {
132 return Err(format!(
133 "Unsupported frame buffer format {format} used with software renderer"
134 )
135 .into())
136 }
137 }
138
139 Ok(())
140 })?;
141 self.presenter.present()?;
142 Ok(())
143 }
144
145 fn size(&self) -> i_slint_core::api::PhysicalSize {
146 self.size
147 }
148}
149