kms: Dmabuf feedback support
This commit is contained in:
parent
636d38921a
commit
bc49507353
8 changed files with 267 additions and 36 deletions
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
backend::render::{workspace_elements, CLEAR_COLOR},
|
backend::render::{workspace_elements, CLEAR_COLOR},
|
||||||
config::OutputConfig,
|
config::OutputConfig,
|
||||||
shell::Shell,
|
shell::Shell,
|
||||||
state::{BackendData, ClientState, Common, Data, Fps},
|
state::{BackendData, ClientState, Common, Data, Fps, SurfaceDmabufFeedback},
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
wayland::{
|
wayland::{
|
||||||
handlers::screencopy::{render_session, UserdataExt},
|
handlers::screencopy::{render_session, UserdataExt},
|
||||||
|
|
@ -22,7 +22,7 @@ use smithay::{
|
||||||
dmabuf::{AnyError, AsDmabuf, Dmabuf, DmabufAllocator},
|
dmabuf::{AnyError, AsDmabuf, Dmabuf, DmabufAllocator},
|
||||||
gbm::{GbmAllocator, GbmBufferFlags, GbmDevice},
|
gbm::{GbmAllocator, GbmBufferFlags, GbmDevice},
|
||||||
vulkan::{ImageUsageFlags, VulkanAllocator},
|
vulkan::{ImageUsageFlags, VulkanAllocator},
|
||||||
Allocator, Format,
|
Allocator, Format, Fourcc,
|
||||||
},
|
},
|
||||||
drm::{
|
drm::{
|
||||||
compositor::{DrmCompositor, PrimaryPlaneElement},
|
compositor::{DrmCompositor, PrimaryPlaneElement},
|
||||||
|
|
@ -38,7 +38,7 @@ use smithay::{
|
||||||
glow::GlowRenderer,
|
glow::GlowRenderer,
|
||||||
multigpu::{gbm::GbmGlesBackend, Error as MultiError, GpuManager},
|
multigpu::{gbm::GbmGlesBackend, Error as MultiError, GpuManager},
|
||||||
utils::draw_render_elements,
|
utils::draw_render_elements,
|
||||||
Bind, Blit, Offscreen, Renderer, TextureFilter,
|
Bind, Blit, ImportDma, Offscreen, Renderer, TextureFilter,
|
||||||
},
|
},
|
||||||
session::{libseat::LibSeatSession, Event as SessionEvent, Session},
|
session::{libseat::LibSeatSession, Event as SessionEvent, Session},
|
||||||
udev::{all_gpus, primary_gpu, UdevBackend, UdevEvent},
|
udev::{all_gpus, primary_gpu, UdevBackend, UdevEvent},
|
||||||
|
|
@ -58,12 +58,15 @@ use smithay::{
|
||||||
},
|
},
|
||||||
input::Libinput,
|
input::Libinput,
|
||||||
nix::{fcntl::OFlag, sys::stat::dev_t},
|
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},
|
wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle, Resource},
|
||||||
},
|
},
|
||||||
utils::{DeviceFd, Size, Transform},
|
utils::{DeviceFd, Size, Transform},
|
||||||
wayland::{
|
wayland::{
|
||||||
dmabuf::{get_dmabuf, DmabufGlobal},
|
dmabuf::{get_dmabuf, DmabufFeedbackBuilder, DmabufGlobal},
|
||||||
relative_pointer::RelativePointerManagerState,
|
relative_pointer::RelativePointerManagerState,
|
||||||
seat::WaylandFocus,
|
seat::WaylandFocus,
|
||||||
},
|
},
|
||||||
|
|
@ -119,6 +122,7 @@ pub struct Surface {
|
||||||
dirty: bool,
|
dirty: bool,
|
||||||
render_timer_token: Option<RegistrationToken>,
|
render_timer_token: Option<RegistrationToken>,
|
||||||
fps: Fps,
|
fps: Fps,
|
||||||
|
feedback: HashMap<DrmNode, SurfaceDmabufFeedback>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type GbmDrmCompositor = DrmCompositor<
|
pub type GbmDrmCompositor = DrmCompositor<
|
||||||
|
|
@ -420,7 +424,7 @@ impl State {
|
||||||
path.display()
|
path.display()
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
let formats = egl_context.dmabuf_render_formats().clone();
|
let formats = egl_context.dmabuf_texture_formats().clone();
|
||||||
(render_node, formats)
|
(render_node, formats)
|
||||||
// NOTE: We need the to drop the EGL types here again,
|
// NOTE: We need the to drop the EGL types here again,
|
||||||
// otherwise the EGLDisplay created below might share the same GBM context
|
// otherwise the EGLDisplay created below might share the same GBM context
|
||||||
|
|
@ -889,6 +893,7 @@ impl Device {
|
||||||
dirty: false,
|
dirty: false,
|
||||||
render_timer_token: None,
|
render_timer_token: None,
|
||||||
fps: Fps::new(renderer.as_mut()),
|
fps: Fps::new(renderer.as_mut()),
|
||||||
|
feedback: HashMap::new(),
|
||||||
};
|
};
|
||||||
self.surfaces.insert(crtc, data);
|
self.surfaces.insert(crtc, data);
|
||||||
|
|
||||||
|
|
@ -896,6 +901,19 @@ impl Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn source_node_for_surface(w: &WlSurface, dh: &DisplayHandle) -> Option<DrmNode> {
|
||||||
|
// Lets check the global drm-node the client got either through default-feedback or wl_drm
|
||||||
|
let client = dh.get_client(w.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();
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn render_node_for_output(
|
fn render_node_for_output(
|
||||||
dh: &DisplayHandle,
|
dh: &DisplayHandle,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
|
|
@ -908,16 +926,7 @@ fn render_node_for_output(
|
||||||
.map(|w| vec![w.clone()])
|
.map(|w| vec![w.clone()])
|
||||||
.unwrap_or_else(|| workspace.windows().collect::<Vec<_>>())
|
.unwrap_or_else(|| workspace.windows().collect::<Vec<_>>())
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|w| {
|
.flat_map(|w| w.wl_surface().and_then(|s| source_node_for_surface(&s, dh)))
|
||||||
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();
|
|
||||||
}
|
|
||||||
if let Some(xwayland_client) = client.get_data::<XWaylandClientData>() {
|
|
||||||
return xwayland_client.user_data().get::<DrmNode>().cloned();
|
|
||||||
}
|
|
||||||
None
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
if nodes.contains(&target_node) || nodes.is_empty() {
|
if nodes.contains(&target_node) || nodes.is_empty() {
|
||||||
target_node
|
target_node
|
||||||
|
|
@ -936,6 +945,59 @@ fn render_node_for_output(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_surface_dmabuf_feedback(
|
||||||
|
render_node: DrmNode,
|
||||||
|
render_formats: HashSet<Format>,
|
||||||
|
target_formats: HashSet<Format>,
|
||||||
|
compositor: &GbmDrmCompositor,
|
||||||
|
) -> SurfaceDmabufFeedback {
|
||||||
|
let combined_formats = render_formats
|
||||||
|
.intersection(&target_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(&combined_formats)
|
||||||
|
.copied()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let target_node = surface.device_fd().dev_id().unwrap();
|
||||||
|
let mut builder = DmabufFeedbackBuilder::new(render_node.dev_id(), render_formats);
|
||||||
|
if target_node != render_node.dev_id() && !combined_formats.is_empty() {
|
||||||
|
builder = builder.add_preference_tranche(target_node, None, combined_formats);
|
||||||
|
};
|
||||||
|
let render_feedback = builder.clone().build().unwrap();
|
||||||
|
|
||||||
|
let scanout_feedback = builder
|
||||||
|
.add_preference_tranche(
|
||||||
|
target_node,
|
||||||
|
Some(zwp_linux_dmabuf_feedback_v1::TrancheFlags::Scanout),
|
||||||
|
planes_formats,
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
SurfaceDmabufFeedback {
|
||||||
|
render_feedback,
|
||||||
|
scanout_feedback,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Surface {
|
impl Surface {
|
||||||
pub fn render_output(
|
pub fn render_output(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -1088,7 +1150,34 @@ impl Surface {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
state.send_frames(&self.output, &frame_result.states);
|
|
||||||
|
state.send_frames(&self.output, &frame_result.states, |source_node| {
|
||||||
|
Some(
|
||||||
|
self.feedback
|
||||||
|
.entry(source_node)
|
||||||
|
.or_insert_with(|| {
|
||||||
|
let render_formats = api
|
||||||
|
.single_renderer(&source_node)
|
||||||
|
.unwrap()
|
||||||
|
.dmabuf_formats()
|
||||||
|
.copied()
|
||||||
|
.collect::<HashSet<_>>();
|
||||||
|
let target_formats = api
|
||||||
|
.single_renderer(target_node)
|
||||||
|
.unwrap()
|
||||||
|
.dmabuf_formats()
|
||||||
|
.copied()
|
||||||
|
.collect::<HashSet<_>>();
|
||||||
|
get_surface_dmabuf_feedback(
|
||||||
|
source_node,
|
||||||
|
render_formats,
|
||||||
|
target_formats,
|
||||||
|
compositor,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.clone(),
|
||||||
|
)
|
||||||
|
});
|
||||||
compositor
|
compositor
|
||||||
.queue_frame(feedback)
|
.queue_frame(feedback)
|
||||||
.with_context(|| "Failed to submit result for display")?
|
.with_context(|| "Failed to submit result for display")?
|
||||||
|
|
@ -1204,6 +1293,7 @@ impl KmsState {
|
||||||
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
|
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
|
||||||
),
|
),
|
||||||
device.gbm.clone(),
|
device.gbm.clone(),
|
||||||
|
&[Fourcc::Abgr8888, Fourcc::Argb8888],
|
||||||
device.formats.clone(),
|
device.formats.clone(),
|
||||||
drm.cursor_size(),
|
drm.cursor_size(),
|
||||||
Some(device.gbm.clone()),
|
Some(device.gbm.clone()),
|
||||||
|
|
@ -1287,8 +1377,6 @@ impl KmsState {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dmabuf_imported(&mut self, global: &DmabufGlobal, dmabuf: Dmabuf) -> Result<()> {
|
pub fn dmabuf_imported(&mut self, global: &DmabufGlobal, dmabuf: Dmabuf) -> Result<()> {
|
||||||
use smithay::backend::renderer::ImportDma;
|
|
||||||
|
|
||||||
for device in self.devices.values() {
|
for device in self.devices.values() {
|
||||||
if device
|
if device
|
||||||
.socket
|
.socket
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,10 @@ use smithay::{
|
||||||
calloop::RegistrationToken,
|
calloop::RegistrationToken,
|
||||||
wayland_server::{backend::GlobalId, Client, DisplayHandle},
|
wayland_server::{backend::GlobalId, Client, DisplayHandle},
|
||||||
},
|
},
|
||||||
wayland::{dmabuf::DmabufGlobal, socket::ListeningSocketSource},
|
wayland::{
|
||||||
|
dmabuf::{DmabufFeedbackBuilder, DmabufGlobal},
|
||||||
|
socket::ListeningSocketSource,
|
||||||
|
},
|
||||||
xwayland::XWaylandClientData,
|
xwayland::XWaylandClientData,
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
@ -59,10 +62,14 @@ impl State {
|
||||||
false
|
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
|
let dmabuf_global = self
|
||||||
.common
|
.common
|
||||||
.dmabuf_state
|
.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
|
let drm_global_id = self
|
||||||
.common
|
.common
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ impl WinitState {
|
||||||
self.screencopy.clear();
|
self.screencopy.clear();
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
self.fps.displayed();
|
self.fps.displayed();
|
||||||
state.send_frames(&self.output, &states);
|
state.send_frames(&self.output, &states, |_| None);
|
||||||
if damage.is_some() {
|
if damage.is_some() {
|
||||||
let mut output_presentation_feedback =
|
let mut output_presentation_feedback =
|
||||||
state.take_presentation_feedback(&self.output, &states);
|
state.take_presentation_feedback(&self.output, &states);
|
||||||
|
|
|
||||||
|
|
@ -247,7 +247,7 @@ impl Surface {
|
||||||
.with_context(|| "Failed to submit buffer for display")?;
|
.with_context(|| "Failed to submit buffer for display")?;
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
self.fps.displayed();
|
self.fps.displayed();
|
||||||
state.send_frames(&self.output, &states);
|
state.send_frames(&self.output, &states, |_| None);
|
||||||
if damage.is_some() {
|
if damage.is_some() {
|
||||||
let mut output_presentation_feedback =
|
let mut output_presentation_feedback =
|
||||||
state.take_presentation_feedback(&self.output, &states);
|
state.take_presentation_feedback(&self.output, &states);
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,17 @@ use std::time::Duration;
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::{
|
backend::renderer::{
|
||||||
element::{surface::WaylandSurfaceRenderElement, AsRenderElements},
|
element::{
|
||||||
|
surface::WaylandSurfaceRenderElement, utils::select_dmabuf_feedback, AsRenderElements,
|
||||||
|
RenderElementStates,
|
||||||
|
},
|
||||||
ImportAll, Renderer,
|
ImportAll, Renderer,
|
||||||
},
|
},
|
||||||
desktop::{
|
desktop::{
|
||||||
utils::{
|
utils::{
|
||||||
send_frames_surface_tree, take_presentation_feedback_surface_tree,
|
send_dmabuf_feedback_surface_tree, send_frames_surface_tree,
|
||||||
with_surfaces_surface_tree, OutputPresentationFeedback,
|
take_presentation_feedback_surface_tree, with_surfaces_surface_tree,
|
||||||
|
OutputPresentationFeedback,
|
||||||
},
|
},
|
||||||
Window,
|
Window,
|
||||||
},
|
},
|
||||||
|
|
@ -34,6 +38,8 @@ use smithay::{
|
||||||
xwayland::{xwm::X11Relatable, X11Surface},
|
xwayland::{xwm::X11Relatable, X11Surface},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::state::SurfaceDmabufFeedback;
|
||||||
|
|
||||||
space_elements! {
|
space_elements! {
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub CosmicSurface;
|
pub CosmicSurface;
|
||||||
|
|
@ -369,7 +375,7 @@ impl CosmicSurface {
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
CosmicSurface::Wayland(window) => {
|
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) => {
|
CosmicSurface::X11(surface) => {
|
||||||
if let Some(wl_surface) = surface.wl_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>(
|
pub fn take_presentation_feedback<F1, F2>(
|
||||||
&self,
|
&self,
|
||||||
output_feedback: &mut OutputPresentationFeedback,
|
output_feedback: &mut OutputPresentationFeedback,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use crate::{
|
||||||
shell::{
|
shell::{
|
||||||
element::{window::CosmicWindowRenderElement, CosmicMapped, CosmicMappedRenderElement},
|
element::{window::CosmicWindowRenderElement, CosmicMapped, CosmicMappedRenderElement},
|
||||||
focus::target::{KeyboardFocusTarget, PointerFocusTarget},
|
focus::target::{KeyboardFocusTarget, PointerFocusTarget},
|
||||||
|
CosmicSurface,
|
||||||
},
|
},
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
};
|
};
|
||||||
|
|
@ -91,6 +92,10 @@ impl MoveGrabState {
|
||||||
.active_window()
|
.active_window()
|
||||||
.send_frame(output, time, throttle, primary_scan_out_output)
|
.send_frame(output, time, throttle, primary_scan_out_output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn window(&self) -> CosmicSurface {
|
||||||
|
self.window.active_window()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MoveSurfaceGrab {
|
pub struct MoveSurfaceGrab {
|
||||||
|
|
|
||||||
100
src/state.rs
100
src/state.rs
|
|
@ -1,7 +1,11 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{kms::KmsState, winit::WinitState, x11::X11State},
|
backend::{
|
||||||
|
kms::{source_node_for_surface, KmsState},
|
||||||
|
winit::WinitState,
|
||||||
|
x11::X11State,
|
||||||
|
},
|
||||||
config::{Config, OutputConfig},
|
config::{Config, OutputConfig},
|
||||||
shell::{layout::floating::SeatMoveGrabState, Shell},
|
shell::{layout::floating::SeatMoveGrabState, Shell},
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
|
|
@ -20,15 +24,18 @@ use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
drm::DrmNode,
|
drm::DrmNode,
|
||||||
renderer::{
|
renderer::{
|
||||||
element::{default_primary_scanout_output_compare, RenderElementStates},
|
element::{
|
||||||
|
default_primary_scanout_output_compare, utils::select_dmabuf_feedback,
|
||||||
|
RenderElementStates,
|
||||||
|
},
|
||||||
glow::GlowRenderer,
|
glow::GlowRenderer,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
desktop::utils::{
|
desktop::utils::{
|
||||||
send_frames_surface_tree, surface_presentation_feedback_flags_from_states,
|
send_dmabuf_feedback_surface_tree, send_frames_surface_tree,
|
||||||
surface_primary_scanout_output, take_presentation_feedback_surface_tree,
|
surface_presentation_feedback_flags_from_states, surface_primary_scanout_output,
|
||||||
update_surface_primary_scanout_output, with_surfaces_surface_tree,
|
take_presentation_feedback_surface_tree, update_surface_primary_scanout_output,
|
||||||
OutputPresentationFeedback,
|
with_surfaces_surface_tree, OutputPresentationFeedback,
|
||||||
},
|
},
|
||||||
input::{pointer::CursorImageStatus, Seat, SeatState},
|
input::{pointer::CursorImageStatus, Seat, SeatState},
|
||||||
output::{Mode as OutputMode, Output, Scale},
|
output::{Mode as OutputMode, Output, Scale},
|
||||||
|
|
@ -45,11 +52,12 @@ use smithay::{
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::CompositorState,
|
compositor::CompositorState,
|
||||||
data_device::DataDeviceState,
|
data_device::DataDeviceState,
|
||||||
dmabuf::DmabufState,
|
dmabuf::{DmabufFeedback, DmabufState},
|
||||||
keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState,
|
keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState,
|
||||||
output::OutputManagerState,
|
output::OutputManagerState,
|
||||||
presentation::PresentationState,
|
presentation::PresentationState,
|
||||||
primary_selection::PrimarySelectionState,
|
primary_selection::PrimarySelectionState,
|
||||||
|
seat::WaylandFocus,
|
||||||
shell::{kde::decoration::KdeDecorationState, xdg::decoration::XdgDecorationState},
|
shell::{kde::decoration::KdeDecorationState, xdg::decoration::XdgDecorationState},
|
||||||
shm::ShmState,
|
shm::ShmState,
|
||||||
viewporter::ViewporterState,
|
viewporter::ViewporterState,
|
||||||
|
|
@ -130,6 +138,12 @@ pub enum BackendData {
|
||||||
Unset,
|
Unset,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct SurfaceDmabufFeedback {
|
||||||
|
pub render_feedback: DmabufFeedback,
|
||||||
|
pub scanout_feedback: DmabufFeedback,
|
||||||
|
}
|
||||||
|
|
||||||
impl BackendData {
|
impl BackendData {
|
||||||
pub fn kms(&mut self) -> &mut KmsState {
|
pub fn kms(&mut self) -> &mut KmsState {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -363,7 +377,12 @@ impl Common {
|
||||||
self.last_active_seat.as_ref().expect("No seat?")
|
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,
|
||||||
|
mut dmabuf_feedback: impl FnMut(DrmNode) -> Option<SurfaceDmabufFeedback>,
|
||||||
|
) {
|
||||||
let time = self.clock.now();
|
let time = self.clock.now();
|
||||||
let throttle = Some(Duration::from_secs(1));
|
let throttle = Some(Duration::from_secs(1));
|
||||||
|
|
||||||
|
|
@ -401,6 +420,21 @@ impl Common {
|
||||||
throttle,
|
throttle,
|
||||||
surface_primary_scanout_output,
|
surface_primary_scanout_output,
|
||||||
);
|
);
|
||||||
|
let window = grab_state.window();
|
||||||
|
if let Some(feedback) = window
|
||||||
|
.wl_surface()
|
||||||
|
.and_then(|wl_surface| {
|
||||||
|
source_node_for_surface(&wl_surface, &self.display_handle)
|
||||||
|
})
|
||||||
|
.and_then(|source| dmabuf_feedback(source))
|
||||||
|
{
|
||||||
|
window.send_dmabuf_feedback(
|
||||||
|
output,
|
||||||
|
&feedback,
|
||||||
|
render_element_states,
|
||||||
|
surface_primary_scanout_output,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -432,6 +466,20 @@ impl Common {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
window.send_frame(output, time, throttle, surface_primary_scanout_output);
|
window.send_frame(output, time, throttle, surface_primary_scanout_output);
|
||||||
|
if let Some(feedback) = window
|
||||||
|
.wl_surface()
|
||||||
|
.and_then(|wl_surface| {
|
||||||
|
source_node_for_surface(&wl_surface, &self.display_handle)
|
||||||
|
})
|
||||||
|
.and_then(|source| dmabuf_feedback(source))
|
||||||
|
{
|
||||||
|
window.send_dmabuf_feedback(
|
||||||
|
output,
|
||||||
|
&feedback,
|
||||||
|
render_element_states,
|
||||||
|
surface_primary_scanout_output,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -466,7 +514,24 @@ impl Common {
|
||||||
time,
|
time,
|
||||||
throttle,
|
throttle,
|
||||||
surface_primary_scanout_output,
|
surface_primary_scanout_output,
|
||||||
)
|
);
|
||||||
|
if let Some(feedback) = source_node_for_surface(&wl_surface, &self.display_handle)
|
||||||
|
.and_then(|source| dmabuf_feedback(source))
|
||||||
|
{
|
||||||
|
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 +547,23 @@ impl Common {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
layer_surface.send_frame(output, time, throttle, surface_primary_scanout_output);
|
layer_surface.send_frame(output, time, throttle, surface_primary_scanout_output);
|
||||||
|
if let Some(feedback) =
|
||||||
|
source_node_for_surface(layer_surface.wl_surface(), &self.display_handle)
|
||||||
|
.and_then(|source| dmabuf_feedback(source))
|
||||||
|
{
|
||||||
|
layer_surface.send_dmabuf_feedback(
|
||||||
|
output,
|
||||||
|
surface_primary_scanout_output,
|
||||||
|
|surface, _| {
|
||||||
|
select_dmabuf_feedback(
|
||||||
|
surface,
|
||||||
|
render_element_states,
|
||||||
|
&feedback.render_feedback,
|
||||||
|
&feedback.scanout_feedback,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -178,9 +178,11 @@ impl ScreencopyHandler for State {
|
||||||
.get_client(surface.id())
|
.get_client(surface.id())
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|client| {
|
.and_then(|client| {
|
||||||
|
// 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>() {
|
if let Some(normal_client) = client.get_data::<ClientState>() {
|
||||||
return normal_client.drm_node.clone();
|
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>() {
|
if let Some(xwayland_client) = client.get_data::<XWaylandClientData>() {
|
||||||
return xwayland_client.user_data().get::<DrmNode>().cloned();
|
return xwayland_client.user_data().get::<DrmNode>().cloned();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue