1
0
Fork 0
forked from wry/wry

Compare commits

..

6 commits

9 changed files with 119 additions and 74 deletions

View file

@ -86,9 +86,7 @@ impl ExtImageCopyCaptureFrameV1 {
let buffer = self.session.buffer.get().unwrap(); let buffer = self.session.buffer.get().unwrap();
if size != buffer.rect.size() { if size != buffer.rect.size() {
self.session.buffer_size_changed(); self.session.buffer_size_changed();
// https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/222 return Err(FrameFailureReason::BufferConstraints);
// self.fail(FrameFailureReason::BufferConstraints);
// return;
} }
if let Err(e) = buffer.update_framebuffer() { if let Err(e) = buffer.update_framebuffer() {
log::error!("Could not import buffer: {}", ErrorFmt(e)); log::error!("Could not import buffer: {}", ErrorFmt(e));
@ -102,6 +100,13 @@ impl ExtImageCopyCaptureFrameV1 {
let mut shm_staging = self.session.shm_staging.take(); let mut shm_staging = self.session.shm_staging.take();
match storage { match storage {
WlBufferStorage::Shm { mem, stride, .. } => { WlBufferStorage::Shm { mem, stride, .. } => {
log::debug!(
"ext-image-copy frame {:?} using wl_shm readback path: {}x{}, stride {}",
self.id,
buffer.rect.width(),
buffer.rect.height(),
*stride,
);
if let Some(b) = &shm_bridge if let Some(b) = &shm_bridge
&& (b.physical_size() != buffer.rect.size() && (b.physical_size() != buffer.rect.size()
|| b.format() != buffer.format || b.format() != buffer.format
@ -159,6 +164,12 @@ impl ExtImageCopyCaptureFrameV1 {
self.session.shm_staging.set(Some(staging)); self.session.shm_staging.set(Some(staging));
} }
WlBufferStorage::Dmabuf { fb, .. } => { WlBufferStorage::Dmabuf { fb, .. } => {
log::debug!(
"ext-image-copy frame {:?} using dmabuf GPU copy path: {}x{}",
self.id,
buffer.rect.width(),
buffer.rect.height(),
);
let Some(fb) = fb else { let Some(fb) = fb else {
return Err(FrameFailureReason::BufferConstraints); return Err(FrameFailureReason::BufferConstraints);
}; };
@ -187,7 +198,11 @@ impl ExtImageCopyCaptureFrameV1 {
) { ) {
match self.try_copy(on, size, f) { match self.try_copy(on, size, f) {
Ok(()) => self.session.status.set(FrameStatus::Captured), Ok(()) => self.session.status.set(FrameStatus::Captured),
Err(e) => self.fail(e), Err(e) => {
if self.session.status.get() != FrameStatus::Failed {
self.fail(e);
}
}
} }
} }

View file

@ -83,6 +83,11 @@ impl ExtImageCopyCaptureSessionV1 {
if self.size_debounce.replace(true) { if self.size_debounce.replace(true) {
return; return;
} }
if let Some(frame) = self.frame.get()
&& let FrameStatus::Capturing | FrameStatus::Captured = self.status.get()
{
frame.fail(FrameFailureReason::BufferConstraints);
}
self.force_capture.set(true); self.force_capture.set(true);
self.send_current_buffer_size(); self.send_current_buffer_size();
self.send_done(); self.send_done();

View file

@ -48,16 +48,13 @@ impl ZwlrScreencopyFrameV1 {
} }
pub fn send_damage(&self) { pub fn send_damage(&self) {
if let Some(output) = self.output.get() { self.client.event(Damage {
let pos = output.pos.get(); self_id: self.id,
self.client.event(Damage { x: 0,
self_id: self.id, y: 0,
x: 0, width: self.rect.width() as _,
y: 0, height: self.rect.height() as _,
width: pos.width() as _, });
height: pos.height() as _,
});
}
} }
pub fn send_buffer(&self) { pub fn send_buffer(&self) {
@ -111,10 +108,28 @@ impl ZwlrScreencopyFrameV1 {
return Err(ZwlrScreencopyFrameV1Error::InvalidBufferFormat); return Err(ZwlrScreencopyFrameV1Error::InvalidBufferFormat);
} }
buffer.update_framebuffer()?; buffer.update_framebuffer()?;
if let Some(WlBufferStorage::Shm { stride, .. }) = buffer.storage.borrow_mut().deref() match buffer.storage.borrow_mut().deref() {
&& *stride != self.rect.width() * 4 Some(WlBufferStorage::Shm { stride, .. }) => {
{ if *stride != self.rect.width() * 4 {
return Err(ZwlrScreencopyFrameV1Error::InvalidBufferStride); return Err(ZwlrScreencopyFrameV1Error::InvalidBufferStride);
}
log::debug!(
"zwlr_screencopy frame {:?} using wl_shm readback path: {}x{}, stride {}",
self.id,
self.rect.width(),
self.rect.height(),
*stride,
);
}
Some(WlBufferStorage::Dmabuf { .. }) => {
log::debug!(
"zwlr_screencopy frame {:?} using dmabuf GPU copy path: {}x{}",
self.id,
self.rect.width(),
self.rect.height(),
);
}
_ => {}
} }
self.buffer.set(Some(buffer)); self.buffer.set(Some(buffer));
if !with_damage && let Some(global) = self.output.get() { if !with_damage && let Some(global) = self.output.get() {
@ -134,6 +149,12 @@ impl ZwlrScreencopyFrameV1 {
} }
self.pending.take(); self.pending.take();
} }
pub fn cancel(&self) {
self.buffer.take();
self.pending.take();
self.send_failed();
}
} }
impl ZwlrScreencopyFrameV1RequestHandler for ZwlrScreencopyFrameV1 { impl ZwlrScreencopyFrameV1RequestHandler for ZwlrScreencopyFrameV1 {

View file

@ -104,8 +104,8 @@ impl ZwlrScreencopyManagerV1 {
let Some(global) = output.global.get() else { let Some(global) = output.global.get() else {
return Ok(()); return Ok(());
}; };
let mode = global.mode.get(); let (width, height) = global.pixel_size();
let mut rect = Rect::new_sized_saturating(0, 0, mode.width, mode.height); let mut rect = Rect::new_sized_saturating(0, 0, width, height);
if let Some(region) = region { if let Some(region) = region {
let scale = global.persistent.scale.get().to_f64(); let scale = global.persistent.scale.get().to_f64();
let x1 = (region.x1() as f64 * scale).round() as i32; let x1 = (region.x1() as f64 * scale).round() as i32;

View file

@ -3,11 +3,9 @@ use {
ifs::wl_surface::xdg_surface::xdg_toplevel::STATE_SUSPENDED, ifs::wl_surface::xdg_surface::xdg_toplevel::STATE_SUSPENDED,
it::{ it::{
test_error::{TestErrorExt, TestResult}, test_error::{TestErrorExt, TestResult},
test_utils::{
test_ouput_node_ext::TestOutputNodeExt, test_toplevel_node_ext::TestToplevelNodeExt,
},
testrun::TestRun, testrun::TestRun,
}, },
tree::Node,
}, },
isnt::std_1::collections::IsntHashSetExt, isnt::std_1::collections::IsntHashSetExt,
std::{rc::Rc, time::Duration}, std::{rc::Rc, time::Duration},
@ -29,7 +27,7 @@ async fn test(run: Rc<TestRun>) -> TestResult {
win2.set_color(0, 255, 0, 255); win2.set_color(0, 255, 0, 255);
win2.map2().await?; win2.map2().await?;
let (x, y) = ds.output.first_toplevel()?.center(); let (x, y) = win1.tl.server.node_absolute_position().center();
ds.move_to(x, y); ds.move_to(x, y);
tassert!(win2.tl.core.states.borrow().not_contains(&STATE_SUSPENDED)); tassert!(win2.tl.core.states.borrow().not_contains(&STATE_SUSPENDED));
@ -45,6 +43,10 @@ async fn test(run: Rc<TestRun>) -> TestResult {
client.sync().await; client.sync().await;
tassert!(win2.tl.core.states.borrow().not_contains(&STATE_SUSPENDED)); tassert!(win2.tl.core.states.borrow().not_contains(&STATE_SUSPENDED));
let (x, y) = win2.tl.server.node_absolute_position().center();
ds.move_to(x, y);
client.sync().await;
let leaves = default_seat.kb.leave.expect()?; let leaves = default_seat.kb.leave.expect()?;
let enters = default_seat.kb.enter.expect()?; let enters = default_seat.kb.enter.expect()?;

View file

@ -315,6 +315,14 @@ impl PwClientNodeOwner for StartedScreencast {
} }
} }
} }
log::debug!(
"Portal screencast using PipeWire dmabuf GPU copy path: {} buffers, format {}, modifier 0x{:08x}, size {}x{}",
self.buffers.borrow().len(),
self.format.get().name,
self.modifier.get(),
self.width.get(),
self.height.get(),
);
self.node self.node
.send_port_output_buffers(&self.port, &self.buffers.borrow()); .send_port_output_buffers(&self.port, &self.buffers.borrow());
} }
@ -633,15 +641,18 @@ impl UsrJayScreencastOwner for StartedScreencast {
fn ready(&self, ev: &Ready) { fn ready(&self, ev: &Ready) {
let idx = ev.idx as usize; let idx = ev.idx as usize;
let buffers = &*self.buffers.borrow();
let pbuffers = self.port.buffers.borrow();
let buffer = &buffers[idx];
let discard_buffer = || { let discard_buffer = || {
self.jay_screencast.release_buffer(idx); self.jay_screencast.release_buffer(idx);
}; };
if !self.buffers_valid.get() { if !self.buffers_valid.get() {
return; return;
} }
let buffers = self.buffers.borrow();
let Some(buffer) = buffers.get(idx) else {
log::warn!("Ignoring ready event for unknown screencast buffer {idx}");
return;
};
let pbuffers = self.port.buffers.borrow();
let Some(io) = self.port.io_buffers.get() else { let Some(io) = self.port.io_buffers.get() else {
discard_buffer(); discard_buffer();
return; return;
@ -767,7 +778,7 @@ pub(super) fn add_screencast_dbus_members(
object.add_method::<Start, _>(move |req, pr| { object.add_method::<Start, _>(move |req, pr| {
dbus_start(&state, req, pr); dbus_start(&state, req, pr);
}); });
object.set_property::<AvailableSourceTypes>(Variant::U32(MONITOR.0)); object.set_property::<AvailableSourceTypes>(Variant::U32((MONITOR | WINDOW).0));
object.set_property::<AvailableCursorModes>(Variant::U32(EMBEDDED.0)); object.set_property::<AvailableCursorModes>(Variant::U32(EMBEDDED.0));
object.set_property::<version>(Variant::U32(5)); object.set_property::<version>(Variant::U32(5));
} }

View file

@ -4,12 +4,11 @@ use {
allocator::BufferObject, allocator::BufferObject,
animation::{ animation::{
AnimationCurve, AnimationState, AnimationStyle, AnimationTick, RetainedExitLayer, AnimationCurve, AnimationState, AnimationStyle, AnimationTick, RetainedExitLayer,
RetainedToplevel, RetainedToplevel, expand_damage_rect,
expand_damage_rect,
multiphase::{ multiphase::{
MultiphasePhase, MultiphasePlan, MultiphasePlanFailure, MultiphaseRequest, MultiphasePhase, MultiphasePlan, MultiphasePlanFailure, MultiphaseRequest,
MultiphaseWindow, MultiphaseWindowHierarchy, MultiphaseWindow, MultiphaseWindowHierarchy, partition_motion_groups,
partition_motion_groups, plan_no_overlap_with_diagnostics, validate_phase_paths, plan_no_overlap_with_diagnostics, validate_phase_paths,
}, },
spawn_in_start_rect, spawn_in_start_rect,
}, },
@ -224,10 +223,7 @@ fn bridged_retarget_plan(
return Err(MultiphasePlanFailure::NoPattern); return Err(MultiphasePlanFailure::NoPattern);
}; };
let mut path = bridge_path.clone(); let mut path = bridge_path.clone();
let mut current = path let mut current = path.last().map(|(_, to)| *to).unwrap_or(window.from);
.last()
.map(|(_, to)| *to)
.unwrap_or(window.from);
while path.len() < bridge_phase_count { while path.len() < bridge_phase_count {
path.push((current, current)); path.push((current, current));
} }
@ -995,6 +991,12 @@ impl State {
} else { } else {
lap.add_child_after(&*la, node); lap.add_child_after(&*la, node);
} }
} else if let Some(last) = c.children.last() {
if autotile {
c.add_tiled_child_after(&*last.node, node);
} else {
c.add_child_after(&*last.node, node);
}
} else { } else {
c.append_child(node); c.append_child(node);
} }
@ -1773,12 +1775,7 @@ impl State {
self.eng.now().msec() self.eng.now().msec()
} }
pub fn queue_tiled_animation( pub fn queue_tiled_animation(self: &Rc<Self>, node_id: NodeId, old: Rect, new: Rect) {
self: &Rc<Self>,
node_id: NodeId,
old: Rect,
new: Rect,
) {
let curve = self let curve = self
.layout_animation_curve_override .layout_animation_curve_override
.get() .get()
@ -1806,12 +1803,7 @@ impl State {
self.queue_layout_animation(node_id, old, new, curve, hierarchy); self.queue_layout_animation(node_id, old, new, curve, hierarchy);
} }
pub fn queue_linear_layout_animation( pub fn queue_linear_layout_animation(self: &Rc<Self>, node_id: NodeId, old: Rect, new: Rect) {
self: &Rc<Self>,
node_id: NodeId,
old: Rect,
new: Rect,
) {
self.queue_layout_animation( self.queue_layout_animation(
node_id, node_id,
old, old,
@ -2164,11 +2156,7 @@ impl State {
started_any started_any
} }
pub fn queue_spawn_in_animation( pub fn queue_spawn_in_animation(self: &Rc<Self>, node_id: NodeId, target: Rect) {
self: &Rc<Self>,
node_id: NodeId,
target: Rect,
) {
if !self.animations.enabled.get() || target.is_empty() { if !self.animations.enabled.get() || target.is_empty() {
return; return;
} }
@ -2829,10 +2817,7 @@ impl State {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use { use {super::*, crate::animation::multiphase::MultiphaseHierarchyPosition};
super::*,
crate::animation::multiphase::MultiphaseHierarchyPosition,
};
fn rect(x1: i32, y1: i32, x2: i32, y2: i32) -> Rect { fn rect(x1: i32, y1: i32, x2: i32, y2: i32) -> Rect {
Rect::new_saturating(x1, y1, x2, y2) Rect::new_saturating(x1, y1, x2, y2)
@ -2846,12 +2831,7 @@ mod tests {
} }
fn candidate(node_id: u32, style: AnimationStyle) -> LayoutAnimationCandidate { fn candidate(node_id: u32, style: AnimationStyle) -> LayoutAnimationCandidate {
candidate_rects( candidate_rects(node_id, rect(0, 0, 100, 100), rect(100, 0, 200, 100), style)
node_id,
rect(0, 0, 100, 100),
rect(100, 0, 200, 100),
style,
)
} }
fn candidate_rects( fn candidate_rects(
@ -2922,14 +2902,16 @@ mod tests {
) )
.unwrap(); .unwrap();
assert!(plan assert!(
.phases plan.phases
.iter() .iter()
.any(|phase| phase.steps.iter().any(|step| step.node_id == NodeId(1)))); .any(|phase| phase.steps.iter().any(|step| step.node_id == NodeId(1)))
assert!(plan );
.phases assert!(
.iter() plan.phases
.any(|phase| phase.steps.iter().any(|step| step.node_id == NodeId(3)))); .iter()
.any(|phase| phase.steps.iter().any(|step| step.node_id == NodeId(3)))
);
} }
#[test] #[test]

View file

@ -2633,6 +2633,9 @@ impl ToplevelNodeBase for ContainerNode {
if let Some(last) = self.focus_history.last() { if let Some(last) = self.focus_history.last() {
return last.node.clone().tl_last_active_child(); return last.node.clone().tl_last_active_child();
} }
if let Some(last) = self.children.last() {
return last.node.clone().tl_last_active_child();
}
self self
} }

View file

@ -460,9 +460,15 @@ impl OutputNode {
} }
self.lock_surface.take(); self.lock_surface.take();
self.jay_outputs.clear(); self.jay_outputs.clear();
self.screencasts.clear(); for screencast in self.screencasts.lock().drain_values() {
self.screencopies.clear(); screencast.do_destroy();
self.ext_copy_sessions.clear(); }
for screencopy in self.screencopies.lock().drain_values() {
screencopy.cancel();
}
for session in self.ext_copy_sessions.lock().drain_values() {
session.stop();
}
self.ext_workspace_groups.clear(); self.ext_workspace_groups.clear();
self.latch_event.clear(); self.latch_event.clear();
self.vblank_event.clear(); self.vblank_event.clear();