Skip to content

Commit 3c12a00

Browse files
author
Dorinda Bassey
committed
Add pipewire cross domain channel type.
This adds a pipewire channel type, increases the maximum number of fds that can be transferred in a single message, and adds support for sharing eventfds between the guest and host. Signed-off-by: Sasha Finkelstein <fnkl.kernel@gmail.com> Signed-off-by: Dorinda Bassey <dbassey@redhat.com>
1 parent c065018 commit 3c12a00

File tree

5 files changed

+106
-46
lines changed

5 files changed

+106
-46
lines changed

ffi/src/include/rutabaga_gfx_ffi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ extern "C" {
9292
* Rutabaga channel types
9393
*/
9494
#define RUTABAGA_CHANNEL_TYPE_WAYLAND 1
95+
#define RUTABAGA_CHANNEL_TYPE_PIPEWIRE 0x10
9596
#define RUTABAGA_CHANNEL_TYPE_X11 0x11
9697

9798
/**

ffi/src/tests/virtgpu_cross_domain_protocol.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
// Channel types (must match rutabaga channel types)
2020
#define CROSS_DOMAIN_CHANNEL_TYPE_WAYLAND 0x0001
2121
#define CROSS_DOMAIN_CHANNEL_TYPE_CAMERA 0x0002
22+
#define CROSS_DOMAIN_CHANNEL_TYPE_PIPEWIRE 0x0010
2223
#define CROSS_DOMAIN_CHANNEL_TYPE_X11 0x0011
2324

2425
// The maximum number of identifiers (value based on wp_linux_dmabuf)

src/cross_domain/cross_domain_protocol.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ pub const CROSS_DOMAIN_CMD_WRITE: u8 = 7;
2222
pub const CROSS_DOMAIN_CMD_CREATE_ATOMIC_MEMORY_SENTINEL: u8 = 8;
2323
pub const CROSS_DOMAIN_CMD_SIGNAL_ATOMIC_MEMORY_SENTINEL: u8 = 9;
2424
pub const CROSS_DOMAIN_CMD_DESTROY_ATOMIC_MEMORY_SENTINEL: u8 = 10;
25+
pub const CROSS_DOMAIN_CMD_READ_CREATE_EVENT: u8 = 11;
2526

2627
/// Channel types (must match rutabaga channel types)
2728
pub const CROSS_DOMAIN_CHANNEL_TYPE_WAYLAND: u32 = 0x0001;
2829
pub const CROSS_DOMAIN_CHANNEL_TYPE_CAMERA: u32 = 0x0002;
30+
pub const CROSS_DOMAIN_CHANNEL_TYPE_PIPEWIRE: u32 = 0x0010;
2931
pub const CROSS_DOMAIN_CHANNEL_TYPE_X11: u32 = 0x0011;
3032

3133
/// The maximum number of identifiers
@@ -88,7 +90,7 @@ pub struct CrossDomainHeader {
8890
}
8991

9092
#[repr(C)]
91-
#[derive(Copy, Clone, Debug, Default, FromBytes, IntoBytes, Immutable)]
93+
#[derive(Copy, Clone, Default, FromBytes, IntoBytes, Immutable)]
9294
pub struct CrossDomainInit {
9395
pub hdr: CrossDomainHeader,
9496
pub query_ring_id: u32,
@@ -157,3 +159,11 @@ pub struct CrossDomainDestroyAtomicMemorySentinel {
157159
pub id: u32,
158160
pub pad: u32,
159161
}
162+
163+
#[repr(C)]
164+
#[derive(Copy, Clone, Default, FromBytes, IntoBytes, Immutable)]
165+
pub struct CrossDomainCreateEvent {
166+
pub hdr: CrossDomainHeader,
167+
pub id: u32,
168+
pub pad: u32,
169+
}

src/cross_domain/mod.rs

Lines changed: 92 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ enum CrossDomainJob {
9292
AddReadPipe(u32),
9393
Finish,
9494
AddAtomicMemorySentinel(u32, Event),
95+
AddReadEvent(u32),
9596
}
9697

9798
enum RingWrite<'a, T> {
@@ -395,18 +396,18 @@ impl CrossDomainWorker {
395396
_ => {
396397
let mut items = self.item_state.lock().unwrap();
397398
let mut cmd_read: CrossDomainReadWrite = Default::default();
398-
let pipe_id: u32 = event
399+
let item_id: u32 = event
399400
.connection_id
400401
.try_into()
401402
.map_err(MesaError::TryFromIntError)?;
402403
let bytes_read;
403404

404405
cmd_read.hdr.cmd = CROSS_DOMAIN_CMD_READ;
405-
cmd_read.identifier = pipe_id;
406+
cmd_read.identifier = item_id;
406407

407408
let item = items
408409
.table
409-
.get_mut(&pipe_id)
410+
.get_mut(&item_id)
410411
.ok_or(RutabagaError::InvalidCrossDomainItemId)?;
411412

412413
match item {
@@ -423,11 +424,18 @@ impl CrossDomainWorker {
423424
self.wait_ctx.delete(readpipe.as_borrowed_descriptor())?;
424425
}
425426
}
427+
CrossDomainItem::Event(ref evt) => {
428+
// For eventfd, we can use wait() to consume the event
429+
if event.readable {
430+
let _ = evt.wait();
431+
}
432+
bytes_read = 0; // eventfd doesn't have data to read like pipes
433+
}
426434
_ => return Err(RutabagaError::InvalidCrossDomainItemType),
427435
}
428436

429437
if event.hung_up && bytes_read == 0 {
430-
items.table.remove(&pipe_id);
438+
items.table.remove(&item_id);
431439
}
432440

433441
self.fence_handler.call(fence);
@@ -547,6 +555,20 @@ impl CrossDomainWorker {
547555
_ => return Err(RutabagaError::InvalidCrossDomainItemType),
548556
}
549557
}
558+
CrossDomainJob::AddReadEvent(efd_id) => {
559+
let items = self.item_state.lock().unwrap();
560+
let item = items
561+
.table
562+
.get(&efd_id)
563+
.ok_or(RutabagaError::InvalidCrossDomainItemId)?;
564+
565+
match item {
566+
CrossDomainItem::Event(event) => self
567+
.wait_ctx
568+
.add(efd_id as u64, event.as_borrowed_descriptor())?,
569+
_ => return Err(RutabagaError::InvalidCrossDomainItemType),
570+
}
571+
}
550572
CrossDomainJob::AddAtomicMemorySentinel(id, recv) => {
551573
self.wait_ctx
552574
.add(id as u64, recv.as_borrowed_descriptor())?;
@@ -720,29 +742,28 @@ impl CrossDomainContext {
720742

721743
fn send(
722744
&mut self,
723-
cmd_send: &CrossDomainSendReceive,
745+
cmd_send: &mut CrossDomainSendReceive,
724746
opaque_data: &[u8],
725747
) -> RutabagaResult<()> {
726748
let mut descriptors: Vec<OwnedDescriptor> = vec![];
727749
let mut write_pipe_opt: Option<WritePipe> = None;
728750
let mut read_pipe_id_opt: Option<u32> = None;
729751

730-
let num_identifiers = cmd_send
731-
.num_identifiers
732-
.try_into()
733-
.map_err(MesaError::TryFromIntError)?;
752+
let num_identifiers = cmd_send.num_identifiers as usize;
734753

735754
if num_identifiers > CROSS_DOMAIN_MAX_IDENTIFIERS {
736755
return Err(MesaError::WithContext("max cross domain identifiers exceeded").into());
737756
}
738757

739758
let iter = cmd_send
740759
.identifiers
741-
.iter()
742-
.zip(cmd_send.identifier_types.iter())
760+
.iter_mut()
761+
.zip(cmd_send.identifier_types.iter_mut())
762+
.zip(cmd_send.identifier_sizes.iter_mut())
763+
.map(|((i, it), is)| (i, it, is))
743764
.take(num_identifiers);
744765

745-
for (identifier, identifier_type) in iter {
766+
for (identifier, identifier_type, _identifier_size) in iter {
746767
if *identifier_type == CROSS_DOMAIN_ID_TYPE_VIRTGPU_BLOB {
747768
let context_resources = self.context_resources.lock().unwrap();
748769

@@ -853,6 +874,25 @@ impl CrossDomainContext {
853874
Ok(())
854875
}
855876

877+
fn read_event_new(&mut self, cmd_event_new: &CrossDomainCreateEvent) -> RutabagaResult<()> {
878+
let items = self.item_state.lock().unwrap();
879+
880+
if let Some(item) = items.table.get(&cmd_event_new.id) {
881+
if let CrossDomainItem::Event(_) = item {
882+
self.state
883+
.as_ref()
884+
.unwrap()
885+
.add_job(CrossDomainJob::AddReadEvent(cmd_event_new.id));
886+
self.resample_evt.as_mut().unwrap().signal()?;
887+
Ok(())
888+
} else {
889+
Err(RutabagaError::InvalidCrossDomainItemType)
890+
}
891+
} else {
892+
Err(RutabagaError::InvalidCrossDomainItemId)
893+
}
894+
}
895+
856896
fn write(&self, cmd_write: &CrossDomainReadWrite, opaque_data: &[u8]) -> RutabagaResult<()> {
857897
let mut items = self.item_state.lock().unwrap();
858898

@@ -886,6 +926,21 @@ impl CrossDomainContext {
886926
_ => Err(RutabagaError::InvalidCrossDomainItemType),
887927
}
888928
}
929+
930+
fn process_cmd_send(&mut self, commands: &mut [u8]) -> RutabagaResult<()> {
931+
let opaque_data_offset = size_of::<CrossDomainSendReceive>();
932+
let (mut cmd_send, _) = CrossDomainSendReceive::read_from_prefix(commands.as_bytes())
933+
.map_err(|_| RutabagaError::InvalidCommandBuffer)?;
934+
935+
let opaque_data = commands
936+
.get_mut(opaque_data_offset..opaque_data_offset + cmd_send.opaque_data_size as usize)
937+
.ok_or(RutabagaError::InvalidCommandSize(
938+
cmd_send.opaque_data_size as usize,
939+
))?;
940+
941+
self.send(&mut cmd_send, opaque_data)?;
942+
Ok(())
943+
}
889944
}
890945

891946
impl Drop for CrossDomainContext {
@@ -911,13 +966,24 @@ impl Drop for CrossDomainContext {
911966
}
912967

913968
#[repr(C)]
914-
#[derive(Copy, Clone, Debug, Default, FromBytes, IntoBytes, Immutable)]
969+
#[derive(Copy, Clone, Default, FromBytes, IntoBytes, Immutable)]
915970
struct CrossDomainInitLegacy {
916971
hdr: CrossDomainHeader,
917972
query_ring_id: u32,
918973
channel_type: u32,
919974
}
920975

976+
impl CrossDomainInitLegacy {
977+
pub(crate) fn upgrade(&self) -> CrossDomainInit {
978+
CrossDomainInit {
979+
hdr: self.hdr,
980+
query_ring_id: self.query_ring_id,
981+
channel_ring_id: self.query_ring_id,
982+
channel_type: self.channel_type,
983+
}
984+
}
985+
}
986+
921987
impl RutabagaContext for CrossDomainContext {
922988
fn context_create_blob(
923989
&mut self,
@@ -1025,24 +1091,13 @@ impl RutabagaContext for CrossDomainContext {
10251091

10261092
match hdr.cmd {
10271093
CROSS_DOMAIN_CMD_INIT => {
1028-
let cmd_init = match CrossDomainInit::read_from_prefix(commands) {
1029-
Ok((cmd_init, _)) => cmd_init,
1030-
_ => {
1031-
if let Ok((cmd_init, _)) =
1032-
CrossDomainInitLegacy::read_from_prefix(commands)
1033-
{
1034-
CrossDomainInit {
1035-
hdr: cmd_init.hdr,
1036-
query_ring_id: cmd_init.query_ring_id,
1037-
channel_ring_id: cmd_init.query_ring_id,
1038-
channel_type: cmd_init.channel_type,
1039-
}
1040-
} else {
1041-
return Err(RutabagaError::InvalidCommandBuffer);
1042-
}
1043-
}
1044-
};
1045-
1094+
let cmd_init = CrossDomainInit::read_from_prefix(commands)
1095+
.map(|(v, _)| v)
1096+
.or_else(|_| {
1097+
CrossDomainInitLegacy::read_from_prefix(commands)
1098+
.map(|(v, _)| v.upgrade())
1099+
})
1100+
.map_err(|_| RutabagaError::InvalidCommandBuffer)?;
10461101
self.initialize(&cmd_init)?;
10471102
}
10481103
CROSS_DOMAIN_CMD_GET_IMAGE_REQUIREMENTS => {
@@ -1053,20 +1108,7 @@ impl RutabagaContext for CrossDomainContext {
10531108
self.get_image_requirements(&cmd_get_reqs)?;
10541109
}
10551110
CROSS_DOMAIN_CMD_SEND => {
1056-
let opaque_data_offset = size_of::<CrossDomainSendReceive>();
1057-
let (cmd_send, _) = CrossDomainSendReceive::read_from_prefix(commands)
1058-
.map_err(|_e| RutabagaError::InvalidCommandBuffer)?;
1059-
1060-
let opaque_data = commands
1061-
.get_mut(
1062-
opaque_data_offset
1063-
..opaque_data_offset + cmd_send.opaque_data_size as usize,
1064-
)
1065-
.ok_or(RutabagaError::InvalidCommandSize(
1066-
cmd_send.opaque_data_size as usize,
1067-
))?;
1068-
1069-
self.send(&cmd_send, opaque_data)?;
1111+
self.process_cmd_send(commands)?;
10701112
}
10711113
CROSS_DOMAIN_CMD_POLL => {
10721114
// Actual polling is done in the subsequent when creating a fence.
@@ -1105,6 +1147,11 @@ impl RutabagaContext for CrossDomainContext {
11051147
.map_err(|_e| RutabagaError::InvalidCommandBuffer)?;
11061148
self.atomic_memory_sentinel_destroy(&cmd_atomic_memory_sentinel_destroy)?;
11071149
}
1150+
CROSS_DOMAIN_CMD_READ_CREATE_EVENT => {
1151+
let (cmd_new_evt, _) = CrossDomainCreateEvent::read_from_prefix(commands)
1152+
.map_err(|_| RutabagaError::InvalidCommandBuffer)?;
1153+
self.read_event_new(&cmd_new_evt)?;
1154+
}
11081155
_ => return Err(MesaError::WithContext("invalid cross domain command").into()),
11091156
}
11101157

src/rutabaga_utils.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,7 @@ impl Transfer3D {
608608
/// Rutabaga path types
609609
pub const RUTABAGA_PATH_TYPE_WAYLAND: u32 = 0x0001;
610610
pub const RUTABAGA_PATH_TYPE_GPU: u32 = 0x0002;
611+
pub const RUTABAGA_PATH_TYPE_PIPEWIRE: u32 = 0x0010;
611612
pub const RUTABAGA_PATH_TYPE_X11: u32 = 0x0011;
612613

613614
pub type RutabagaPaths = Vec<RutabagaPath>;

0 commit comments

Comments
 (0)