fix: honor screencopy cursor overlay requests
This commit is contained in:
1 parent
4a1eab5b4a
commit
f0862348c9
4 files changed
+130
-13
No files matched your search
@@ -71,9 +71,8 @@ FERESE_ENABLE_SCREENCOPY=1 cargo run -p ferese
|
||||
```
|
||||
|
||||
The current M5 implementation supports one-shot output and region capture into
|
||||
ARGB8888 shared-memory buffers. Captures currently include Ferese's software
|
||||
cursor even when a client does not request a cursor overlay; cursor-free
|
||||
capture remains part of the M5 interoperability acceptance work.
|
||||
ARGB8888 shared-memory buffers. Cursor overlays are included only when the
|
||||
capture client requests them.
|
||||
|
||||
### Direct DRM session
|
||||
|
||||
|
||||
@@ -38,7 +38,10 @@ use smithay::{
|
||||
wayland::presentation::Refresh,
|
||||
};
|
||||
|
||||
use crate::{Ferese, winit::animated_window_elements};
|
||||
use crate::{
|
||||
Ferese,
|
||||
winit::{animated_window_elements, cursorless_window_elements, redraw_output},
|
||||
};
|
||||
|
||||
pub struct DirectBackendState {
|
||||
pub session: LibSeatSession,
|
||||
@@ -349,7 +352,27 @@ fn render_output(state: &mut Ferese, node: DrmNode, crtc: crtc::Handle) {
|
||||
&elements,
|
||||
[0.035, 0.04, 0.055, 1.0],
|
||||
)?;
|
||||
if state.process_screencopies(&mut device.renderer, &framebuffer, &output.output) {
|
||||
let cursorless_capture = state.has_pending_screencopy(&output.output, false);
|
||||
let captured_with_cursor =
|
||||
state.process_screencopies(&mut device.renderer, &framebuffer, &output.output, true);
|
||||
|
||||
if cursorless_capture {
|
||||
let cursorless_elements =
|
||||
cursorless_window_elements(state, &mut device.renderer, &output.output);
|
||||
redraw_output(
|
||||
&mut device.renderer,
|
||||
&mut framebuffer,
|
||||
&output.output,
|
||||
&cursorless_elements,
|
||||
)?;
|
||||
state.process_screencopies(&mut device.renderer, &framebuffer, &output.output, false);
|
||||
redraw_output(
|
||||
&mut device.renderer,
|
||||
&mut framebuffer,
|
||||
&output.output,
|
||||
&elements,
|
||||
)?;
|
||||
} else if captured_with_cursor {
|
||||
let _ = device
|
||||
.renderer
|
||||
.render(
|
||||
|
||||
@@ -28,6 +28,7 @@ const BYTES_PER_PIXEL: usize = 4;
|
||||
pub(crate) struct FrameData {
|
||||
output: Option<Output>,
|
||||
region: Rectangle<i32, Buffer>,
|
||||
overlay_cursor: bool,
|
||||
used: Mutex<bool>,
|
||||
}
|
||||
|
||||
@@ -37,6 +38,7 @@ pub(crate) struct PendingScreencopy {
|
||||
buffer: WlBuffer,
|
||||
pub(crate) output: Output,
|
||||
region: Rectangle<i32, Buffer>,
|
||||
overlay_cursor: bool,
|
||||
with_damage: bool,
|
||||
}
|
||||
|
||||
@@ -75,14 +77,14 @@ impl Dispatch<ZwlrScreencopyManagerV1, ()> for Ferese {
|
||||
match request {
|
||||
zwlr_screencopy_manager_v1::Request::CaptureOutput {
|
||||
frame,
|
||||
overlay_cursor: _,
|
||||
overlay_cursor,
|
||||
output,
|
||||
} => {
|
||||
create_frame(data_init, frame, output, None);
|
||||
create_frame(data_init, frame, output, None, overlay_cursor != 0);
|
||||
}
|
||||
zwlr_screencopy_manager_v1::Request::CaptureOutputRegion {
|
||||
frame,
|
||||
overlay_cursor: _,
|
||||
overlay_cursor,
|
||||
output,
|
||||
x,
|
||||
y,
|
||||
@@ -94,6 +96,7 @@ impl Dispatch<ZwlrScreencopyManagerV1, ()> for Ferese {
|
||||
frame,
|
||||
output,
|
||||
Some(Rectangle::new((x, y).into(), (width, height).into())),
|
||||
overlay_cursor != 0,
|
||||
);
|
||||
}
|
||||
zwlr_screencopy_manager_v1::Request::Destroy => {}
|
||||
@@ -161,6 +164,7 @@ impl Ferese {
|
||||
buffer,
|
||||
output,
|
||||
region: data.region,
|
||||
overlay_cursor: data.overlay_cursor,
|
||||
with_damage,
|
||||
});
|
||||
crate::backends::direct::render_all(self);
|
||||
@@ -171,6 +175,7 @@ impl Ferese {
|
||||
renderer: &mut R,
|
||||
framebuffer: &R::Framebuffer<'_>,
|
||||
output: &Output,
|
||||
overlay_cursor: bool,
|
||||
) -> bool
|
||||
where
|
||||
R: ExportMem,
|
||||
@@ -180,7 +185,9 @@ impl Ferese {
|
||||
let captures = std::mem::take(&mut self.pending_screencopies);
|
||||
|
||||
for capture in captures {
|
||||
if &capture.output != output {
|
||||
if &capture.output != output
|
||||
|| !cursor_overlay_matches(capture.overlay_cursor, overlay_cursor)
|
||||
{
|
||||
remaining.push(capture);
|
||||
continue;
|
||||
}
|
||||
@@ -198,6 +205,17 @@ impl Ferese {
|
||||
self.pending_screencopies = remaining;
|
||||
framebuffer_binding_changed
|
||||
}
|
||||
|
||||
pub(crate) fn has_pending_screencopy(&self, output: &Output, overlay_cursor: bool) -> bool {
|
||||
self.pending_screencopies.iter().any(|capture| {
|
||||
capture.output == *output
|
||||
&& cursor_overlay_matches(capture.overlay_cursor, overlay_cursor)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn cursor_overlay_matches(requested: bool, rendered: bool) -> bool {
|
||||
requested == rendered
|
||||
}
|
||||
|
||||
fn create_frame(
|
||||
@@ -205,6 +223,7 @@ fn create_frame(
|
||||
frame: New<ZwlrScreencopyFrameV1>,
|
||||
wl_output: smithay::reexports::wayland_server::protocol::wl_output::WlOutput,
|
||||
requested: Option<Rectangle<i32, Logical>>,
|
||||
overlay_cursor: bool,
|
||||
) {
|
||||
let Some(output) = Output::from_resource(&wl_output) else {
|
||||
let frame = data_init.init(
|
||||
@@ -212,6 +231,7 @@ fn create_frame(
|
||||
Arc::new(FrameData {
|
||||
output: None,
|
||||
region: Rectangle::from_size((1, 1).into()),
|
||||
overlay_cursor,
|
||||
used: Mutex::new(true),
|
||||
}),
|
||||
);
|
||||
@@ -224,6 +244,7 @@ fn create_frame(
|
||||
Arc::new(FrameData {
|
||||
output: Some(output),
|
||||
region: Rectangle::from_size((1, 1).into()),
|
||||
overlay_cursor,
|
||||
used: Mutex::new(true),
|
||||
}),
|
||||
);
|
||||
@@ -235,6 +256,7 @@ fn create_frame(
|
||||
let data = Arc::new(FrameData {
|
||||
output: Some(output),
|
||||
region,
|
||||
overlay_cursor,
|
||||
used: Mutex::new(false),
|
||||
});
|
||||
let frame = data_init.init(frame, data);
|
||||
@@ -392,4 +414,12 @@ mod tests {
|
||||
capture_region_for_geometry(mode, 2.0, Transform::Normal, Some(requested),).is_none()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cursor_overlay_requests_use_only_the_matching_render_pass() {
|
||||
assert!(cursor_overlay_matches(false, false));
|
||||
assert!(cursor_overlay_matches(true, true));
|
||||
assert!(!cursor_overlay_matches(false, true));
|
||||
assert!(!cursor_overlay_matches(true, false));
|
||||
}
|
||||
}
|
||||
+69
-4
@@ -6,10 +6,10 @@ use std::{
|
||||
use smithay::{
|
||||
backend::{
|
||||
renderer::{
|
||||
Frame, ImportDma, Renderer,
|
||||
Color32F, Frame, ImportDma, Renderer,
|
||||
damage::OutputDamageTracker,
|
||||
element::{
|
||||
AsRenderElements, Kind as RenderElementKind,
|
||||
AsRenderElements, Kind as RenderElementKind, RenderElement,
|
||||
memory::MemoryRenderBufferRenderElement,
|
||||
render_elements,
|
||||
surface::{WaylandSurfaceRenderElement, render_elements_from_surface_tree},
|
||||
@@ -19,6 +19,7 @@ use smithay::{
|
||||
},
|
||||
},
|
||||
gles::GlesRenderer,
|
||||
utils::draw_render_elements,
|
||||
},
|
||||
winit::{self, WinitEvent},
|
||||
},
|
||||
@@ -143,7 +144,22 @@ pub fn init(event_loop: &mut EventLoop<Ferese>, state: &mut Ferese) -> Result<()
|
||||
&elements,
|
||||
[0.035, 0.04, 0.055, 1.0],
|
||||
)?;
|
||||
if state.process_screencopies(renderer, &framebuffer, &output) {
|
||||
let cursorless_capture = state.has_pending_screencopy(&output, false);
|
||||
let captured_with_cursor =
|
||||
state.process_screencopies(renderer, &framebuffer, &output, true);
|
||||
|
||||
if cursorless_capture {
|
||||
let cursorless_elements =
|
||||
output_elements(state, renderer, &output, false);
|
||||
redraw_output(
|
||||
renderer,
|
||||
&mut framebuffer,
|
||||
&output,
|
||||
&cursorless_elements,
|
||||
)?;
|
||||
state.process_screencopies(renderer, &framebuffer, &output, false);
|
||||
redraw_output(renderer, &mut framebuffer, &output, &elements)?;
|
||||
} else if captured_with_cursor {
|
||||
let _ = renderer
|
||||
.render(
|
||||
&mut framebuffer,
|
||||
@@ -203,13 +219,34 @@ pub(crate) fn animated_window_elements(
|
||||
state: &Ferese,
|
||||
renderer: &mut GlesRenderer,
|
||||
output: &Output,
|
||||
) -> Vec<AnimatedWindowRenderElement> {
|
||||
output_elements(state, renderer, output, true)
|
||||
}
|
||||
|
||||
pub(crate) fn cursorless_window_elements(
|
||||
state: &Ferese,
|
||||
renderer: &mut GlesRenderer,
|
||||
output: &Output,
|
||||
) -> Vec<AnimatedWindowRenderElement> {
|
||||
output_elements(state, renderer, output, false)
|
||||
}
|
||||
|
||||
fn output_elements(
|
||||
state: &Ferese,
|
||||
renderer: &mut GlesRenderer,
|
||||
output: &Output,
|
||||
include_cursor: bool,
|
||||
) -> Vec<AnimatedWindowRenderElement> {
|
||||
let Some(output_geometry) = state.space.output_geometry(output) else {
|
||||
return Vec::new();
|
||||
};
|
||||
let scale = output.current_scale().fractional_scale();
|
||||
|
||||
let mut elements = cursor_elements(state, renderer, output_geometry, scale);
|
||||
let mut elements = if include_cursor {
|
||||
cursor_elements(state, renderer, output_geometry, scale)
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
elements.extend(layer_elements(
|
||||
renderer,
|
||||
output,
|
||||
@@ -264,6 +301,34 @@ pub(crate) fn animated_window_elements(
|
||||
elements
|
||||
}
|
||||
|
||||
pub(crate) fn redraw_output<R, E>(
|
||||
renderer: &mut R,
|
||||
framebuffer: &mut R::Framebuffer<'_>,
|
||||
output: &Output,
|
||||
elements: &[E],
|
||||
) -> Result<(), R::Error>
|
||||
where
|
||||
R: Renderer,
|
||||
R::TextureId: 'static,
|
||||
E: RenderElement<R>,
|
||||
{
|
||||
let mode = output.current_mode().expect("output has a mode");
|
||||
let transform = output.current_transform().invert();
|
||||
let damage = Rectangle::from_size(transform.transform_size(mode.size));
|
||||
let mut frame = renderer.render(framebuffer, mode.size, transform)?;
|
||||
|
||||
frame.clear(Color32F::new(0.035, 0.04, 0.055, 1.0), &[damage])?;
|
||||
draw_render_elements(
|
||||
&mut frame,
|
||||
output.current_scale().fractional_scale(),
|
||||
elements,
|
||||
&[damage],
|
||||
)?;
|
||||
let _ = frame.finish()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn layer_surfaces(output: &Output) -> Vec<LayerSurface> {
|
||||
layer_map_for_output(output).layers().cloned().collect()
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user