From 806e739ec2357c8cd68b95ebf2206a5b37ba7712 Mon Sep 17 00:00:00 2001 From: Ottatop Date: Sat, 12 Aug 2023 12:37:46 -0500 Subject: [PATCH] Dedup render element generation code --- src/backend/udev.rs | 153 +++++----------------------------------- src/backend/winit.rs | 125 +++++---------------------------- src/render.rs | 161 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 188 insertions(+), 251 deletions(-) diff --git a/src/backend/udev.rs b/src/backend/udev.rs index 752d911..b263e0c 100644 --- a/src/backend/udev.rs +++ b/src/backend/udev.rs @@ -10,7 +10,6 @@ use std::{ ffi::OsString, os::fd::FromRawFd, path::Path, - sync::Mutex, time::Duration, }; @@ -31,10 +30,7 @@ use smithay::{ libinput::{LibinputInputBackend, LibinputSessionInterface}, renderer::{ damage::{self, OutputDamageTracker}, - element::{ - self, surface::WaylandSurfaceRenderElement, texture::TextureBuffer, - AsRenderElements, RenderElement, RenderElementStates, - }, + element::{texture::TextureBuffer, RenderElement, RenderElementStates}, gles::{GlesRenderer, GlesTexture}, multigpu::{gbm::GbmGlesBackend, GpuManager, MultiRenderer, MultiTexture}, sync::SyncPoint, @@ -51,11 +47,10 @@ use smithay::{ }, delegate_dmabuf, desktop::{ - space::{self, SurfaceTree}, utils::{send_frames_surface_tree, OutputPresentationFeedback}, Space, }, - input::pointer::{CursorImageAttributes, CursorImageStatus}, + input::pointer::CursorImageStatus, output::{Output, PhysicalProperties, Subpixel}, reexports::{ ash::vk::ExtPhysicalDeviceDrmFn, @@ -79,11 +74,8 @@ use smithay::{ backend::GlobalId, protocol::wl_surface::WlSurface, Display, DisplayHandle, }, }, - utils::{ - Clock, DeviceFd, IsAlive, Logical, Monotonic, Physical, Point, Rectangle, Scale, Transform, - }, + utils::{Clock, DeviceFd, Logical, Monotonic, Physical, Point, Rectangle, Transform}, wayland::{ - compositor, dmabuf::{ DmabufFeedback, DmabufFeedbackBuilder, DmabufGlobal, DmabufHandler, DmabufState, ImportError, @@ -98,8 +90,8 @@ use smithay_drm_extras::{ use crate::{ api::msg::{Args, OutgoingMsg}, - render::{pointer::PointerElement, CustomRenderElements, OutputRenderElements}, - state::{take_presentation_feedback, CalloopData, State, SurfaceDmabufFeedback, WithState}, + render::{pointer::PointerElement, CustomRenderElements}, + state::{take_presentation_feedback, CalloopData, State, SurfaceDmabufFeedback}, window::WindowElement, }; @@ -1486,129 +1478,18 @@ fn render_surface<'a>( clock: &Clock, focus_stack: &[WindowElement], ) -> Result { - let output_geometry = space.output_geometry(output).unwrap(); - let scale = Scale::from(output.current_scale().fractional_scale()); - - let mut custom_render_elements: Vec> = Vec::new(); - // draw input method surface if any - let rectangle = input_method.coordinates(); - let position = Point::from(( - rectangle.loc.x + rectangle.size.w, - rectangle.loc.y + rectangle.size.h, - )); - input_method.with_surface(|surface| { - custom_render_elements.extend(AsRenderElements::>::render_elements( - &SurfaceTree::from_surface(surface), - renderer, - position.to_physical_precise_round(scale), - scale, - 1.0, - )); - }); - - if output_geometry.to_f64().contains(pointer_location) { - let cursor_hotspot = if let CursorImageStatus::Surface(ref surface) = cursor_status { - compositor::with_states(surface, |states| { - states - .data_map - .get::>() - .unwrap() - .lock() - .unwrap() - .hotspot - }) - } else { - (0, 0).into() - }; - let cursor_pos = pointer_location - output_geometry.loc.to_f64() - cursor_hotspot.to_f64(); - let cursor_pos_scaled = cursor_pos.to_physical(scale).to_i32_round(); - - // set cursor - pointer_element.set_texture(pointer_image.clone()); - - // draw the cursor as relevant - { - // reset the cursor if the surface is no longer alive - let mut reset = false; - if let CursorImageStatus::Surface(ref surface) = *cursor_status { - reset = !surface.alive(); - } - if reset { - *cursor_status = CursorImageStatus::Default; - } - - pointer_element.set_status(cursor_status.clone()); - } - - custom_render_elements.extend(pointer_element.render_elements( - renderer, - cursor_pos_scaled, - scale, - 1.0, - )); - - if let Some(dnd_icon) = dnd_icon { - custom_render_elements.extend(AsRenderElements::render_elements( - &smithay::desktop::space::SurfaceTree::from_surface(dnd_icon), - renderer, - cursor_pos_scaled, - scale, - 1.0, - )); - } - } - - let output_render_elements = { - let top_fullscreen_window = focus_stack.iter().rev().find(|win| { - win.with_state(|state| { - state.status.is_fullscreen() && state.tags.iter().any(|tag| tag.active()) - }) - }); - - // If fullscreen windows exist, render only the topmost one - // TODO: wait until the fullscreen window has committed, this will stop flickering - if let Some(window) = top_fullscreen_window { - let mut output_render_elements = - Vec::>>::new(); - - let window_render_elements: Vec> = - window.render_elements(renderer, (0, 0).into(), scale, 1.0); - - output_render_elements.extend( - custom_render_elements - .into_iter() - .map(OutputRenderElements::from), - ); - - output_render_elements.extend( - window_render_elements - .into_iter() - .map(|elem| OutputRenderElements::Window(element::Wrap::from(elem))), - ); - - output_render_elements - } else { - // render everything - let space_render_elements = - space::space_render_elements(renderer, [space], output, 1.0) - .expect("Failed to get render elements"); - - let mut output_render_elements = - Vec::>>::new(); - - output_render_elements.extend( - custom_render_elements - .into_iter() - .map(OutputRenderElements::from), - ); - output_render_elements.extend( - space_render_elements - .into_iter() - .map(OutputRenderElements::from), - ); - output_render_elements - } - }; + let output_render_elements = crate::render::generate_render_elements( + renderer, + space, + output, + input_method, + pointer_location, + pointer_element, + Some(pointer_image), + cursor_status, + dnd_icon, + focus_stack, + ); let res = surface.compositor.render_frame::<_, _, GlesTexture>( renderer, diff --git a/src/backend/winit.rs b/src/backend/winit.rs index 43b2a42..b9ba6f2 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later -use std::{error::Error, ffi::OsString, sync::Mutex, time::Duration}; +use std::{error::Error, ffi::OsString, time::Duration}; use smithay::{ backend::{ @@ -8,15 +8,14 @@ use smithay::{ egl::EGLDevice, renderer::{ damage::{self, OutputDamageTracker}, - element::{self, surface::WaylandSurfaceRenderElement, AsRenderElements}, gles::{GlesRenderer, GlesTexture}, ImportDma, ImportEgl, ImportMemWl, }, winit::{WinitError, WinitEvent, WinitGraphicsBackend}, }, delegate_dmabuf, - desktop::{layer_map_for_output, space, utils::send_frames_surface_tree}, - input::pointer::{CursorImageAttributes, CursorImageStatus}, + desktop::{layer_map_for_output, utils::send_frames_surface_tree}, + input::pointer::CursorImageStatus, output::{Output, Subpixel}, reexports::{ calloop::{ @@ -26,19 +25,19 @@ use smithay::{ wayland_protocols::wp::presentation_time::server::wp_presentation_feedback, wayland_server::{protocol::wl_surface::WlSurface, Display}, }, - utils::{IsAlive, Scale, Transform}, + utils::{IsAlive, Transform}, wayland::{ - compositor, dmabuf::{ DmabufFeedback, DmabufFeedbackBuilder, DmabufGlobal, DmabufHandler, DmabufState, ImportError, }, + input_method::InputMethodSeat, }, }; use crate::{ - render::{pointer::PointerElement, CustomRenderElements, OutputRenderElements}, - state::{take_presentation_feedback, CalloopData, State, WithState}, + render::pointer::PointerElement, + state::{take_presentation_feedback, CalloopData, State}, }; use super::Backend; @@ -258,106 +257,18 @@ pub fn run_winit() -> Result<(), Box> { let full_redraw = &mut state.backend_data.full_redraw; *full_redraw = full_redraw.saturating_sub(1); - let scale = Scale::from(output.current_scale().fractional_scale()); - let cursor_hotspot = - if let CursorImageStatus::Surface(ref surface) = state.cursor_status { - compositor::with_states(surface, |states| { - states - .data_map - .get::>() - .expect("Mutex wasn't in the data map") - .lock() - .expect("Failed to lock Mutex") - .hotspot - }) - } else { - (0, 0).into() - }; - let cursor_pos = state.pointer_location - cursor_hotspot.to_f64(); - let cursor_pos_scaled = cursor_pos.to_physical(scale).to_i32_round::(); - - let mut custom_render_elements = Vec::>::new(); - - custom_render_elements.extend(pointer_element.render_elements( + let output_render_elements = crate::render::generate_render_elements( state.backend_data.backend.renderer(), - cursor_pos_scaled, - scale, - 1.0, - )); - - if let Some(dnd_icon) = state.dnd_icon.as_ref() { - custom_render_elements.extend(AsRenderElements::::render_elements( - &smithay::desktop::space::SurfaceTree::from_surface(dnd_icon), - state.backend_data.backend.renderer(), - cursor_pos_scaled, - scale, - 1.0, - )); - } - - let output_render_elements = { - let renderer = state.backend_data.backend.renderer(); - - let top_fullscreen_window = - state.focus_state.focus_stack.iter().rev().find(|win| { - win.with_state(|state| { - state.status.is_fullscreen() - && state.tags.iter().any(|tag| tag.active()) - }) - }); - - // If fullscreen windows exist, render only the topmost one - // TODO: wait until the fullscreen window has committed, this will stop flickering - if let Some(window) = top_fullscreen_window { - let mut output_render_elements = Vec::< - OutputRenderElements< - GlesRenderer, - WaylandSurfaceRenderElement, - >, - >::new(); - - let window_render_elements: Vec> = - window.render_elements(renderer, (0, 0).into(), scale, 1.0); - - output_render_elements.extend( - custom_render_elements - .into_iter() - .map(OutputRenderElements::from), - ); - - output_render_elements.extend( - window_render_elements - .into_iter() - .map(|elem| OutputRenderElements::Window(element::Wrap::from(elem))), - ); - - output_render_elements - } else { - // render everything - let space_render_elements = - space::space_render_elements(renderer, [&state.space], &output, 1.0) - .expect("Failed to get render elements"); - - let mut output_render_elements = Vec::< - OutputRenderElements< - GlesRenderer, - WaylandSurfaceRenderElement, - >, - >::new(); - - output_render_elements.extend( - custom_render_elements - .into_iter() - .map(OutputRenderElements::from), - ); - output_render_elements.extend( - space_render_elements - .into_iter() - .map(OutputRenderElements::from), - ); - output_render_elements - } - }; + &state.space, + &output, + state.seat.input_method(), + state.pointer_location, + &mut pointer_element, + None, + &mut state.cursor_status, + state.dnd_icon.as_ref(), + &state.focus_state.focus_stack, + ); let render_res = state.backend_data.backend.bind().and_then(|_| { let age = if *full_redraw > 0 { diff --git a/src/render.rs b/src/render.rs index 525a54f..3c56b83 100644 --- a/src/render.rs +++ b/src/render.rs @@ -1,16 +1,28 @@ // SPDX-License-Identifier: GPL-3.0-or-later +use std::sync::Mutex; + use smithay::{ backend::renderer::{ - element::{surface::WaylandSurfaceRenderElement, AsRenderElements, Wrap}, + element::{ + self, surface::WaylandSurfaceRenderElement, texture::TextureBuffer, AsRenderElements, + Wrap, + }, ImportAll, ImportMem, Renderer, Texture, }, - desktop::space::SpaceRenderElements, + desktop::{ + space::{self, SpaceRenderElements, SurfaceTree}, + Space, + }, + input::pointer::{CursorImageAttributes, CursorImageStatus}, + output::Output, + reexports::wayland_server::protocol::wl_surface::WlSurface, render_elements, - utils::{Physical, Point, Scale}, + utils::{IsAlive, Logical, Physical, Point, Scale}, + wayland::{compositor, input_method::InputMethodHandle}, }; -use crate::window::WindowElement; +use crate::{state::WithState, window::WindowElement}; use self::pointer::{PointerElement, PointerRenderElement}; @@ -61,14 +73,147 @@ where } } -pub fn render_elements( +#[allow(clippy::too_many_arguments)] +pub fn generate_render_elements( renderer: &mut R, + space: &Space, + output: &Output, + input_method: &InputMethodHandle, + pointer_location: Point, pointer_element: &mut PointerElement, + pointer_image: Option<&TextureBuffer>, + cursor_status: &mut CursorImageStatus, + dnd_icon: Option<&WlSurface>, + focus_stack: &[WindowElement], ) -> Vec>> where - R: Renderer + ImportAll, + R: Renderer + ImportAll + ImportMem, ::TextureId: 'static, - T: Texture, + T: Texture + Clone, { - vec![] + let output_geometry = space + .output_geometry(output) + .expect("called output_geometry on an unmapped output"); + let scale = Scale::from(output.current_scale().fractional_scale()); + + let mut custom_render_elements: Vec> = Vec::new(); + // draw input method surface if any + let rectangle = input_method.coordinates(); + let position = Point::from(( + rectangle.loc.x + rectangle.size.w, + rectangle.loc.y + rectangle.size.h, + )); + input_method.with_surface(|surface| { + custom_render_elements.extend(AsRenderElements::::render_elements( + &SurfaceTree::from_surface(surface), + renderer, + position.to_physical_precise_round(scale), + scale, + 1.0, + )); + }); + + if output_geometry.to_f64().contains(pointer_location) { + let cursor_hotspot = if let CursorImageStatus::Surface(ref surface) = cursor_status { + compositor::with_states(surface, |states| { + states + .data_map + .get::>() + .expect("surface data map had no CursorImageAttributes") + .lock() + .expect("failed to lock mutex") + .hotspot + }) + } else { + (0, 0).into() + }; + let cursor_pos = pointer_location - output_geometry.loc.to_f64() - cursor_hotspot.to_f64(); + let cursor_pos_scaled = cursor_pos.to_physical(scale).to_i32_round(); + + // set cursor + if let Some(pointer_image) = pointer_image { + pointer_element.set_texture(pointer_image.clone()); + } + + // draw the cursor as relevant and + // reset the cursor if the surface is no longer alive + if let CursorImageStatus::Surface(surface) = &*cursor_status { + if !surface.alive() { + *cursor_status = CursorImageStatus::Default; + } + } + + pointer_element.set_status(cursor_status.clone()); + + custom_render_elements.extend(pointer_element.render_elements( + renderer, + cursor_pos_scaled, + scale, + 1.0, + )); + + if let Some(dnd_icon) = dnd_icon { + custom_render_elements.extend(AsRenderElements::render_elements( + &smithay::desktop::space::SurfaceTree::from_surface(dnd_icon), + renderer, + cursor_pos_scaled, + scale, + 1.0, + )); + } + } + + let output_render_elements = { + let top_fullscreen_window = focus_stack.iter().rev().find(|win| { + win.with_state(|state| { + state.status.is_fullscreen() && state.tags.iter().any(|tag| tag.active()) + }) + }); + + // If fullscreen windows exist, render only the topmost one + // TODO: wait until the fullscreen window has committed, this will stop flickering + if let Some(window) = top_fullscreen_window { + let mut output_render_elements = + Vec::>>::new(); + + let window_render_elements: Vec> = + window.render_elements(renderer, (0, 0).into(), scale, 1.0); + + output_render_elements.extend( + custom_render_elements + .into_iter() + .map(OutputRenderElements::from), + ); + + output_render_elements.extend( + window_render_elements + .into_iter() + .map(|elem| OutputRenderElements::Window(element::Wrap::from(elem))), + ); + + output_render_elements + } else { + // render everything + let space_render_elements = + space::space_render_elements(renderer, [space], output, 1.0) + .expect("Failed to get render elements"); + + let mut output_render_elements = + Vec::>>::new(); + + output_render_elements.extend( + custom_render_elements + .into_iter() + .map(OutputRenderElements::from), + ); + output_render_elements.extend( + space_render_elements + .into_iter() + .map(OutputRenderElements::from), + ); + output_render_elements + } + }; + + output_render_elements }