diff --git a/src/backend/udev.rs b/src/backend/udev.rs index 98ec821..ea5f928 100644 --- a/src/backend/udev.rs +++ b/src/backend/udev.rs @@ -23,19 +23,18 @@ use smithay::{ drm::{ compositor::{DrmCompositor, PrimaryPlaneElement}, CreateDrmNodeError, DrmDevice, DrmDeviceFd, DrmError, DrmEvent, DrmEventMetadata, - DrmNode, DrmSurface, GbmBufferedSurface, NodeType, + DrmNode, NodeType, }, egl::{self, EGLDevice, EGLDisplay}, libinput::{LibinputInputBackend, LibinputSessionInterface}, renderer::{ - damage::{self, OutputDamageTracker}, + damage::{self}, element::{ surface::WaylandSurfaceRenderElement, texture::TextureBuffer, RenderElement, RenderElementStates, }, gles::{GlesRenderer, GlesTexture}, multigpu::{gbm::GbmGlesBackend, GpuManager, MultiRenderer, MultiTexture}, - sync::SyncPoint, Bind, ExportMem, ImportDma, ImportEgl, ImportMemWl, Offscreen, Renderer, }, session::{ @@ -64,7 +63,6 @@ use smithay::{ control::{connector, crtc, ModeTypeFlags}, Device, }, - gbm, input::Libinput, nix::fcntl::OFlag, wayland_protocols::wp::{ @@ -75,7 +73,7 @@ use smithay::{ backend::GlobalId, protocol::wl_surface::WlSurface, Display, DisplayHandle, }, }, - utils::{Clock, DeviceFd, IsAlive, Logical, Monotonic, Physical, Point, Rectangle, Transform}, + utils::{Clock, DeviceFd, IsAlive, Logical, Monotonic, Point, Transform}, wayland::{ dmabuf::{DmabufFeedback, DmabufFeedbackBuilder, DmabufGlobal, DmabufState}, input_method::{InputMethodHandle, InputMethodSeat}, @@ -109,12 +107,16 @@ const SUPPORTED_FORMATS: &[Fourcc] = &[ ]; const SUPPORTED_FORMATS_8BIT_ONLY: &[Fourcc] = &[Fourcc::Abgr8888, Fourcc::Argb8888]; +/// A [`MultiRenderer`] that uses the [`GbmGlesBackend`]. type UdevRenderer<'a, 'b> = MultiRenderer<'a, 'a, 'b, GbmGlesBackend, GbmGlesBackend>; +/// Udev state attached to each [`Output`]. #[derive(Debug, PartialEq)] struct UdevOutputId { + /// The GPU node device_id: DrmNode, + /// The [Crtc][crtc::Handle] the output is pushing to crtc: crtc::Handle, } @@ -220,7 +222,7 @@ pub fn run_udev() -> anyhow::Result<()> { } } - let Backend::Udev(backend) = &mut state.backend else { + let Backend::Udev(udev) = &mut state.backend else { unreachable!() }; @@ -252,7 +254,7 @@ pub fn run_udev() -> anyhow::Result<()> { // Initialize libinput backend let mut libinput_context = Libinput::new_with_udev::>( - backend.session.clone().into(), + udev.session.clone().into(), ); libinput_context .udev_assign_seat(state.seat.name()) @@ -318,8 +320,7 @@ pub fn run_udev() -> anyhow::Result<()> { .unwrap(); state.shm_state.update_formats( - backend - .gpu_manager + udev.gpu_manager .single_renderer(&primary_gpu) .unwrap() .shm_formats(), @@ -353,7 +354,7 @@ pub fn run_udev() -> anyhow::Result<()> { ImageUsageFlags::COLOR_ATTACHMENT | ImageUsageFlags::SAMPLED, ) { Ok(allocator) => { - backend.allocator = Some(Box::new(DmabufAllocator(allocator)) + udev.allocator = Some(Box::new(DmabufAllocator(allocator)) as Box>); } Err(err) => { @@ -364,16 +365,16 @@ pub fn run_udev() -> anyhow::Result<()> { } } - if backend.allocator.is_none() { + if udev.allocator.is_none() { tracing::info!("No vulkan allocator found, using GBM."); - let gbm = backend + let gbm = udev .backends .get(&primary_gpu) // If the primary_gpu failed to initialize, we likely have a kmsro device - .or_else(|| backend.backends.values().next()) + .or_else(|| udev.backends.values().next()) // Don't fail, if there is no allocator. There is a chance, that this a single gpu system and we don't need one. .map(|backend| backend.gbm.clone()); - backend.allocator = gbm.map(|gbm| { + udev.allocator = gbm.map(|gbm| { Box::new(DmabufAllocator(GbmAllocator::new( gbm, GbmBufferFlags::RENDERING, @@ -382,7 +383,7 @@ pub fn run_udev() -> anyhow::Result<()> { } #[cfg_attr(not(feature = "egl"), allow(unused_mut))] - let mut renderer = backend.gpu_manager.single_renderer(&primary_gpu).unwrap(); + let mut renderer = udev.gpu_manager.single_renderer(&primary_gpu).unwrap(); { tracing::info!( @@ -403,10 +404,10 @@ pub fn run_udev() -> anyhow::Result<()> { let mut dmabuf_state = DmabufState::new(); let global = dmabuf_state .create_global_with_default_feedback::(&display.handle(), &default_feedback); - backend.dmabuf_state = Some((dmabuf_state, global)); + udev.dmabuf_state = Some((dmabuf_state, global)); - let gpu_manager = &mut backend.gpu_manager; - backend.backends.values_mut().for_each(|backend_data| { + let gpu_manager = &mut udev.gpu_manager; + udev.backends.values_mut().for_each(|backend_data| { // Update the per drm surface dmabuf feedback backend_data.surfaces.values_mut().for_each(|surface_data| { surface_data.dmabuf_feedback = surface_data.dmabuf_feedback.take().or_else(|| { @@ -470,7 +471,7 @@ fn get_surface_dmabuf_feedback( primary_gpu: DrmNode, render_node: DrmNode, gpu_manager: &mut GpuManager>, - composition: &SurfaceComposition, + composition: &GbmDrmCompositor, ) -> Option { let primary_formats = gpu_manager .single_renderer(&primary_gpu) @@ -538,7 +539,7 @@ struct SurfaceData { display_handle: DisplayHandle, device_id: DrmNode, render_node: DrmNode, - compositor: SurfaceComposition, + compositor: GbmDrmCompositor, dmabuf_feedback: Option, } @@ -550,9 +551,6 @@ impl Drop for SurfaceData { } } -type RenderSurface = - GbmBufferedSurface, Option>; - type GbmDrmCompositor = DrmCompositor< GbmAllocator, GbmDevice, @@ -560,145 +558,42 @@ type GbmDrmCompositor = DrmCompositor< DrmDeviceFd, >; -enum SurfaceComposition { - Surface { - surface: RenderSurface, - damage_tracker: OutputDamageTracker, - }, - Compositor(GbmDrmCompositor), -} - struct SurfaceCompositorRenderResult { rendered: bool, states: RenderElementStates, - sync: Option, - damage: Option>>, } -impl SurfaceComposition { - fn frame_submitted(&mut self) -> Result, SwapBuffersError> { - match self { - SurfaceComposition::Surface { surface, .. } => surface - .frame_submitted() - .map(Option::flatten) - .map_err(SwapBuffersError::from), - SurfaceComposition::Compositor(comp) => comp - .frame_submitted() - .map(Option::flatten) - .map_err(SwapBuffersError::from), - } - } - - fn format(&self) -> gbm::Format { - match self { - SurfaceComposition::Surface { surface, .. } => surface.format(), - SurfaceComposition::Compositor(comp) => comp.format(), - } - } - - fn surface(&self) -> &DrmSurface { - match self { - SurfaceComposition::Compositor(c) => c.surface(), - SurfaceComposition::Surface { surface, .. } => surface.surface(), - } - } - - fn reset_buffers(&mut self) { - match self { - SurfaceComposition::Compositor(c) => c.reset_buffers(), - SurfaceComposition::Surface { surface, .. } => surface.reset_buffers(), - } - } - - fn queue_frame( - &mut self, - sync: Option, - damage: Option>>, - user_data: Option, - ) -> Result<(), SwapBuffersError> { - match self { - SurfaceComposition::Surface { surface, .. } => surface - .queue_buffer(sync, damage, user_data) - .map_err(Into::::into), - SurfaceComposition::Compositor(c) => c - .queue_frame(user_data) - .map_err(Into::::into), - } - } - - fn render_frame( - &mut self, - renderer: &mut R, - elements: &[E], - clear_color: [f32; 4], - ) -> Result - where - R: Renderer + Bind + Bind + Offscreen + ExportMem, - ::TextureId: 'static, - ::Error: Into, - E: RenderElement, - { - match self { - SurfaceComposition::Surface { - surface, - damage_tracker, - } => { - let (dmabuf, age) = surface - .next_buffer() - .map_err(Into::::into)?; - renderer - .bind(dmabuf) - .map_err(Into::::into)?; - let current_debug_flags = renderer.debug_flags(); - - tracing::info!("surface damage_tracker render_output"); - - let res = damage_tracker - .render_output(renderer, age.into(), elements, clear_color) - .map(|res| { - res.sync.wait(); // feature flag here - let rendered = res.damage.is_some(); - SurfaceCompositorRenderResult { - rendered, - damage: res.damage, - states: res.states, - sync: rendered.then_some(res.sync), - } - }) - .map_err(|err| match err { - damage::Error::Rendering(err) => err.into(), - _ => unreachable!(), - }); - renderer.set_debug_flags(current_debug_flags); - res +fn render_frame( + compositor: &mut GbmDrmCompositor, + renderer: &mut R, + elements: &[E], + clear_color: [f32; 4], +) -> Result +where + R: Renderer + Bind + Bind + Offscreen + ExportMem, + ::TextureId: 'static, + ::Error: Into, + E: RenderElement, +{ + compositor + .render_frame(renderer, elements, clear_color) + .map(|render_frame_result| { + // feature flag here + if let PrimaryPlaneElement::Swapchain(element) = render_frame_result.primary_element { + element.sync.wait(); } - SurfaceComposition::Compositor(compositor) => compositor - .render_frame(renderer, elements, clear_color) - .map(|render_frame_result| { - // feature flag here - if let PrimaryPlaneElement::Swapchain(element) = - render_frame_result.primary_element - { - element.sync.wait(); - } - SurfaceCompositorRenderResult { - rendered: render_frame_result.damage.is_some(), - states: render_frame_result.states, - sync: None, - damage: None, - } - }) - .map_err(|err| match err { - smithay::backend::drm::compositor::RenderFrameError::PrepareFrame(err) => { - err.into() - } - smithay::backend::drm::compositor::RenderFrameError::RenderFrame( - damage::Error::Rendering(err), - ) => err.into(), - _ => unreachable!(), - }), - } - } + SurfaceCompositorRenderResult { + rendered: render_frame_result.damage.is_some(), + states: render_frame_result.states, + } + }) + .map_err(|err| match err { + smithay::backend::drm::compositor::RenderFrameError::PrepareFrame(err) => err.into(), + smithay::backend::drm::compositor::RenderFrameError::RenderFrame( + damage::Error::Rendering(err), + ) => err.into(), + _ => unreachable!(), + }) } impl State { @@ -880,20 +775,7 @@ impl State { SUPPORTED_FORMATS }; - let compositor = if std::env::var("ANVIL_DISABLE_DRM_COMPOSITOR").is_ok() { - let gbm_surface = - match GbmBufferedSurface::new(surface, allocator, color_formats, render_formats) { - Ok(renderer) => renderer, - Err(err) => { - tracing::warn!("Failed to create rendering surface: {}", err); - return; - } - }; - SurfaceComposition::Surface { - surface: gbm_surface, - damage_tracker: OutputDamageTracker::from_output(&output), - } - } else { + let compositor = { let driver = match device.drm.get_driver() { Ok(driver) => driver, Err(err) => { @@ -919,7 +801,7 @@ impl State { planes.overlay = vec![]; } - let compositor = match DrmCompositor::new( + match DrmCompositor::new( &output, surface, Some(planes), @@ -935,8 +817,7 @@ impl State { tracing::warn!("Failed to create drm compositor: {}", err); return; } - }; - SurfaceComposition::Compositor(compositor) + } }; let dmabuf_feedback = get_surface_dmabuf_feedback( @@ -1165,7 +1046,7 @@ impl State { .map_err(SwapBuffersError::from) { Ok(user_data) => { - if let Some(mut feedback) = user_data { + if let Some(mut feedback) = user_data.flatten() { let tp = metadata.as_ref().and_then(|metadata| match metadata.time { smithay::backend::drm::DrmEventTime::Monotonic(tp) => Some(tp), smithay::backend::drm::DrmEventTime::Realtime(_) => None, @@ -1552,7 +1433,7 @@ fn render_surface<'a>( // TODO: set waiting for vblank to true here surface .compositor - .queue_frame(None, None, None) + .queue_frame(None) .map_err(Into::::into)?; // TODO: still draw the cursor here @@ -1574,7 +1455,8 @@ fn render_surface<'a>( Some(pointer_image), ); - let res = surface.compositor.render_frame::<_, _, GlesTexture>( + let res = render_frame::<_, _, GlesTexture>( + &mut surface.compositor, renderer, &output_render_elements, [0.6, 0.6, 0.6, 1.0], @@ -1607,7 +1489,7 @@ fn render_surface<'a>( // TODO: set waiting for vblank to true here surface .compositor - .queue_frame(res.sync, res.damage, Some(output_presentation_feedback)) + .queue_frame(Some(output_presentation_feedback)) .map_err(SwapBuffersError::from)?; } @@ -1618,14 +1500,13 @@ fn initial_render( surface: &mut SurfaceData, renderer: &mut UdevRenderer<'_, '_>, ) -> Result<(), SwapBuffersError> { - surface - .compositor - .render_frame::<_, CustomRenderElements<_, WaylandSurfaceRenderElement<_>>, GlesTexture>( - renderer, - &[], - [0.6, 0.6, 0.6, 1.0], - )?; - surface.compositor.queue_frame(None, None, None)?; + render_frame::<_, CustomRenderElements<_, WaylandSurfaceRenderElement<_>>, GlesTexture>( + &mut surface.compositor, + renderer, + &[], + [0.6, 0.6, 0.6, 1.0], + )?; + surface.compositor.queue_frame(None)?; surface.compositor.reset_buffers(); Ok(())