kms: Dmabuf Feedback support
This commit is contained in:
parent
486266f7bb
commit
c8bb417d9b
8 changed files with 234 additions and 26 deletions
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
backend::render::{workspace_elements, CLEAR_COLOR},
|
||||
config::OutputConfig,
|
||||
shell::Shell,
|
||||
state::{BackendData, ClientState, Common, Data, Fps},
|
||||
state::{BackendData, ClientState, Common, Data, Fps, SurfaceDmabufFeedback},
|
||||
utils::prelude::*,
|
||||
wayland::{
|
||||
handlers::screencopy::{render_session, UserdataExt},
|
||||
|
|
@ -38,7 +38,7 @@ use smithay::{
|
|||
glow::GlowRenderer,
|
||||
multigpu::{gbm::GbmGlesBackend, Error as MultiError, GpuManager},
|
||||
utils::draw_render_elements,
|
||||
Bind, Blit, Offscreen, Renderer, TextureFilter,
|
||||
Bind, Blit, ImportDma, Offscreen, Renderer, TextureFilter,
|
||||
},
|
||||
session::{libseat::LibSeatSession, Event as SessionEvent, Session},
|
||||
udev::{all_gpus, primary_gpu, UdevBackend, UdevEvent},
|
||||
|
|
@ -58,12 +58,16 @@ use smithay::{
|
|||
},
|
||||
input::Libinput,
|
||||
nix::{fcntl::OFlag, sys::stat::dev_t},
|
||||
wayland_protocols::wp::presentation_time::server::wp_presentation_feedback,
|
||||
wayland_protocols::wp::{
|
||||
linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1,
|
||||
presentation_time::server::wp_presentation_feedback,
|
||||
},
|
||||
wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle, Resource},
|
||||
},
|
||||
utils::{DeviceFd, Size, Transform},
|
||||
wayland::{
|
||||
dmabuf::{get_dmabuf, DmabufGlobal},
|
||||
compositor::with_states,
|
||||
dmabuf::{get_dmabuf, DmabufFeedbackBuilder, DmabufGlobal, SurfaceDmabufFeedbackState},
|
||||
relative_pointer::RelativePointerManagerState,
|
||||
seat::WaylandFocus,
|
||||
},
|
||||
|
|
@ -119,6 +123,7 @@ pub struct Surface {
|
|||
dirty: bool,
|
||||
render_timer_token: Option<RegistrationToken>,
|
||||
fps: Fps,
|
||||
feedback: Option<SurfaceDmabufFeedback>,
|
||||
}
|
||||
|
||||
pub type GbmDrmCompositor = DrmCompositor<
|
||||
|
|
@ -889,6 +894,7 @@ impl Device {
|
|||
dirty: false,
|
||||
render_timer_token: None,
|
||||
fps: Fps::new(renderer.as_mut()),
|
||||
feedback: None,
|
||||
};
|
||||
self.surfaces.insert(crtc, data);
|
||||
|
||||
|
|
@ -909,10 +915,18 @@ fn render_node_for_output(
|
|||
.unwrap_or_else(|| workspace.windows().collect::<Vec<_>>())
|
||||
.into_iter()
|
||||
.flat_map(|w| {
|
||||
// has the client requested surface-feedback? If yes it is properly rendering on our target_node
|
||||
if with_states(&w.wl_surface()?, |data| {
|
||||
SurfaceDmabufFeedbackState::from_states(data).is_some()
|
||||
}) {
|
||||
return Some(target_node.clone());
|
||||
}
|
||||
// else lets check the global drm-node the client got either through default-feedback or wl_drm
|
||||
let client = dh.get_client(w.wl_surface()?.id()).ok()?;
|
||||
if let Some(normal_client) = client.get_data::<ClientState>() {
|
||||
return normal_client.drm_node.clone();
|
||||
}
|
||||
// last but not least all xwayland-surfaces should also share a single node
|
||||
if let Some(xwayland_client) = client.get_data::<XWaylandClientData>() {
|
||||
return xwayland_client.user_data().get::<DrmNode>().cloned();
|
||||
}
|
||||
|
|
@ -936,6 +950,51 @@ fn render_node_for_output(
|
|||
}
|
||||
}
|
||||
|
||||
fn get_surface_dmabuf_feedback(
|
||||
render_node: DrmNode,
|
||||
renderer: &mut GlMultiRenderer<'_, '_>,
|
||||
compositor: &GbmDrmCompositor,
|
||||
) -> Option<SurfaceDmabufFeedback> {
|
||||
let render_formats = renderer.dmabuf_formats().copied().collect::<HashSet<_>>();
|
||||
|
||||
let surface = compositor.surface();
|
||||
let planes = surface.planes().unwrap();
|
||||
// We limit the scan-out trache to formats we can also render from
|
||||
// so that there is always a fallback render path available in case
|
||||
// the supplied buffer can not be scanned out directly
|
||||
let planes_formats = surface
|
||||
.supported_formats(planes.primary.handle)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.chain(
|
||||
planes
|
||||
.overlay
|
||||
.iter()
|
||||
.flat_map(|p| surface.supported_formats(p.handle).unwrap()),
|
||||
)
|
||||
.collect::<HashSet<_>>()
|
||||
.intersection(&render_formats)
|
||||
.copied()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let builder = DmabufFeedbackBuilder::new(render_node.dev_id(), render_formats);
|
||||
let render_feedback = builder.clone().build().unwrap();
|
||||
|
||||
let scanout_feedback = builder
|
||||
.add_preference_tranche(
|
||||
surface.device_fd().dev_id().unwrap(),
|
||||
Some(zwp_linux_dmabuf_feedback_v1::TrancheFlags::Scanout),
|
||||
planes_formats,
|
||||
)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
Some(SurfaceDmabufFeedback {
|
||||
render_feedback,
|
||||
scanout_feedback,
|
||||
})
|
||||
}
|
||||
|
||||
impl Surface {
|
||||
pub fn render_output(
|
||||
&mut self,
|
||||
|
|
@ -1088,7 +1147,7 @@ impl Surface {
|
|||
} else {
|
||||
None
|
||||
};
|
||||
state.send_frames(&self.output, &frame_result.states);
|
||||
state.send_frames(&self.output, &frame_result.states, self.feedback.as_ref());
|
||||
compositor
|
||||
.queue_frame(feedback)
|
||||
.with_context(|| "Failed to submit result for display")?
|
||||
|
|
@ -1215,6 +1274,16 @@ impl KmsState {
|
|||
.unwrap_or_else(|_| String::from("Unknown"))
|
||||
)
|
||||
})?;
|
||||
surface.feedback =
|
||||
self.api.single_renderer(&device.render_node).ok().and_then(
|
||||
|mut renderer| {
|
||||
get_surface_dmabuf_feedback(
|
||||
device.render_node,
|
||||
&mut renderer,
|
||||
&target,
|
||||
)
|
||||
},
|
||||
);
|
||||
surface.surface = Some(target);
|
||||
true
|
||||
};
|
||||
|
|
@ -1287,8 +1356,6 @@ impl KmsState {
|
|||
}
|
||||
|
||||
pub fn dmabuf_imported(&mut self, global: &DmabufGlobal, dmabuf: Dmabuf) -> Result<()> {
|
||||
use smithay::backend::renderer::ImportDma;
|
||||
|
||||
for device in self.devices.values() {
|
||||
if device
|
||||
.socket
|
||||
|
|
|
|||
|
|
@ -10,7 +10,10 @@ use smithay::{
|
|||
calloop::RegistrationToken,
|
||||
wayland_server::{backend::GlobalId, Client, DisplayHandle},
|
||||
},
|
||||
wayland::{dmabuf::DmabufGlobal, socket::ListeningSocketSource},
|
||||
wayland::{
|
||||
dmabuf::{DmabufFeedbackBuilder, DmabufGlobal},
|
||||
socket::ListeningSocketSource,
|
||||
},
|
||||
xwayland::XWaylandClientData,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
|
@ -59,10 +62,14 @@ impl State {
|
|||
false
|
||||
};
|
||||
|
||||
let feedback = DmabufFeedbackBuilder::new(render_node.dev_id(), formats.clone())
|
||||
.build()
|
||||
.with_context(|| "Failed to create drm format shared memory table")?;
|
||||
|
||||
let dmabuf_global = self
|
||||
.common
|
||||
.dmabuf_state
|
||||
.create_global_with_filter::<State, _>(dh, formats.clone(), filter);
|
||||
.create_global_with_filter_and_default_feedback::<State, _>(dh, &feedback, filter);
|
||||
|
||||
let drm_global_id = self
|
||||
.common
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ impl WinitState {
|
|||
self.screencopy.clear();
|
||||
#[cfg(feature = "debug")]
|
||||
self.fps.displayed();
|
||||
state.send_frames(&self.output, &states);
|
||||
state.send_frames(&self.output, &states, None);
|
||||
if damage.is_some() {
|
||||
let mut output_presentation_feedback =
|
||||
state.take_presentation_feedback(&self.output, &states);
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ impl Surface {
|
|||
.with_context(|| "Failed to submit buffer for display")?;
|
||||
#[cfg(feature = "debug")]
|
||||
self.fps.displayed();
|
||||
state.send_frames(&self.output, &states);
|
||||
state.send_frames(&self.output, &states, None);
|
||||
if damage.is_some() {
|
||||
let mut output_presentation_feedback =
|
||||
state.take_presentation_feedback(&self.output, &states);
|
||||
|
|
|
|||
|
|
@ -2,13 +2,17 @@ use std::time::Duration;
|
|||
|
||||
use smithay::{
|
||||
backend::renderer::{
|
||||
element::{surface::WaylandSurfaceRenderElement, AsRenderElements},
|
||||
element::{
|
||||
surface::WaylandSurfaceRenderElement, utils::select_dmabuf_feedback, AsRenderElements,
|
||||
RenderElementStates,
|
||||
},
|
||||
ImportAll, Renderer,
|
||||
},
|
||||
desktop::{
|
||||
utils::{
|
||||
send_frames_surface_tree, take_presentation_feedback_surface_tree,
|
||||
with_surfaces_surface_tree, OutputPresentationFeedback,
|
||||
send_dmabuf_feedback_surface_tree, send_frames_surface_tree,
|
||||
take_presentation_feedback_surface_tree, with_surfaces_surface_tree,
|
||||
OutputPresentationFeedback,
|
||||
},
|
||||
Window,
|
||||
},
|
||||
|
|
@ -34,6 +38,8 @@ use smithay::{
|
|||
xwayland::{xwm::X11Relatable, X11Surface},
|
||||
};
|
||||
|
||||
use crate::state::SurfaceDmabufFeedback;
|
||||
|
||||
space_elements! {
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub CosmicSurface;
|
||||
|
|
@ -369,7 +375,7 @@ impl CosmicSurface {
|
|||
{
|
||||
match self {
|
||||
CosmicSurface::Wayland(window) => {
|
||||
window.send_frame(output, time, throttle, primary_scan_out_output)
|
||||
window.send_frame(output, time, throttle, primary_scan_out_output);
|
||||
}
|
||||
CosmicSurface::X11(surface) => {
|
||||
if let Some(wl_surface) = surface.wl_surface() {
|
||||
|
|
@ -386,6 +392,47 @@ impl CosmicSurface {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn send_dmabuf_feedback<F1>(
|
||||
&self,
|
||||
output: &Output,
|
||||
feedback: &SurfaceDmabufFeedback,
|
||||
render_element_states: &RenderElementStates,
|
||||
primary_scan_out_output: F1,
|
||||
) where
|
||||
F1: FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy,
|
||||
{
|
||||
match self {
|
||||
CosmicSurface::Wayland(window) => {
|
||||
window.send_dmabuf_feedback(output, primary_scan_out_output, |surface, _| {
|
||||
select_dmabuf_feedback(
|
||||
surface,
|
||||
render_element_states,
|
||||
&feedback.render_feedback,
|
||||
&feedback.scanout_feedback,
|
||||
)
|
||||
})
|
||||
}
|
||||
CosmicSurface::X11(surface) => {
|
||||
if let Some(wl_surface) = surface.wl_surface() {
|
||||
send_dmabuf_feedback_surface_tree(
|
||||
&wl_surface,
|
||||
output,
|
||||
primary_scan_out_output,
|
||||
|surface, _| {
|
||||
select_dmabuf_feedback(
|
||||
surface,
|
||||
render_element_states,
|
||||
&feedback.render_feedback,
|
||||
&feedback.scanout_feedback,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take_presentation_feedback<F1, F2>(
|
||||
&self,
|
||||
output_feedback: &mut OutputPresentationFeedback,
|
||||
|
|
|
|||
|
|
@ -6,12 +6,13 @@ use crate::{
|
|||
element::{window::CosmicWindowRenderElement, CosmicMapped, CosmicMappedRenderElement},
|
||||
focus::target::{KeyboardFocusTarget, PointerFocusTarget},
|
||||
},
|
||||
state::SurfaceDmabufFeedback,
|
||||
utils::prelude::*,
|
||||
};
|
||||
|
||||
use smithay::{
|
||||
backend::renderer::{
|
||||
element::{AsRenderElements, RenderElement},
|
||||
element::{AsRenderElements, RenderElement, RenderElementStates},
|
||||
ImportAll, ImportMem, Renderer,
|
||||
},
|
||||
desktop::space::SpaceElement,
|
||||
|
|
@ -91,6 +92,21 @@ impl MoveGrabState {
|
|||
.active_window()
|
||||
.send_frame(output, time, throttle, primary_scan_out_output)
|
||||
}
|
||||
|
||||
pub fn send_dmabuf_feedback(
|
||||
&self,
|
||||
output: &Output,
|
||||
feedback: &SurfaceDmabufFeedback,
|
||||
render_element_states: &RenderElementStates,
|
||||
primary_scan_out_output: impl FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy,
|
||||
) {
|
||||
self.window.active_window().send_dmabuf_feedback(
|
||||
output,
|
||||
feedback,
|
||||
render_element_states,
|
||||
primary_scan_out_output,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MoveSurfaceGrab {
|
||||
|
|
|
|||
74
src/state.rs
74
src/state.rs
|
|
@ -20,15 +20,18 @@ use smithay::{
|
|||
backend::{
|
||||
drm::DrmNode,
|
||||
renderer::{
|
||||
element::{default_primary_scanout_output_compare, RenderElementStates},
|
||||
element::{
|
||||
default_primary_scanout_output_compare, utils::select_dmabuf_feedback,
|
||||
RenderElementStates,
|
||||
},
|
||||
glow::GlowRenderer,
|
||||
},
|
||||
},
|
||||
desktop::utils::{
|
||||
send_frames_surface_tree, surface_presentation_feedback_flags_from_states,
|
||||
surface_primary_scanout_output, take_presentation_feedback_surface_tree,
|
||||
update_surface_primary_scanout_output, with_surfaces_surface_tree,
|
||||
OutputPresentationFeedback,
|
||||
send_dmabuf_feedback_surface_tree, send_frames_surface_tree,
|
||||
surface_presentation_feedback_flags_from_states, surface_primary_scanout_output,
|
||||
take_presentation_feedback_surface_tree, update_surface_primary_scanout_output,
|
||||
with_surfaces_surface_tree, OutputPresentationFeedback,
|
||||
},
|
||||
input::{pointer::CursorImageStatus, Seat, SeatState},
|
||||
output::{Mode as OutputMode, Output, Scale},
|
||||
|
|
@ -45,7 +48,7 @@ use smithay::{
|
|||
wayland::{
|
||||
compositor::CompositorState,
|
||||
data_device::DataDeviceState,
|
||||
dmabuf::DmabufState,
|
||||
dmabuf::{DmabufFeedback, DmabufState},
|
||||
keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState,
|
||||
output::OutputManagerState,
|
||||
presentation::PresentationState,
|
||||
|
|
@ -130,6 +133,11 @@ pub enum BackendData {
|
|||
Unset,
|
||||
}
|
||||
|
||||
pub struct SurfaceDmabufFeedback {
|
||||
pub render_feedback: DmabufFeedback,
|
||||
pub scanout_feedback: DmabufFeedback,
|
||||
}
|
||||
|
||||
impl BackendData {
|
||||
pub fn kms(&mut self) -> &mut KmsState {
|
||||
match self {
|
||||
|
|
@ -363,7 +371,12 @@ impl Common {
|
|||
self.last_active_seat.as_ref().expect("No seat?")
|
||||
}
|
||||
|
||||
pub fn send_frames(&self, output: &Output, render_element_states: &RenderElementStates) {
|
||||
pub fn send_frames(
|
||||
&self,
|
||||
output: &Output,
|
||||
render_element_states: &RenderElementStates,
|
||||
dmabuf_feedback: Option<&SurfaceDmabufFeedback>,
|
||||
) {
|
||||
let time = self.clock.now();
|
||||
let throttle = Some(Duration::from_secs(1));
|
||||
|
||||
|
|
@ -401,6 +414,14 @@ impl Common {
|
|||
throttle,
|
||||
surface_primary_scanout_output,
|
||||
);
|
||||
if let Some(feedback) = dmabuf_feedback {
|
||||
grab_state.send_dmabuf_feedback(
|
||||
output,
|
||||
feedback,
|
||||
render_element_states,
|
||||
surface_primary_scanout_output,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -432,6 +453,14 @@ impl Common {
|
|||
);
|
||||
});
|
||||
window.send_frame(output, time, throttle, surface_primary_scanout_output);
|
||||
if let Some(feedback) = dmabuf_feedback {
|
||||
window.send_dmabuf_feedback(
|
||||
output,
|
||||
feedback,
|
||||
render_element_states,
|
||||
surface_primary_scanout_output,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -466,7 +495,22 @@ impl Common {
|
|||
time,
|
||||
throttle,
|
||||
surface_primary_scanout_output,
|
||||
)
|
||||
);
|
||||
if let Some(feedback) = dmabuf_feedback {
|
||||
send_dmabuf_feedback_surface_tree(
|
||||
&wl_surface,
|
||||
output,
|
||||
surface_primary_scanout_output,
|
||||
|surface, _| {
|
||||
select_dmabuf_feedback(
|
||||
surface,
|
||||
render_element_states,
|
||||
&feedback.render_feedback,
|
||||
&feedback.scanout_feedback,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -482,6 +526,20 @@ impl Common {
|
|||
);
|
||||
});
|
||||
layer_surface.send_frame(output, time, throttle, surface_primary_scanout_output);
|
||||
if let Some(feedback) = dmabuf_feedback {
|
||||
layer_surface.send_dmabuf_feedback(
|
||||
output,
|
||||
surface_primary_scanout_output,
|
||||
|surface, _| {
|
||||
select_dmabuf_feedback(
|
||||
surface,
|
||||
render_element_states,
|
||||
&feedback.render_feedback,
|
||||
&feedback.scanout_feedback,
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use smithay::{
|
|||
Bind, Blit, BufferType, ExportMem, ImportAll, ImportMem, Offscreen, Renderer,
|
||||
},
|
||||
},
|
||||
desktop::{layer_map_for_output, space::SpaceElement},
|
||||
desktop::{layer_map_for_output, space::SpaceElement, utils::surface_primary_scanout_output},
|
||||
output::Output,
|
||||
reexports::wayland_server::{
|
||||
protocol::{wl_buffer::WlBuffer, wl_shm::Format as ShmFormat, wl_surface::WlSurface},
|
||||
|
|
@ -33,7 +33,8 @@ use smithay::{
|
|||
},
|
||||
utils::{IsAlive, Logical, Physical, Rectangle, Scale, Transform},
|
||||
wayland::{
|
||||
dmabuf::get_dmabuf,
|
||||
compositor::with_states,
|
||||
dmabuf::{get_dmabuf, SurfaceDmabufFeedbackState},
|
||||
seat::WaylandFocus,
|
||||
shm::{with_buffer_contents, with_buffer_contents_mut},
|
||||
},
|
||||
|
|
@ -178,9 +179,21 @@ impl ScreencopyHandler for State {
|
|||
.get_client(surface.id())
|
||||
.ok()
|
||||
.and_then(|client| {
|
||||
// has the client requested surface-feedback? If yes it is properly rendering on the node of the display
|
||||
if with_states(&surface, |data| {
|
||||
SurfaceDmabufFeedbackState::from_states(data).is_some()
|
||||
}) {
|
||||
if let Some(output) = with_states(&surface, |data| {
|
||||
surface_primary_scanout_output(&surface, data)
|
||||
}) {
|
||||
return kms.target_node_for_output(&output);
|
||||
}
|
||||
}
|
||||
// else lets check the global drm-node the client got either through default-feedback or wl_drm
|
||||
if let Some(normal_client) = client.get_data::<ClientState>() {
|
||||
return normal_client.drm_node.clone();
|
||||
}
|
||||
// last but not least all xwayland-surfaces should also share a single node
|
||||
if let Some(xwayland_client) = client.get_data::<XWaylandClientData>() {
|
||||
return xwayland_client.user_data().get::<DrmNode>().cloned();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue