From dd11d434730a5dea56106d0533bf42c6b7206ed0 Mon Sep 17 00:00:00 2001 From: Chirantan Ekbote Date: Tue, 11 Jun 2019 21:50:46 +0900 Subject: [PATCH] gpu: Allow more than one resource bridge socket Currently the wayland device accesses buffers allocated by the gpu device via a dedicated socket connection. Upcoming virtual devices like vdec and camera will also need access to these buffers. Modify the gpu device so that it can process requests on multiple resource_bridge sockets. Each future device that needs access to gpu device buffers should create a new resource bridge socket pair and add it to the list of sockets that the gpu device monitors. The actual interface between the devices is unchanged. BUG=b:133381367 TEST=run glxgears in a crostini container with and without gpu enabled Change-Id: I58693881945965071a53653bf4f86681725267d0 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1652876 Tested-by: kokoro Commit-Queue: Chirantan Ekbote Reviewed-by: Chirantan Ekbote Auto-Submit: Chirantan Ekbote --- devices/src/virtio/gpu/mod.rs | 42 ++++++++++++++++++++-------------- src/linux.rs | 43 +++++++++++++++++++++-------------- 2 files changed, 51 insertions(+), 34 deletions(-) diff --git a/devices/src/virtio/gpu/mod.rs b/devices/src/virtio/gpu/mod.rs index cc42ace0f6..0031b73e47 100644 --- a/devices/src/virtio/gpu/mod.rs +++ b/devices/src/virtio/gpu/mod.rs @@ -8,7 +8,7 @@ mod protocol; use std::cell::RefCell; use std::collections::VecDeque; use std::i64; -use std::mem::size_of; +use std::mem::{self, size_of}; use std::os::unix::io::{AsRawFd, RawFd}; use std::path::{Path, PathBuf}; use std::rc::Rc; @@ -474,7 +474,7 @@ struct Worker { ctrl_evt: EventFd, cursor_queue: Queue, cursor_evt: EventFd, - resource_bridge: Option, + resource_bridges: Vec, kill_evt: EventFd, state: Frontend, } @@ -492,9 +492,9 @@ impl Worker { CtrlQueue, CursorQueue, Display, - ResourceBridge, InterruptResample, Kill, + ResourceBridge { index: usize }, } let poll_ctx: PollContext = match PollContext::new() @@ -517,12 +517,14 @@ impl Worker { } }; - if let Some(resource_bridge) = &self.resource_bridge { - if let Err(e) = poll_ctx.add(resource_bridge, Token::ResourceBridge) { + for (index, bridge) in self.resource_bridges.iter().enumerate() { + if let Err(e) = poll_ctx.add(bridge, Token::ResourceBridge { index }) { error!("failed to add resource bridge to PollContext: {}", e); } } + // Declare this outside the loop so we don't keep allocating and freeing the vector. + let mut process_resource_bridge = Vec::with_capacity(self.resource_bridges.len()); 'poll: loop { // If there are outstanding fences, wake up early to poll them. let duration = if !self.state.fence_descriptors.is_empty() { @@ -539,7 +541,11 @@ impl Worker { } }; let mut signal_used = false; - let mut process_resource_bridge = false; + + // Clear the old values and re-initialize with false. + process_resource_bridge.clear(); + process_resource_bridge.resize(self.resource_bridges.len(), false); + for event in events.iter_readable() { match event.token() { Token::CtrlQueue => { @@ -558,7 +564,7 @@ impl Worker { let _ = self.exit_evt.write(1); } } - Token::ResourceBridge => process_resource_bridge = true, + Token::ResourceBridge { index } => process_resource_bridge[index] = true, Token::InterruptResample => { let _ = self.interrupt_resample_evt.read(); if self.interrupt_status.load(Ordering::SeqCst) != 0 { @@ -587,9 +593,11 @@ impl Worker { // Process the entire control queue before the resource bridge in case a resource is // created or destroyed by the control queue. Processing the resource bridge first may // lead to a race condition. - if process_resource_bridge { - if let Some(resource_bridge) = &self.resource_bridge { - self.state.process_resource_bridge(resource_bridge); + for (bridge, &should_process) in + self.resource_bridges.iter().zip(&process_resource_bridge) + { + if should_process { + self.state.process_resource_bridge(bridge); } } @@ -604,7 +612,7 @@ pub struct Gpu { config_event: bool, exit_evt: EventFd, gpu_device_socket: Option, - resource_bridge: Option, + resource_bridges: Vec, kill_evt: Option, wayland_socket_path: PathBuf, } @@ -613,14 +621,14 @@ impl Gpu { pub fn new>( exit_evt: EventFd, gpu_device_socket: Option, - resource_bridge: Option, + resource_bridges: Vec, wayland_socket_path: P, ) -> Gpu { Gpu { config_event: false, exit_evt, gpu_device_socket, - resource_bridge, + resource_bridges, kill_evt: None, wayland_socket_path: wayland_socket_path.as_ref().to_path_buf(), } @@ -664,8 +672,8 @@ impl VirtioDevice for Gpu { } keep_fds.push(self.exit_evt.as_raw_fd()); - if let Some(resource_bridge) = &self.resource_bridge { - keep_fds.push(resource_bridge.as_raw_fd()); + for bridge in &self.resource_bridges { + keep_fds.push(bridge.as_raw_fd()); } keep_fds } @@ -739,7 +747,7 @@ impl VirtioDevice for Gpu { }; self.kill_evt = Some(self_kill_evt); - let resource_bridge = self.resource_bridge.take(); + let resource_bridges = mem::replace(&mut self.resource_bridges, Vec::new()); let ctrl_queue = queues.remove(0); let ctrl_evt = queue_evts.remove(0); @@ -802,7 +810,7 @@ impl VirtioDevice for Gpu { ctrl_evt, cursor_queue, cursor_evt, - resource_bridge, + resource_bridges, kill_evt, state: Frontend::new(Backend::new( device, diff --git a/src/linux.rs b/src/linux.rs index 2fe1d5b2b9..48cbe522f1 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -552,7 +552,7 @@ fn create_gpu_device( cfg: &Config, exit_evt: &EventFd, gpu_device_socket: VmMemoryControlRequestSocket, - gpu_socket: virtio::resource_bridge::ResourceResponseSocket, + gpu_sockets: Vec, wayland_socket_path: &Path, ) -> DeviceResult { let jailed_wayland_path = Path::new("/wayland-0"); @@ -560,7 +560,7 @@ fn create_gpu_device( let dev = virtio::Gpu::new( exit_evt.try_clone().map_err(Error::CloneEventFd)?, Some(gpu_device_socket), - Some(gpu_socket), + gpu_sockets, if cfg.sandbox { &jailed_wayland_path } else { @@ -835,36 +835,45 @@ fn create_virtio_devices( } #[cfg_attr(not(feature = "gpu"), allow(unused_mut))] - let mut resource_bridge_wl_socket = None::; + let mut resource_bridges = Vec::::new(); + + if let Some(wayland_socket_path) = cfg.wayland_socket_path.as_ref() { + #[cfg_attr(not(feature = "gpu"), allow(unused_mut))] + let mut wl_resource_bridge = None::; + + #[cfg(feature = "gpu")] + { + if cfg.gpu { + let (wl_socket, gpu_socket) = + virtio::resource_bridge::pair().map_err(Error::CreateSocket)?; + resource_bridges.push(gpu_socket); + wl_resource_bridge = Some(wl_socket); + } + } + + devs.push(create_wayland_device( + cfg, + wayland_socket_path, + wayland_device_socket, + wl_resource_bridge, + )?); + } #[cfg(feature = "gpu")] { if cfg.gpu { if let Some(wayland_socket_path) = &cfg.wayland_socket_path { - let (wl_socket, gpu_socket) = - virtio::resource_bridge::pair().map_err(Error::CreateSocket)?; - resource_bridge_wl_socket = Some(wl_socket); - devs.push(create_gpu_device( cfg, _exit_evt, gpu_device_socket, - gpu_socket, + resource_bridges, wayland_socket_path, )?); } } } - if let Some(wayland_socket_path) = cfg.wayland_socket_path.as_ref() { - devs.push(create_wayland_device( - cfg, - wayland_socket_path, - wayland_device_socket, - resource_bridge_wl_socket, - )?); - } - if let Some(cid) = cfg.cid { devs.push(create_vhost_vsock_device(cfg, cid, mem)?); }