Skip to content

Commit 8790902

Browse files
WhatAmISupposedToPutHereslp
authored andcommitted
Improved pipewire bridge support
Linux version of Dota 2 includes a new enough version of SDL to have native pipewire support. Naturally it ends up using protocol features that the bridge did not support previously Signed-off-by: Sasha Finkelstein <[email protected]>
1 parent ef920fb commit 8790902

5 files changed

Lines changed: 71 additions & 51 deletions

File tree

crates/muvm/src/guest/bridge/common.rs

Lines changed: 17 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -329,25 +329,13 @@ impl Context {
329329
channel_type,
330330
protocol_version: CROSS_DOMAIN_PROTOCOL_VERSION,
331331
};
332-
this.submit_cmd(&init_cmd, mem::size_of::<CrossDomainInit>(), None, None)?;
332+
this.submit_cmd(&init_cmd, mem::size_of::<CrossDomainInit>(), None)?;
333333
this.poll_cmd()?;
334334
Ok(this)
335335
}
336336

337-
pub fn submit_cmd<T>(
338-
&self,
339-
cmd: &T,
340-
cmd_size: usize,
341-
ring_idx: Option<u32>,
342-
ring_handle: Option<u32>,
343-
) -> Result<()> {
344-
submit_cmd_raw(
345-
self.fd.as_raw_fd() as c_int,
346-
cmd,
347-
cmd_size,
348-
ring_idx,
349-
ring_handle,
350-
)
337+
pub fn submit_cmd<T>(&self, cmd: &T, cmd_size: usize, ring_idx: Option<u32>) -> Result<()> {
338+
submit_cmd_raw(self.fd.as_raw_fd() as c_int, cmd, cmd_size, ring_idx)
351339
}
352340

353341
fn poll_cmd(&self) -> Result<()> {
@@ -356,18 +344,11 @@ impl Context {
356344
&cmd,
357345
mem::size_of::<CrossDomainPoll>(),
358346
Some(CROSS_DOMAIN_CHANNEL_RING),
359-
None,
360347
)
361348
}
362349
}
363350

364-
pub fn submit_cmd_raw<T>(
365-
fd: c_int,
366-
cmd: &T,
367-
cmd_size: usize,
368-
ring_idx: Option<u32>,
369-
ring_handle: Option<u32>,
370-
) -> Result<()> {
351+
pub fn submit_cmd_raw<T>(fd: c_int, cmd: &T, cmd_size: usize, ring_idx: Option<u32>) -> Result<()> {
371352
let cmd_buf = cmd as *const T as *const u8;
372353
let mut exec = DrmVirtgpuExecbuffer {
373354
command: cmd_buf as u64,
@@ -378,18 +359,10 @@ pub fn submit_cmd_raw<T>(
378359
exec.ring_idx = ring_idx;
379360
exec.flags = VIRTGPU_EXECBUF_RING_IDX;
380361
}
381-
let ring_handle = &ring_handle;
382-
if let Some(ring_handle) = ring_handle {
383-
exec.bo_handles = ring_handle as *const u32 as u64;
384-
exec.num_bo_handles = 1;
385-
}
386362
// SAFETY: `exec` and `cmd` outlive the call, and it does not modify `cmd`
387363
unsafe {
388364
drm_virtgpu_execbuffer(fd, &mut exec)?;
389365
}
390-
if ring_handle.is_some() {
391-
unimplemented!();
392-
}
393366
Ok(())
394367
}
395368

@@ -488,6 +461,8 @@ pub trait ProtocolHandler: Sized {
488461
) -> Result<StreamSendResult<Self::ResourceFinalizer>>;
489462

490463
fn process_vgpu_extra(this: &mut Client<Self>, cmd: u8) -> Result<()>;
464+
465+
fn process_fd_extra(this: &mut Client<Self>, fd: u64, events: EpollFlags) -> Result<()>;
491466
}
492467

493468
pub struct Client<'a, P: ProtocolHandler> {
@@ -695,7 +670,7 @@ impl<'a, P: ProtocolHandler> Client<'a, P> {
695670
ring_msg.identifier_types[i] = res.identifier_type;
696671
ring_msg.identifier_sizes[i] = res.identifier_size;
697672
}
698-
self.gpu_ctx.submit_cmd(&ring_msg, size, None, None)?;
673+
self.gpu_ctx.submit_cmd(&ring_msg, size, None)?;
699674
for fin in finalizers {
700675
fin.finalize(self)?;
701676
}
@@ -913,7 +888,16 @@ impl<'a, P: ProtocolHandler> Client<'a, P> {
913888
);
914889
}
915890
} else {
916-
unimplemented!()
891+
let close = P::process_fd_extra(self, fd, events)
892+
.map_err(|e| {
893+
let srv_id = self.gpu_ctx.fd.as_raw_fd() as u64;
894+
eprintln!("Server {srv_id} disconnected with error: {e:?}");
895+
e
896+
})
897+
.is_err();
898+
if close {
899+
self.sub_poll.close();
900+
}
917901
}
918902
}
919903
}

