| 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 | |
| 6 | use i_slint_core::api::PhysicalSize as PhysicalWindowSize; |
| 7 | use i_slint_core::platform::PlatformError; |
| 8 | pub use i_slint_core::software_renderer::SoftwareRenderer; |
| 9 | use i_slint_core::software_renderer::{PremultipliedRgbaColor, RepaintBufferType, TargetPixel}; |
| 10 | use std::rc::Rc; |
| 11 | |
| 12 | use crate::display::RenderingRotation; |
| 13 | |
| 14 | pub 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)] |
| 23 | struct DumbBufferPixelXrgb888(pub u32); |
| 24 | |
| 25 | impl 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 | |
| 38 | impl 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 | |
| 50 | impl 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 | |
| 66 | impl 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 | |
| 88 | impl 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 | |