-
Notifications
You must be signed in to change notification settings - Fork 535
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
LinuxKMS: Add support for the Slint software renderer #4334
Changes from 4 commits
21e5b6f
0bd65a9
ab82ece
1b95249
d71821d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,8 +8,9 @@ use std::pin::Pin; | |
use std::rc::Rc; | ||
|
||
use i_slint_core::api::{LogicalPosition, PhysicalSize as PhysicalWindowSize}; | ||
use i_slint_core::graphics::Image; | ||
use i_slint_core::graphics::{euclid, Image}; | ||
use i_slint_core::item_rendering::ItemRenderer; | ||
use i_slint_core::lengths::LogicalRect; | ||
use i_slint_core::platform::WindowEvent; | ||
use i_slint_core::slice::Slice; | ||
use i_slint_core::Property; | ||
|
@@ -108,13 +109,19 @@ impl FullscreenWindowAdapter { | |
self.rotation, | ||
&|item_renderer| { | ||
if let Some(mouse_position) = mouse_position.get() { | ||
let cursor_image = mouse_cursor_image(); | ||
item_renderer.save_state(); | ||
item_renderer.translate( | ||
i_slint_core::lengths::logical_point_from_api(mouse_position) | ||
.to_vector(), | ||
); | ||
item_renderer.draw_image_direct(mouse_cursor_image()); | ||
item_renderer.restore_state(); | ||
let cursor_rect = LogicalRect::new( | ||
euclid::point2(mouse_position.x, mouse_position.y), | ||
euclid::Size2D::from_untyped(cursor_image.size().cast()), | ||
); | ||
self.renderer.as_core_renderer().mark_dirty_region(cursor_rect.into()); | ||
Comment on lines
+120
to
+124
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is harmless, but I can also remove it if desired. It's a no-op as there won't be a mouse with the sw renderer, and otherwise mark_dirty_region is a no-op with the GPU renderers. But for strictly speaking this is the correct thing to do while we have the code for this approach here (to be removed later with the image we discussed). |
||
} | ||
}, | ||
Box::new({ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
// Copyright © SixtyFPS GmbH <info@slint.dev> | ||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 | ||
|
||
//! Delegate the rendering to the [`i_slint_core::software_renderer::SoftwareRenderer`] | ||
|
||
use i_slint_core::api::PhysicalSize as PhysicalWindowSize; | ||
use i_slint_core::platform::PlatformError; | ||
pub use i_slint_core::software_renderer::SoftwareRenderer; | ||
use i_slint_core::software_renderer::{PremultipliedRgbaColor, RepaintBufferType, TargetPixel}; | ||
use std::rc::Rc; | ||
|
||
use crate::display::{Presenter, RenderingRotation}; | ||
use crate::drmoutput::DrmOutput; | ||
|
||
pub struct SoftwareRendererAdapter { | ||
renderer: SoftwareRenderer, | ||
display: Rc<crate::display::swdisplay::SoftwareBufferDisplay>, | ||
size: PhysicalWindowSize, | ||
} | ||
|
||
#[repr(transparent)] | ||
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] | ||
struct DumbBufferPixel(pub u32); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why can't the existing argb8pixel be used? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see an argb8pixel in our code base. I see these:
This is basically the same as in commit 46ec787 . If you have a suggestion where it could be shared, then I'm all for it. Should I introduce a "softbuffer-pixel" feature in i-slint-core perhaps? I wonder in which module to place it. |
||
|
||
impl From<DumbBufferPixel> for PremultipliedRgbaColor { | ||
#[inline] | ||
fn from(pixel: DumbBufferPixel) -> Self { | ||
let v = pixel.0; | ||
PremultipliedRgbaColor { | ||
red: (v >> 16) as u8, | ||
green: (v >> 8) as u8, | ||
blue: (v >> 0) as u8, | ||
alpha: (v >> 24) as u8, | ||
} | ||
} | ||
} | ||
|
||
impl From<PremultipliedRgbaColor> for DumbBufferPixel { | ||
#[inline] | ||
fn from(pixel: PremultipliedRgbaColor) -> Self { | ||
Self( | ||
(pixel.alpha as u32) << 24 | ||
| ((pixel.red as u32) << 16) | ||
| ((pixel.green as u32) << 8) | ||
| (pixel.blue as u32), | ||
) | ||
} | ||
} | ||
|
||
impl TargetPixel for DumbBufferPixel { | ||
fn blend(&mut self, color: PremultipliedRgbaColor) { | ||
let mut x = PremultipliedRgbaColor::from(*self); | ||
x.blend(color); | ||
*self = x.into(); | ||
} | ||
|
||
fn from_rgb(r: u8, g: u8, b: u8) -> Self { | ||
Self(0xff000000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32)) | ||
} | ||
|
||
fn background() -> Self { | ||
Self(0) | ||
} | ||
} | ||
|
||
impl SoftwareRendererAdapter { | ||
pub fn new( | ||
device_opener: &crate::DeviceOpener, | ||
) -> Result<Box<dyn crate::fullscreenwindowadapter::FullscreenRenderer>, PlatformError> { | ||
let drm_output = DrmOutput::new(device_opener)?; | ||
let display = Rc::new(crate::display::swdisplay::SoftwareBufferDisplay::new(drm_output)?); | ||
|
||
let (width, height) = display.drm_output.size(); | ||
let size = i_slint_core::api::PhysicalSize::new(width, height); | ||
|
||
let renderer = Box::new(Self { renderer: SoftwareRenderer::new(), display, size }); | ||
|
||
eprintln!("Using Software renderer"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. leftover? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Intentional , all the renderers currently print when they’re in use. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok. Althoug they probably shouldn't in a production binary. (it would be shown with the FPS env variable, right?) |
||
|
||
Ok(renderer) | ||
} | ||
} | ||
|
||
impl crate::fullscreenwindowadapter::FullscreenRenderer for SoftwareRendererAdapter { | ||
fn as_core_renderer(&self) -> &dyn i_slint_core::renderer::Renderer { | ||
&self.renderer | ||
} | ||
|
||
fn is_ready_to_present(&self) -> bool { | ||
self.display.drm_output.is_ready_to_present() | ||
} | ||
|
||
fn render_and_present( | ||
&self, | ||
rotation: RenderingRotation, | ||
_draw_mouse_cursor_callback: &dyn Fn(&mut dyn i_slint_core::item_rendering::ItemRenderer), | ||
ready_for_next_animation_frame: Box<dyn FnOnce()>, | ||
) -> Result<(), PlatformError> { | ||
self.display.map_back_buffer(&mut |mut pixels, age| { | ||
self.renderer.set_repaint_buffer_type(match age { | ||
1 => RepaintBufferType::ReusedBuffer, | ||
2 => RepaintBufferType::SwappedBuffers, | ||
_ => RepaintBufferType::NewBuffer, | ||
}); | ||
|
||
self.renderer.set_rendering_rotation(match rotation { | ||
RenderingRotation::NoRotation => { | ||
i_slint_core::software_renderer::RenderingRotation::NoRotation | ||
} | ||
RenderingRotation::Rotate90 => { | ||
i_slint_core::software_renderer::RenderingRotation::Rotate90 | ||
} | ||
RenderingRotation::Rotate180 => { | ||
i_slint_core::software_renderer::RenderingRotation::Rotate180 | ||
} | ||
RenderingRotation::Rotate270 => { | ||
i_slint_core::software_renderer::RenderingRotation::Rotate270 | ||
} | ||
}); | ||
|
||
let buffer: &mut [DumbBufferPixel] = bytemuck::cast_slice_mut(pixels.as_mut()); | ||
self.renderer.render(buffer, self.size.width as usize); | ||
|
||
Ok(()) | ||
})?; | ||
self.display.present_with_next_frame_callback(ready_for_next_animation_frame)?; | ||
Ok(()) | ||
} | ||
|
||
fn size(&self) -> i_slint_core::api::PhysicalSize { | ||
self.size | ||
} | ||
|
||
fn register_page_flip_handler( | ||
&self, | ||
event_loop_handle: crate::calloop_backend::EventLoopHandle, | ||
) -> Result<(), PlatformError> { | ||
self.display.drm_output.register_page_flip_handler(event_loop_handle) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the missing cursor be documented, perhaps?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, I'll add that.