image-copy: Use damage_output() for additional damage

The important change here is that we now apply the additional damage
first, instead of using `.extend()` to add it after other elements. This
is important since `OutputDamageTracker` will ignore our damage elements
if there are behind an element with an opaque region.

This also makes things a bit simpler, especially `take_screencopy_frames()`,
which no longer needs a mutable references to extend then truncate.

The implementation of `OutputDamageTracker` isn't entirely clear, but as
far as I can tell this is intended to work, and it seems to work in some
testing.
This commit is contained in:
Ian Douglas Scott 2025-09-17 11:06:02 -07:00 committed by Victoria Brekenfeld
parent cac7a5aca6
commit 9bc1b6e1ee
4 changed files with 74 additions and 113 deletions

View file

@ -1080,7 +1080,7 @@ impl SurfaceThreadState {
let frames = self
.mirroring
.is_none()
.then(|| take_screencopy_frames(&self.output, &mut elements, &mut has_cursor_mode_none))
.then(|| take_screencopy_frames(&self.output, &elements, &mut has_cursor_mode_none))
.unwrap_or_default();
// actual rendering
@ -1606,10 +1606,9 @@ fn get_surface_dmabuf_feedback(
}
}
// TODO: Don't mutate `elements`
fn take_screencopy_frames(
output: &Output,
elements: &mut Vec<CosmicElement<GlMultiRenderer>>,
elements: &[CosmicElement<GlMultiRenderer>],
has_cursor_mode_none: &mut bool,
) -> Vec<(
ScreencopySessionRef,
@ -1624,7 +1623,15 @@ fn take_screencopy_frames(
let session_data = session.user_data().get::<SessionData>().unwrap();
let mut damage_tracking = session_data.lock().unwrap();
let old_len = if !additional_damage.is_empty() {
let buffer = frame.buffer();
let age = if matches!(buffer_type(&buffer), Some(BufferType::Shm)) {
// TODO re-use offscreen buffer to damage track screencopy to shm
0
} else {
damage_tracking.age_for_buffer(&buffer)
};
if !additional_damage.is_empty() {
let area = output
.current_mode()
.unwrap()
@ -1634,41 +1641,26 @@ fn take_screencopy_frames(
.to_buffer(1, Transform::Normal)
.to_f64();
let old_len = elements.len();
elements.extend(
additional_damage
.into_iter()
.map(|rect| {
rect.to_f64()
.to_logical(
output.current_scale().fractional_scale(),
output.current_transform(),
&area,
)
.to_i32_round()
})
.map(DamageElement::new)
.map(Into::into),
);
Some(old_len)
} else {
None
let additional_damage_elements: Vec<_> = additional_damage
.into_iter()
.map(|rect| {
rect.to_f64()
.to_logical(
output.current_scale().fractional_scale(),
output.current_transform(),
&area,
)
.to_i32_round()
})
.map(DamageElement::new)
.collect();
let _ = damage_tracking
.dt
.damage_output(age, &additional_damage_elements);
};
let buffer = frame.buffer();
let age = if matches!(buffer_type(&frame.buffer()), Some(BufferType::Shm)) {
// TODO re-use offscreen buffer to damage track screencopy to shm
0
} else {
damage_tracking.age_for_buffer(&buffer)
};
let res = damage_tracking.dt.damage_output(age, elements);
if let Some(old_len) = old_len {
elements.truncate(old_len);
}
if !session.draw_cursor() {
*has_cursor_mode_none = true;
}