From de48583b2e516958ec362fce6ace4dd93aefa2ba Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Mon, 5 Aug 2024 12:16:04 -0700 Subject: [PATCH 1/2] TODO Remove `Send` bound from `MemoryRenderBuffer` --- src/backend/renderer/element/memory.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/renderer/element/memory.rs b/src/backend/renderer/element/memory.rs index f3d508e9e3ed..b8b80fffd443 100644 --- a/src/backend/renderer/element/memory.rs +++ b/src/backend/renderer/element/memory.rs @@ -327,7 +327,7 @@ struct MemoryRenderBufferInner { transform: Transform, opaque_regions: Option>>, damage_bag: DamageBag, - textures: HashMap<(TypeId, usize), Box>, + textures: HashMap<(TypeId, usize), Box>, renderer_seen: HashMap<(TypeId, usize), CommitCounter>, } @@ -414,7 +414,7 @@ impl MemoryRenderBufferInner { ) -> Result<::TextureId, ::Error> where R: Renderer + ImportMem, - ::TextureId: Send + Clone + 'static, + ::TextureId: Clone + 'static, { let texture_id = (TypeId::of::<::TextureId>(), renderer.id()); let current_commit = self.damage_bag.current_commit(); @@ -596,7 +596,7 @@ impl MemoryRenderBufferRenderElement { ) -> Result::Error> where R: ImportMem, - ::TextureId: Send + Clone + 'static, + ::TextureId: Clone + 'static, { let mut inner = buffer.inner.lock().unwrap(); let texture = inner.import_texture(renderer)?; From 413f291b331348f6ee0278149a1212130735961d Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Mon, 5 Aug 2024 14:56:42 -0700 Subject: [PATCH 2/2] WIP anvil/udev: Dynamic support for pixman rendererer --- anvil/src/drawing.rs | 2 +- anvil/src/udev.rs | 265 ++++++++++++++++++++++++++++++------------- 2 files changed, 184 insertions(+), 83 deletions(-) diff --git a/anvil/src/drawing.rs b/anvil/src/drawing.rs index 0fa62201ed02..9115b23b4b22 100644 --- a/anvil/src/drawing.rs +++ b/anvil/src/drawing.rs @@ -66,7 +66,7 @@ impl std::fmt::Debug for PointerRenderElement { } } -impl AsRenderElements for PointerElement +impl AsRenderElements for PointerElement where R: Renderer + ImportAll + ImportMem, { diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index ee7c2c3f54d5..500257acfe9f 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -18,7 +18,7 @@ use smithay::backend::drm::compositor::PrimaryPlaneElement; #[cfg(feature = "egl")] use smithay::backend::renderer::ImportEgl; #[cfg(feature = "debug")] -use smithay::backend::renderer::{multigpu::MultiTexture, ImportMem}; +use smithay::backend::renderer::{multigpu::MultiTexture, pixman::PixmanTexture}; use smithay::{ backend::{ allocator::{ @@ -39,8 +39,9 @@ use smithay::{ element::{memory::MemoryRenderBuffer, AsRenderElements, RenderElement, RenderElementStates}, gles::{GlesRenderer, GlesTexture}, multigpu::{gbm::GbmGlesBackend, GpuManager, MultiRenderer}, + pixman::{PixmanRenderBuffer, PixmanRenderer}, sync::SyncPoint, - Bind, DebugFlags, ExportMem, ImportDma, ImportMemWl, Offscreen, Renderer, + Bind, DebugFlags, ExportMem, ImportDma, ImportDmaWl, ImportMem, ImportMemWl, Offscreen, Renderer, }, session::{ libseat::{self, LibSeatSession}, @@ -107,25 +108,58 @@ const SUPPORTED_FORMATS: &[Fourcc] = &[ ]; const SUPPORTED_FORMATS_8BIT_ONLY: &[Fourcc] = &[Fourcc::Abgr8888, Fourcc::Argb8888]; -type UdevRenderer<'a> = MultiRenderer< +type GlMultiRenderer<'a> = MultiRenderer< 'a, 'a, GbmGlesBackend, GbmGlesBackend, >; +enum RendererRef<'a> { + Multi(GlMultiRenderer<'a>), + Pixman(&'a mut PixmanRenderer), +} + #[derive(Debug, PartialEq)] struct UdevOutputId { device_id: DrmNode, crtc: crtc::Handle, } +enum Renderers { + Gpus(GpuManager>), + Pixman(PixmanRenderer), +} + +impl Renderers { + fn renderer( + &mut self, + render_device: &DrmNode, + target_device: &DrmNode, + copy_format: Fourcc, + ) -> RendererRef<'_> { + match self { + Renderers::Gpus(gpus) => { + RendererRef::Multi(gpus.renderer(render_device, target_device, copy_format).unwrap()) + } + Renderers::Pixman(renderer) => RendererRef::Pixman(renderer), + } + } + + fn single_renderer(&mut self, device: &DrmNode) -> RendererRef<'_> { + match self { + Renderers::Gpus(gpus) => RendererRef::Multi(gpus.single_renderer(device).unwrap()), + Renderers::Pixman(renderer) => RendererRef::Pixman(renderer), + } + } +} + pub struct UdevData { pub session: LibSeatSession, dh: DisplayHandle, dmabuf_state: Option<(DmabufState, DmabufGlobal)>, primary_gpu: DrmNode, - gpus: GpuManager>, + renderers: Renderers, backends: HashMap, pointer_images: Vec<(xcursor::parser::Image, MemoryRenderBuffer)>, pointer_element: PointerElement, @@ -160,13 +194,15 @@ impl DmabufHandler for AnvilState { } fn dmabuf_imported(&mut self, _global: &DmabufGlobal, dmabuf: Dmabuf, notifier: ImportNotifier) { - if self + let renderer = self .backend_data - .gpus - .single_renderer(&self.backend_data.primary_gpu) - .and_then(|mut renderer| renderer.import_dmabuf(&dmabuf, None)) - .is_ok() - { + .renderers + .single_renderer(&self.backend_data.primary_gpu); + let res = match renderer { + RendererRef::Multi(mut renderer) => renderer.import_dmabuf(&dmabuf, None).is_ok(), + RendererRef::Pixman(renderer) => renderer.import_dmabuf(&dmabuf, None).is_ok(), + }; + if res { dmabuf.set_node(self.backend_data.primary_gpu); let _ = notifier.successful::>(); } else { @@ -195,8 +231,10 @@ impl Backend for UdevData { } fn early_import(&mut self, surface: &wl_surface::WlSurface) { - if let Err(err) = self.gpus.early_import(self.primary_gpu, surface) { - warn!("Early buffer import failed: {}", err); + if let Renderers::Gpus(gpus) = &mut self.renderers { + if let Err(err) = gpus.early_import(self.primary_gpu, surface) { + warn!("Early buffer import failed: {}", err); + } } } @@ -242,14 +280,20 @@ pub fn run_udev() { }; info!("Using {} as primary gpu.", primary_gpu); - let gpus = GpuManager::new(GbmGlesBackend::with_context_priority(ContextPriority::High)).unwrap(); + let renderers = if std::env::var("ANVIL_USE_PIXMAN").is_ok() { + Renderers::Pixman(PixmanRenderer::new().unwrap()) + } else { + Renderers::Gpus( + GpuManager::new(GbmGlesBackend::with_context_priority(ContextPriority::High)).unwrap(), + ) + }; let data = UdevData { dh: display_handle.clone(), dmabuf_state: None, session, primary_gpu, - gpus, + renderers, backends: HashMap::new(), pointer_image: crate::cursor::Cursor::load(), pointer_images: Vec::new(), @@ -365,17 +409,15 @@ pub fn run_udev() { error!("Skipping device {device_id}: {err}"); } } - state.shm_state.update_formats( - state - .backend_data - .gpus - .single_renderer(&primary_gpu) - .unwrap() - .shm_formats(), - ); + + let shm_formats = match state.backend_data.renderers.single_renderer(&primary_gpu) { + RendererRef::Multi(renderer) => renderer.shm_formats(), + RendererRef::Pixman(renderer) => renderer.shm_formats(), + }; + state.shm_state.update_formats(shm_formats); #[cfg_attr(not(feature = "egl"), allow(unused_mut))] - let mut renderer = state.backend_data.gpus.single_renderer(&primary_gpu).unwrap(); + let mut renderer = state.backend_data.renderers.single_renderer(&primary_gpu); #[cfg(feature = "debug")] { @@ -383,7 +425,23 @@ pub fn run_udev() { image::ImageReader::with_format(std::io::Cursor::new(FPS_NUMBERS_PNG), image::ImageFormat::Png) .decode() .unwrap(); - let fps_texture = renderer + let res = match &mut renderer { + RendererRef::Multi(renderer) => renderer.import_memory( + &fps_image.to_rgba8(), + Fourcc::Abgr8888, + (fps_image.width() as i32, fps_image.height() as i32).into(), + false) + .expect("Unable to upload FPS texture"), + RendererRef::Pixman(renderer) => renderer.import_memory( + &fps_image.to_rgba8(), + Fourcc::Abgr8888, + (fps_image.width() as i32, fps_image.height() as i32).into(), + false) + .expect("Unable to upload FPS texture"), + }; + let fps_texture = state + .backend_data + .renderer .import_memory( &fps_image.to_rgba8(), Fourcc::Abgr8888, @@ -403,14 +461,21 @@ pub fn run_udev() { #[cfg(feature = "egl")] { info!(?primary_gpu, "Trying to initialize EGL Hardware Acceleration",); - match renderer.bind_wl_display(&display_handle) { + let res = match &mut renderer { + RendererRef::Multi(renderer) => renderer.bind_wl_display(&display_handle), + RendererRef::Pixman(renderer) => renderer.bind_wl_display(&display_handle), + }; + match res { Ok(_) => info!("EGL hardware-acceleration enabled"), Err(err) => info!(?err, "Failed to initialize EGL hardware-acceleration"), } } // init dmabuf support with format list from our primary gpu - let dmabuf_formats = renderer.dmabuf_formats(); + let dmabuf_formats = match renderer { + RendererRef::Multi(renderer) => renderer.dmabuf_formats(), + RendererRef::Pixman(renderer) => renderer.dmabuf_formats(), + }; let default_feedback = DmabufFeedbackBuilder::new(primary_gpu.dev_id(), dmabuf_formats) .build() .unwrap(); @@ -419,7 +484,7 @@ pub fn run_udev() { .create_global_with_default_feedback::>(&display_handle, &default_feedback); state.backend_data.dmabuf_state = Some((dmabuf_state, global)); - let gpus = &mut state.backend_data.gpus; + let renderers = &mut state.backend_data.renderers; state.backend_data.backends.values_mut().for_each(|backend_data| { // Update the per drm surface dmabuf feedback backend_data.surfaces.values_mut().for_each(|surface_data| { @@ -427,7 +492,7 @@ pub fn run_udev() { get_surface_dmabuf_feedback( primary_gpu, surface_data.render_node, - gpus, + renderers, &surface_data.compositor, ) }); @@ -772,11 +837,20 @@ enum DeviceAddError { fn get_surface_dmabuf_feedback( primary_gpu: DrmNode, render_node: DrmNode, - gpus: &mut GpuManager>, + renderers: &mut Renderers, composition: &SurfaceComposition, ) -> Option { - let primary_formats = gpus.single_renderer(&primary_gpu).ok()?.dmabuf_formats(); - let render_formats = gpus.single_renderer(&render_node).ok()?.dmabuf_formats(); + let (primary_formats, render_formats) = match renderers { + Renderers::Gpus(gpus) => { + let primary_formats = gpus.single_renderer(&primary_gpu).ok()?.dmabuf_formats(); + let render_formats = gpus.single_renderer(&render_node).ok()?.dmabuf_formats(); + (primary_formats, render_formats) + } + Renderers::Pixman(renderer) => { + let formats = renderer.dmabuf_formats(); + (formats.clone(), formats) + } + }; let all_render_formats = primary_formats .iter() @@ -862,11 +936,11 @@ impl AnvilState { .and_then(|x| x.try_get_render_node().ok().flatten()) .unwrap_or(node); - self.backend_data - .gpus - .as_mut() - .add_node(render_node, gbm.clone()) - .map_err(DeviceAddError::AddNode)?; + if let Renderers::Gpus(gpus) = &mut self.backend_data.renderers { + gpus.as_mut() + .add_node(render_node, gbm.clone()) + .map_err(DeviceAddError::AddNode)?; + } self.backend_data.backends.insert( node, @@ -901,12 +975,15 @@ impl AnvilState { return; }; - let mut renderer = self - .backend_data - .gpus - .single_renderer(&device.render_node) - .unwrap(); - let render_formats = renderer.as_mut().egl_context().dmabuf_render_formats().clone(); + let render_formats = match self.backend_data.renderers.single_renderer(&device.render_node) { + RendererRef::Multi(mut renderer) => { + renderer.as_mut().egl_context().dmabuf_render_formats().clone() + } + RendererRef::Pixman(renderer) => >::supported_formats(renderer) + .unwrap() + .into_iter() + .collect(), + }; let output_name = format!("{}-{}", connector.interface().as_str(), connector.interface_id()); info!(?crtc, "Trying to setup connector {}", output_name,); @@ -1065,7 +1142,7 @@ impl AnvilState { let dmabuf_feedback = get_surface_dmabuf_feedback( self.backend_data.primary_gpu, device.render_node, - &mut self.backend_data.gpus, + &mut self.backend_data.renderers, &compositor, ); @@ -1186,10 +1263,9 @@ impl AnvilState { leasing_global.disable_global::>(); } - self.backend_data - .gpus - .as_mut() - .remove_node(&backend_data.render_node); + if let Renderers::Gpus(gpus) = &mut self.backend_data.renderers { + gpus.as_mut().remove_node(&backend_data.render_node); + } self.handle.remove(backend_data.registration_token); @@ -1395,15 +1471,11 @@ impl AnvilState { let render_node = surface.render_node; let primary_gpu = self.backend_data.primary_gpu; - let mut renderer = if primary_gpu == render_node { - self.backend_data.gpus.single_renderer(&render_node) - } else { - let format = surface.compositor.format(); - self.backend_data - .gpus - .renderer(&primary_gpu, &render_node, format) - } - .unwrap(); + let format = surface.compositor.format(); + let renderer = self + .backend_data + .renderers + .renderer(&primary_gpu, &render_node, format); let pointer_images = &mut self.backend_data.pointer_images; let pointer_image = pointer_images @@ -1441,19 +1513,34 @@ impl AnvilState { return; }; - let result = render_surface( - surface, - &mut renderer, - &self.space, - &output, - self.pointer.current_location(), - &pointer_image, - &mut self.backend_data.pointer_element, - &self.dnd_icon, - &mut self.cursor_status, - &self.clock, - self.show_window_preview, - ); + let result = match renderer { + RendererRef::Multi(mut renderer) => render_surface::<_, GlesTexture>( + surface, + &mut renderer, + &self.space, + &output, + self.pointer.current_location(), + &pointer_image, + &mut self.backend_data.pointer_element, + &self.dnd_icon, + &mut self.cursor_status, + &self.clock, + self.show_window_preview, + ), + RendererRef::Pixman(renderer) => render_surface::<_, PixmanRenderBuffer>( + surface, + renderer, + &self.space, + &output, + self.pointer.current_location(), + &pointer_image, + &mut self.backend_data.pointer_element, + &self.dnd_icon, + &mut self.cursor_status, + &self.clock, + self.show_window_preview, + ), + }; let reschedule = match &result { Ok(has_rendered) => !has_rendered, Err(err) => { @@ -1529,9 +1616,9 @@ impl AnvilState { }; let node = surface.render_node; - let result = { - let mut renderer = self.backend_data.gpus.single_renderer(&node).unwrap(); - initial_render(surface, &mut renderer) + let result = match self.backend_data.renderers.single_renderer(&node) { + RendererRef::Multi(mut renderer) => initial_render::<_, GlesTexture>(surface, &mut renderer), + RendererRef::Pixman(renderer) => initial_render::<_, PixmanRenderBuffer>(surface, renderer), }; if let Err(err) = result { @@ -1551,9 +1638,9 @@ impl AnvilState { #[allow(clippy::too_many_arguments)] #[profiling::function] -fn render_surface<'a>( +fn render_surface<'a, R, Target>( surface: &'a mut SurfaceData, - renderer: &mut UdevRenderer<'a>, + renderer: &mut R, space: &Space, output: &Output, pointer_location: Point, @@ -1563,7 +1650,19 @@ fn render_surface<'a>( cursor_status: &mut CursorImageStatus, clock: &Clock, show_window_preview: bool, -) -> Result { +) -> Result +where + R: Renderer + + ImportEgl + + ImportMem + + ImportDmaWl + + ImportMemWl + + ExportMem + + Bind + + Offscreen, + ::TextureId: Clone + 'static, + SwapBuffersError: From<::Error>, +{ let output_geometry = space.output_geometry(output).unwrap(); let scale = Scale::from(output.current_scale().fractional_scale()); @@ -1609,7 +1708,7 @@ fn render_surface<'a>( { if let Some(wl_surface) = dnd_icon.as_ref() { if wl_surface.alive() { - custom_elements.extend(AsRenderElements::>::render_elements( + custom_elements.extend(AsRenderElements::::render_elements( &SurfaceTree::from_surface(wl_surface), renderer, cursor_pos_scaled, @@ -1637,7 +1736,7 @@ fn render_surface<'a>( damage, } = surface .compositor - .render_frame::<_, _, GlesTexture>(renderer, &elements, clear_color)?; + .render_frame::<_, _, Target>(renderer, &elements, clear_color)?; post_repaint( output, @@ -1665,13 +1764,15 @@ fn render_surface<'a>( Ok(rendered) } -fn initial_render( - surface: &mut SurfaceData, - renderer: &mut UdevRenderer<'_>, -) -> Result<(), SwapBuffersError> { +fn initial_render(surface: &mut SurfaceData, renderer: &mut R) -> Result<(), SwapBuffersError> +where + R: Renderer + ImportEgl + ImportDmaWl + ImportMemWl + ExportMem + Bind + Offscreen, + ::TextureId: Clone + 'static, + SwapBuffersError: From<::Error>, +{ surface .compositor - .render_frame::<_, CustomRenderElements<_>, GlesTexture>(renderer, &[], CLEAR_COLOR)?; + .render_frame::<_, CustomRenderElements<_>, Target>(renderer, &[], CLEAR_COLOR)?; surface.compositor.queue_frame(None, None, None)?; surface.compositor.reset_buffers();