diff --git a/anvil/src/drawing.rs b/anvil/src/drawing.rs index cd62d454b675..ac0d3ed02064 100644 --- a/anvil/src/drawing.rs +++ b/anvil/src/drawing.rs @@ -198,7 +198,7 @@ where impl RenderElement for FpsElement<::TextureId> where R: Renderer + ImportAll, - ::TextureId: 'static, + ::TextureId: Send + 'static, { fn draw( &self, diff --git a/anvil/src/render.rs b/anvil/src/render.rs index 6346799a71be..3f675161df93 100644 --- a/anvil/src/render.rs +++ b/anvil/src/render.rs @@ -27,7 +27,8 @@ use crate::{ smithay::backend::renderer::element::render_elements! { pub CustomRenderElements where - R: ImportAll + ImportMem; + R: ImportAll + ImportMem, + ::TextureId: Send; Pointer=PointerRenderElement, Surface=WaylandSurfaceRenderElement, #[cfg(feature = "debug")] @@ -51,7 +52,8 @@ impl std::fmt::Debug for CustomRenderElements { } smithay::backend::renderer::element::render_elements! { - pub OutputRenderElements where R: ImportAll + ImportMem; + pub OutputRenderElements where R: ImportAll + ImportMem, + ::TextureId: Send; Space=SpaceRenderElements, Window=Wrap, Custom=CustomRenderElements, @@ -201,7 +203,7 @@ pub fn render_output<'a, 'd, R>( ) -> Result, OutputDamageTrackerError> where R: Renderer + ImportAll + ImportMem, - R::TextureId: Clone + 'static, + R::TextureId: Clone + Send + 'static, { let (elements, clear_color) = output_elements(output, space, custom_elements, renderer, show_window_preview); diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index b482527f6e3f..49bc642651e3 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}, @@ -111,31 +112,71 @@ 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), + } + } +} + +#[cfg(feature = "debug")] +#[derive(Clone)] +enum Texture { + Pixman(PixmanTexture), + Multi(MultiTexture), +} + pub struct UdevData { pub session: LibSeatSession, dh: DisplayHandle, dmabuf_state: Option<(DmabufState, DmabufGlobal)>, syncobj_state: Option, primary_gpu: DrmNode, - gpus: GpuManager>, + renderers: Renderers, backends: HashMap, pointer_images: Vec<(xcursor::parser::Image, MemoryRenderBuffer)>, pointer_element: PointerElement, #[cfg(feature = "debug")] - fps_texture: Option, + fps_texture: Option, pointer_image: crate::cursor::Cursor, debug_flags: DebugFlags, keyboards: Vec, @@ -165,13 +206,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 { @@ -200,8 +243,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); + } } } @@ -247,7 +292,13 @@ 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(), @@ -255,7 +306,7 @@ pub fn run_udev() { syncobj_state: None, session, primary_gpu, - gpus, + renderers, backends: HashMap::new(), pointer_image: crate::cursor::Cursor::load(), pointer_images: Vec::new(), @@ -371,17 +422,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")] { @@ -389,14 +438,28 @@ pub fn run_udev() { image::ImageReader::with_format(std::io::Cursor::new(FPS_NUMBERS_PNG), image::ImageFormat::Png) .decode() .unwrap(); - let fps_texture = 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 = match &mut renderer { + RendererRef::Multi(renderer) => Texture::Multi( + 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) => Texture::Pixman( + 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"), + ), + }; for backend in state.backend_data.backends.values_mut() { for surface in backend.surfaces.values_mut() { @@ -409,14 +472,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(); @@ -425,7 +495,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| { @@ -433,7 +503,7 @@ pub fn run_udev() { get_surface_dmabuf_feedback( primary_gpu, surface_data.render_node, - gpus, + renderers, &surface_data.compositor, ) }); @@ -795,11 +865,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() @@ -885,11 +964,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, @@ -924,12 +1003,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,); @@ -1096,7 +1178,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, ); @@ -1215,10 +1297,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); @@ -1446,15 +1527,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 @@ -1479,18 +1556,32 @@ impl AnvilState { buffer }); - 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.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.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.show_window_preview, + ), + }; let reschedule = match result { Ok((has_rendered, states)) => { let dmabuf_feedback = surface.dmabuf_feedback.clone(); @@ -1573,9 +1664,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 { @@ -1595,9 +1686,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, @@ -1606,7 +1697,19 @@ fn render_surface<'a>( dnd_icon: &Option, cursor_status: &mut CursorImageStatus, show_window_preview: bool, -) -> Result<(bool, RenderElementStates), SwapBuffersError> { +) -> Result<(bool, RenderElementStates), SwapBuffersError> +where + R: Renderer + + ImportEgl + + ImportMem + + ImportDmaWl + + ImportMemWl + + ExportMem + + Bind + + Offscreen, + ::TextureId: Clone + Send + 'static, + SwapBuffersError: From<::Error>, +{ let output_geometry = space.output_geometry(output).unwrap(); let scale = Scale::from(output.current_scale().fractional_scale()); @@ -1663,7 +1766,7 @@ fn render_surface<'a>( .to_physical(scale) .to_i32_round(); if icon.surface.alive() { - custom_elements.extend(AsRenderElements::>::render_elements( + custom_elements.extend(AsRenderElements::::render_elements( &SurfaceTree::from_surface(&icon.surface), renderer, dnd_icon_pos, @@ -1690,7 +1793,7 @@ fn render_surface<'a>( damage, } = surface .compositor - .render_frame::<_, _, GlesTexture>(renderer, &elements, clear_color)?; + .render_frame::<_, _, Target>(renderer, &elements, clear_color)?; if rendered { let output_presentation_feedback = take_presentation_feedback(output, space, &states); @@ -1704,13 +1807,15 @@ fn render_surface<'a>( Ok((rendered, states)) } -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 + Send + '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();