Compare commits

...
1 Commits
Author SHA1 Message Date
galister db777d7937 XSHM & PipeWire CPU capture fixes 2026-10-23 21:11:33 +09:00
8 changed files with 117 additions and 28 deletions

No files matched your search

Generated
+1 -2
View File
@@ -4773,8 +4773,7 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "rxscreen"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afbab13f83503a8272b7150d487494992cf6c59c299dcaf5d8ffac75bad9fc96"
source = "git+https://github.com/galister/rxscreen.git?rev=7197e1de6622b65859e6f2060b5750185e0dad2a#7197e1de6622b65859e6f2060b5750185e0dad2a"
dependencies = [
"libc",
]
+63 -19
View File
@@ -31,6 +31,9 @@ use crate::{
const CURSOR_SIZE: f32 = 16. / 1440.;
// synchronize queue shared by the WlxCapture worker threads
static CAPTURE_QUEUE_MUTEX: Mutex<()> = Mutex::new(());
struct BufPass {
pass: WGfxPass<Vert2Uv>,
buf_vert: Arc<Buffer<Vert2Uv>>,
@@ -664,6 +667,17 @@ fn upload_image(
height: u32,
format: Format,
data: &[u8],
) -> Option<Arc<Image>> {
upload_image_with_row_length(me, width, height, format, data, 0)
}
fn upload_image_with_row_length(
me: &WlxCaptureIn,
width: u32,
height: u32,
format: Format,
data: &[u8],
buffer_row_length: u32,
) -> Option<Arc<Image>> {
let cmd_result = if me.use_capture_queue {
me.gfx
@@ -679,15 +693,23 @@ fn upload_image(
return None;
}
};
let image = match cmd_xfer.upload_image(width, height, format, data) {
Ok(x) => x,
Err(e) => {
log::error!("{}: Could not create vkImage: {:?}", me.name, e);
return None;
}
};
let image =
match cmd_xfer.upload_image_with_row_length(width, height, format, data, buffer_row_length)
{
Ok(x) => x,
Err(e) => {
log::error!("{}: Could not create vkImage: {:?}", me.name, e);
return None;
}
};
if let Err(e) = cmd_xfer.build_and_execute_now() {
let result = if me.use_capture_queue {
let _guard = CAPTURE_QUEUE_MUTEX.lock().unwrap(); // mutex poison only
cmd_xfer.build_and_execute_now()
} else {
cmd_xfer.build_and_execute_now()
};
if let Err(e) = result {
log::error!("{}: Could not execute upload: {:?}", me.name, e);
return None;
}
@@ -757,8 +779,22 @@ pub(super) fn receive_callback(me: &WlxCaptureIn, frame: WlxFrame) -> Option<Wlx
}
};
let data = unsafe { std::slice::from_raw_parts(frame.ptr as *const u8, frame.size) };
let image = upload_image(me, frame.format.width, frame.format.height, format, data)?;
// SAFETY: the MemPtr params & allocation and must be valid and must outlive the callback
let pixels = unsafe {
std::slice::from_raw_parts(
(frame.ptr as *const u8).add(frame.offset),
frame.size - frame.offset,
)
};
let buffer_row_length = (frame.stride / 4) as u32;
let image = upload_image_with_row_length(
me,
frame.format.width,
frame.format.height,
format,
pixels,
buffer_row_length,
)?;
Some(WlxCaptureOut {
image: me.gfx.create_image_view(image).ok()?,
@@ -811,6 +847,8 @@ pub(super) enum MainThreadFrame {
Cpu {
format: FrameFormat,
data: Vec<u8>,
offset: usize,
stride: usize,
mouse: Option<MouseMeta>,
},
Dmabuf {
@@ -870,12 +908,16 @@ where
MainThreadFrame::Cpu {
format,
data,
offset,
stride,
mouse,
} => {
let frame = wlx_frame::MemPtrFrame {
format,
ptr: data.as_ptr() as usize,
size: data.len(),
offset,
stride,
mouse,
};
receive_callback(
@@ -910,22 +952,24 @@ fn receive_callback_dummy(_: &DmaExporterProxy, frame: WlxFrame) -> Option<MainT
Some(MainThreadFrame::Cpu {
format: frame.format,
data: map.as_slice().to_vec(),
offset: frame.plane.offset as _,
stride: (frame.format.width as usize).checked_mul(4)?,
mouse: frame.mouse,
})
}
WlxFrame::MemPtr(frame) => {
let data = if frame.size == 0 {
Vec::new()
} else {
if frame.ptr == 0 {
log::error!("Main-thread CPU capture received a null MemPtr frame");
return None;
}
unsafe { std::slice::from_raw_parts(frame.ptr as *const u8, frame.size) }.to_vec()
// SAFETY: Allocation must be valid & must outlive the callback
let pixels = unsafe {
std::slice::from_raw_parts(
(frame.ptr as *const u8).add(frame.offset),
frame.size - frame.offset,
)
};
Some(MainThreadFrame::Cpu {
format: frame.format,
data,
data: pixels.to_vec(),
offset: frame.offset,
stride: frame.stride,
mouse: frame.mouse,
})
}
+18 -3
View File
@@ -139,6 +139,17 @@ impl CommandBufferBuilder<CmdBufGfx> {
impl CommandBufferBuilder<CmdBufXfer> {
pub fn upload_image(&mut self, width: u32, height: u32, format: Format, data: &[u8]) -> anyhow::Result<Arc<Image>> {
self.upload_image_with_row_length(width, height, format, data, 0)
}
pub fn upload_image_with_row_length(
&mut self,
width: u32,
height: u32,
format: Format,
data: &[u8],
buffer_row_length: u32,
) -> anyhow::Result<Arc<Image>> {
let image = self.graphics.create_image(ImageCreateInfo::new_2d(
width,
height,
@@ -149,9 +160,13 @@ impl CommandBufferBuilder<CmdBufXfer> {
.graphics
.empty_buffer::<u8>(BufferUsage::TRANSFER_SRC, data.len() as u64)?;
staging.write()?.copy_from_slice(data);
self
.raw
.copy_buffer_to_image(&staging.raw, &image.raw, [0, 0, 0], [width, height, 1]);
self.raw.copy_buffer_to_image_with_row_length(
&staging.raw,
&image.raw,
[0, 0, 0],
[width, height, 1],
buffer_row_length,
);
self.keepalive.push(Box::new(staging));
self.keepalive.push(Box::new(image.clone()));
Ok(image)
+12 -1
View File
@@ -2494,11 +2494,22 @@ impl RawCommandBuffer {
image: &Arc<RawImage>,
offset: [u32; 3],
extent: [u32; 3],
) {
self.copy_buffer_to_image_with_row_length(buffer, image, offset, extent, 0);
}
pub(super) fn copy_buffer_to_image_with_row_length(
&mut self,
buffer: &RawBuffer,
image: &Arc<RawImage>,
offset: [u32; 3],
extent: [u32; 3],
buffer_row_length: u32,
) {
self.transition_image(image, ImageLayout::TransferDst);
let regions = [vk::BufferImageCopy::default()
.buffer_offset(0)
.buffer_row_length(0)
.buffer_row_length(buffer_row_length)
.buffer_image_height(0)
.image_subresource(vk::ImageSubresourceLayers {
aspect_mask: vk::ImageAspectFlags::COLOR,
+3 -1
View File
@@ -31,7 +31,9 @@ wayland-protocols = {
drm-fourcc = "2.2.0"
rxscreen = {
version = "0.1.7",
git = "https://github.com/galister/rxscreen.git",
rev = "7197e1de6622b65859e6f2060b5750185e0dad2a",
# version = "0.1.7",
features = [
"mouse",
"shm",
+2
View File
@@ -128,6 +128,8 @@ pub struct MemPtrFrame {
pub format: FrameFormat,
pub ptr: usize,
pub size: usize,
pub offset: usize,
pub stride: usize,
pub mouse: Option<MouseMeta>,
}
+16 -2
View File
@@ -376,10 +376,24 @@ where
}
}
DataType::MemPtr => {
let raw = datas[0].as_raw();
let chunk = datas[0].chunk();
let offset = chunk.offset() as usize;
let chunk_size = chunk.size() as usize;
let Some(size) = offset.checked_add(chunk_size) else {
log::error!("{name}: PipeWire chunk range overflow");
return;
};
if size > raw.maxsize as usize {
log::error!("{name}: PipeWire chunk extends beyond allocation");
return;
}
let memptr = MemPtrFrame {
format: *format,
ptr: datas[0].as_raw().data as _,
size: datas[0].chunk().size() as _,
ptr: raw.data as _,
size,
offset,
stride: chunk.stride() as _,
mouse: mouse_meta,
};
+2
View File
@@ -109,6 +109,8 @@ where
transform: Transform::Normal,
},
ptr: unsafe { image.as_ptr() as _ },
offset: 0,
stride: image.bytes_per_line() as _,
size,
mouse: d.root_mouse_position().and_then(|root_pos| {
monitor.mouse_to_local(root_pos).map(|(x, y)| MouseMeta {