crates/muvm/src/guest/bridge/pipewire.rs

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::guest::bridge::common::{
1717
const CROSS_DOMAIN_CHANNEL_TYPE_PW: u32 = 0x10;
1818
const CROSS_DOMAIN_CMD_READ_EVENTFD_NEW: u8 = 11;
1919
const CROSS_DOMAIN_CMD_READ: u8 = 6;
20+
const CROSS_DOMAIN_CMD_WRITE: u8 = 7;
2021

2122
const SPA_TYPE_STRUCT: u32 = 14;
2223

@@ -149,6 +150,7 @@ impl MessageResourceFinalizer for PipeWireResourceFinalizer {
149150

150151
struct CrossDomainEventFd {
151152
event_fd: EventFd,
153+
resource: u32,
152154
}
153155

154156
struct ClientNodeData {
@@ -172,14 +174,22 @@ struct PipeWireProtocolHandler {
172174
}
173175

174176
impl PipeWireProtocolHandler {
175-
fn create_guest_to_host_eventfd(this: &mut Client<Self>, node_id: u32) -> Result<OwnedFd> {
177+
fn create_guest_to_host_eventfd(
178+
this: &mut Client<Self>,
179+
node_id: u32,
180+
resource: CrossDomainResource,
181+
) -> Result<OwnedFd> {
176182
let efd = EventFd::from_flags(EfdFlags::EFD_NONBLOCK)?;
177183
let ofd = efd.as_fd().try_clone_to_owned()?;
178184
this.sub_poll.add(efd.as_fd(), EpollFlags::EPOLLIN);
179185
let raw = efd.as_raw_fd() as u64;
180-
this.protocol_handler
181-
.guest_to_host_eventfds
182-
.insert(raw, CrossDomainEventFd { event_fd: efd });
186+
this.protocol_handler.guest_to_host_eventfds.insert(
187+
raw,
188+
CrossDomainEventFd {
189+
event_fd: efd,
190+
resource: resource.identifier,
191+
},
192+
);
183193
this.protocol_handler
184194
.client_nodes
185195
.get_mut(&node_id)
@@ -208,10 +218,14 @@ impl PipeWireProtocolHandler {
208218
.unwrap()
209219
.host_to_guest
210220
.push(resource.identifier);
211-
this.gpu_ctx.submit_cmd(&msg, msg_size, None, None)?;
212-
this.protocol_handler
213-
.host_to_guest_eventfds
214-
.insert(resource.identifier, CrossDomainEventFd { event_fd: efd });
221+
this.gpu_ctx.submit_cmd(&msg, msg_size, None)?;
222+
this.protocol_handler.host_to_guest_eventfds.insert(
223+
resource.identifier,
224+
CrossDomainEventFd {
225+
event_fd: efd,
226+
resource: resource.identifier,
227+
},
228+
);
215229
Ok(ofd)
216230
}
217231
}
@@ -249,13 +263,13 @@ impl ProtocolHandler for PipeWireProtocolHandler {
249263
fds.push(this.virtgpu_id_to_prime(rsc)?);
250264
} else if this.protocol_handler.client_nodes.contains_key(&hdr.id) {
251265
if hdr.opcode == PW_OPC_CLIENT_NODE_SET_ACTIVATION {
252-
resources.pop_front().ok_or(Errno::EIO)?;
253-
fds.push(Self::create_guest_to_host_eventfd(this, hdr.id)?);
266+
let rsc = resources.pop_front().ok_or(Errno::EIO)?;
267+
fds.push(Self::create_guest_to_host_eventfd(this, hdr.id, rsc)?);
254268
} else if hdr.opcode == PW_OPC_CLIENT_NODE_TRANSPORT {
255269
let rsc1 = resources.pop_front().ok_or(Errno::EIO)?;
256270
fds.push(Self::create_host_to_guest_eventfd(this, hdr.id, rsc1)?);
257-
resources.pop_front().ok_or(Errno::EIO)?;
258-
fds.push(Self::create_guest_to_host_eventfd(this, hdr.id)?);
271+
let rsc2 = resources.pop_front().ok_or(Errno::EIO)?;
272+
fds.push(Self::create_guest_to_host_eventfd(this, hdr.id, rsc2)?);
259273
} else {
260274
unimplemented!()
261275
}
@@ -332,6 +346,25 @@ impl ProtocolHandler for PipeWireProtocolHandler {
332346
Err(Errno::ENOENT.into())
333347
}
334348
}
349+
350+
fn process_fd_extra(this: &mut Client<Self>, fd: u64, _: EpollFlags) -> Result<()> {
351+
let efd = this
352+
.protocol_handler
353+
.guest_to_host_eventfds
354+
.get(&fd)
355+
.ok_or(Errno::ENOENT)?;
356+
let msg_size = mem::size_of::<CrossDomainReadWrite<[u8; mem::size_of::<u64>()]>>();
357+
let val = efd.event_fd.read()?;
358+
let msg = CrossDomainReadWrite {
359+
hdr: CrossDomainHeader::new(CROSS_DOMAIN_CMD_WRITE, msg_size as u16),
360+
identifier: efd.resource,
361+
hang_up: 0,
362+
opaque_data_size: mem::size_of::<u64>() as u32,
363+
pad: 0,
364+
data: val.to_ne_bytes(),
365+
};
366+
this.gpu_ctx.submit_cmd(&msg, msg_size, None)
367+
}
335368
}
336369

337370
pub fn start_pwbridge() {

crates/muvm/src/guest/bridge/x11.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use nix::libc::{
1919
SYS_openat, AT_FDCWD, MAP_ANONYMOUS, MAP_FIXED, MAP_PRIVATE, MAP_SHARED, O_CLOEXEC, O_RDWR,
2020
PROT_READ, PROT_WRITE,
2121
};
22+
use nix::sys::epoll::EpollFlags;
2223
use nix::sys::mman::{mmap, munmap, MapFlags, ProtFlags};
2324
use nix::sys::ptrace;
2425
use nix::sys::signal::Signal;
@@ -121,7 +122,7 @@ impl MessageResourceFinalizer for X11ResourceFinalizer {
121122
};
122123
client
123124
.gpu_ctx
124-
.submit_cmd(&ft_msg, ft_destroy_msg_size, None, None)?;
125+
.submit_cmd(&ft_msg, ft_destroy_msg_size, None)?;
125126
},
126127
}
127128
Ok(())
@@ -337,6 +338,9 @@ impl ProtocolHandler for X11ProtocolHandler {
337338
};
338339
this.protocol_handler.process_futex_signal(recv)
339340
}
341+
fn process_fd_extra(_: &mut Client<Self>, _: u64, _: EpollFlags) -> Result<()> {
342+
unreachable!()
343+
}
340344
}
341345

342346
impl X11ProtocolHandler {
@@ -494,8 +498,7 @@ impl X11ProtocolHandler {
494498
handle: handle.handle,
495499
pad: 0,
496500
};
497-
this.gpu_ctx
498-
.submit_cmd(&ft_msg, ft_new_msg_size, None, None)?;
501+
this.gpu_ctx.submit_cmd(&ft_msg, ft_new_msg_size, None)?;
499502
let fd = this.gpu_ctx.fd.as_raw_fd() as c_int;
500503
this.protocol_handler
501504
.futex_watchers
@@ -597,7 +600,7 @@ impl FutexWatcherThread {
597600
id: xid,
598601
pad: 0,
599602
};
600-
common::submit_cmd_raw(fd, &ft_signal_cmd, ft_signal_msg_size, None, None).unwrap();
603+
common::submit_cmd_raw(fd, &ft_signal_cmd, ft_signal_msg_size, None).unwrap();
601604
}
602605
});
603606
FutexWatcherThread {

crates/muvm/src/hidpipe_server.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ struct EvdevContainer {
104104
names_to_fds: HashMap<String, u64>,
105105
}
106106

107-
fn insert_entry<K, V>(entry: hash_map::Entry<K, V>, v: V) -> &V {
107+
fn insert_entry<K, V>(entry: hash_map::Entry<'_, K, V>, v: V) -> &V {
108108
match entry {
109109
hash_map::Entry::Vacant(e) => e.insert(v),
110110
hash_map::Entry::Occupied(mut e) => {

crates/muvm/src/net.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ fn parse_range(r: &str) -> Result<(u32, u32)> {
2424
}
2525

2626
impl PublishSpec<'_> {
27-
fn parse(mut arg: &str) -> Result<PublishSpec> {
27+
fn parse(mut arg: &str) -> Result<PublishSpec<'_>> {
2828
let mut udp = false;
2929
if arg.ends_with("/udp") {
3030
udp = true;

0 commit comments

Comments
 (0)