Dedup render element generation code

This commit is contained in:
Ottatop 2023-08-12 12:37:46 -05:00
parent d75e0dad22
commit 806e739ec2
3 changed files with 188 additions and 251 deletions

View file

@ -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<Monotonic>,
focus_stack: &[WindowElement],
) -> Result<bool, SwapBuffersError> {
let output_geometry = space.output_geometry(output).unwrap();
let scale = Scale::from(output.current_scale().fractional_scale());
let mut custom_render_elements: Vec<CustomRenderElements<_>> = 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::<UdevRenderer<'a, '_>>::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::<Mutex<CursorImageAttributes>>()
.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::<OutputRenderElements<_, WaylandSurfaceRenderElement<_>>>::new();
let window_render_elements: Vec<WaylandSurfaceRenderElement<_>> =
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::<OutputRenderElements<_, 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
}
};
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,

View file

@ -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<dyn Error>> {
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::<Mutex<CursorImageAttributes>>()
.expect("Mutex<CursorImageAttributes> wasn't in the data map")
.lock()
.expect("Failed to lock Mutex<CursorImageAttributes>")
.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::<i32>();
let mut custom_render_elements = Vec::<CustomRenderElements<GlesRenderer>>::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::<GlesRenderer>::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<GlesRenderer>,
>,
>::new();
let window_render_elements: Vec<WaylandSurfaceRenderElement<_>> =
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<GlesRenderer>,
>,
>::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 {

View file

@ -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<R, T>(
#[allow(clippy::too_many_arguments)]
pub fn generate_render_elements<R, T>(
renderer: &mut R,
space: &Space<WindowElement>,
output: &Output,
input_method: &InputMethodHandle,
pointer_location: Point<f64, Logical>,
pointer_element: &mut PointerElement<T>,
pointer_image: Option<&TextureBuffer<T>>,
cursor_status: &mut CursorImageStatus,
dnd_icon: Option<&WlSurface>,
focus_stack: &[WindowElement],
) -> Vec<OutputRenderElements<R, WaylandSurfaceRenderElement<R>>>
where
R: Renderer + ImportAll,
R: Renderer<TextureId = T> + ImportAll + ImportMem,
<R as Renderer>::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<CustomRenderElements<_>> = 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::<R>::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::<Mutex<CursorImageAttributes>>()
.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::<OutputRenderElements<_, WaylandSurfaceRenderElement<_>>>::new();
let window_render_elements: Vec<WaylandSurfaceRenderElement<_>> =
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::<OutputRenderElements<_, 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
}
};
output_render_elements
}