mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-06 02:25:23 +00:00
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 <noreply+kokoro@google.com> Commit-Queue: Chirantan Ekbote <chirantan@chromium.org> Reviewed-by: Chirantan Ekbote <chirantan@chromium.org> Auto-Submit: Chirantan Ekbote <chirantan@chromium.org>
This commit is contained in:
parent
cc91fc8252
commit
dd11d43473
2 changed files with 51 additions and 34 deletions
|
@ -8,7 +8,7 @@ mod protocol;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::i64;
|
use std::i64;
|
||||||
use std::mem::size_of;
|
use std::mem::{self, size_of};
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -474,7 +474,7 @@ struct Worker {
|
||||||
ctrl_evt: EventFd,
|
ctrl_evt: EventFd,
|
||||||
cursor_queue: Queue,
|
cursor_queue: Queue,
|
||||||
cursor_evt: EventFd,
|
cursor_evt: EventFd,
|
||||||
resource_bridge: Option<ResourceResponseSocket>,
|
resource_bridges: Vec<ResourceResponseSocket>,
|
||||||
kill_evt: EventFd,
|
kill_evt: EventFd,
|
||||||
state: Frontend,
|
state: Frontend,
|
||||||
}
|
}
|
||||||
|
@ -492,9 +492,9 @@ impl Worker {
|
||||||
CtrlQueue,
|
CtrlQueue,
|
||||||
CursorQueue,
|
CursorQueue,
|
||||||
Display,
|
Display,
|
||||||
ResourceBridge,
|
|
||||||
InterruptResample,
|
InterruptResample,
|
||||||
Kill,
|
Kill,
|
||||||
|
ResourceBridge { index: usize },
|
||||||
}
|
}
|
||||||
|
|
||||||
let poll_ctx: PollContext<Token> = match PollContext::new()
|
let poll_ctx: PollContext<Token> = match PollContext::new()
|
||||||
|
@ -517,12 +517,14 @@ impl Worker {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(resource_bridge) = &self.resource_bridge {
|
for (index, bridge) in self.resource_bridges.iter().enumerate() {
|
||||||
if let Err(e) = poll_ctx.add(resource_bridge, Token::ResourceBridge) {
|
if let Err(e) = poll_ctx.add(bridge, Token::ResourceBridge { index }) {
|
||||||
error!("failed to add resource bridge to PollContext: {}", e);
|
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 {
|
'poll: loop {
|
||||||
// If there are outstanding fences, wake up early to poll them.
|
// If there are outstanding fences, wake up early to poll them.
|
||||||
let duration = if !self.state.fence_descriptors.is_empty() {
|
let duration = if !self.state.fence_descriptors.is_empty() {
|
||||||
|
@ -539,7 +541,11 @@ impl Worker {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut signal_used = false;
|
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() {
|
for event in events.iter_readable() {
|
||||||
match event.token() {
|
match event.token() {
|
||||||
Token::CtrlQueue => {
|
Token::CtrlQueue => {
|
||||||
|
@ -558,7 +564,7 @@ impl Worker {
|
||||||
let _ = self.exit_evt.write(1);
|
let _ = self.exit_evt.write(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Token::ResourceBridge => process_resource_bridge = true,
|
Token::ResourceBridge { index } => process_resource_bridge[index] = true,
|
||||||
Token::InterruptResample => {
|
Token::InterruptResample => {
|
||||||
let _ = self.interrupt_resample_evt.read();
|
let _ = self.interrupt_resample_evt.read();
|
||||||
if self.interrupt_status.load(Ordering::SeqCst) != 0 {
|
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
|
// 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
|
// created or destroyed by the control queue. Processing the resource bridge first may
|
||||||
// lead to a race condition.
|
// lead to a race condition.
|
||||||
if process_resource_bridge {
|
for (bridge, &should_process) in
|
||||||
if let Some(resource_bridge) = &self.resource_bridge {
|
self.resource_bridges.iter().zip(&process_resource_bridge)
|
||||||
self.state.process_resource_bridge(resource_bridge);
|
{
|
||||||
|
if should_process {
|
||||||
|
self.state.process_resource_bridge(bridge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,7 +612,7 @@ pub struct Gpu {
|
||||||
config_event: bool,
|
config_event: bool,
|
||||||
exit_evt: EventFd,
|
exit_evt: EventFd,
|
||||||
gpu_device_socket: Option<VmMemoryControlRequestSocket>,
|
gpu_device_socket: Option<VmMemoryControlRequestSocket>,
|
||||||
resource_bridge: Option<ResourceResponseSocket>,
|
resource_bridges: Vec<ResourceResponseSocket>,
|
||||||
kill_evt: Option<EventFd>,
|
kill_evt: Option<EventFd>,
|
||||||
wayland_socket_path: PathBuf,
|
wayland_socket_path: PathBuf,
|
||||||
}
|
}
|
||||||
|
@ -613,14 +621,14 @@ impl Gpu {
|
||||||
pub fn new<P: AsRef<Path>>(
|
pub fn new<P: AsRef<Path>>(
|
||||||
exit_evt: EventFd,
|
exit_evt: EventFd,
|
||||||
gpu_device_socket: Option<VmMemoryControlRequestSocket>,
|
gpu_device_socket: Option<VmMemoryControlRequestSocket>,
|
||||||
resource_bridge: Option<ResourceResponseSocket>,
|
resource_bridges: Vec<ResourceResponseSocket>,
|
||||||
wayland_socket_path: P,
|
wayland_socket_path: P,
|
||||||
) -> Gpu {
|
) -> Gpu {
|
||||||
Gpu {
|
Gpu {
|
||||||
config_event: false,
|
config_event: false,
|
||||||
exit_evt,
|
exit_evt,
|
||||||
gpu_device_socket,
|
gpu_device_socket,
|
||||||
resource_bridge,
|
resource_bridges,
|
||||||
kill_evt: None,
|
kill_evt: None,
|
||||||
wayland_socket_path: wayland_socket_path.as_ref().to_path_buf(),
|
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());
|
keep_fds.push(self.exit_evt.as_raw_fd());
|
||||||
if let Some(resource_bridge) = &self.resource_bridge {
|
for bridge in &self.resource_bridges {
|
||||||
keep_fds.push(resource_bridge.as_raw_fd());
|
keep_fds.push(bridge.as_raw_fd());
|
||||||
}
|
}
|
||||||
keep_fds
|
keep_fds
|
||||||
}
|
}
|
||||||
|
@ -739,7 +747,7 @@ impl VirtioDevice for Gpu {
|
||||||
};
|
};
|
||||||
self.kill_evt = Some(self_kill_evt);
|
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_queue = queues.remove(0);
|
||||||
let ctrl_evt = queue_evts.remove(0);
|
let ctrl_evt = queue_evts.remove(0);
|
||||||
|
@ -802,7 +810,7 @@ impl VirtioDevice for Gpu {
|
||||||
ctrl_evt,
|
ctrl_evt,
|
||||||
cursor_queue,
|
cursor_queue,
|
||||||
cursor_evt,
|
cursor_evt,
|
||||||
resource_bridge,
|
resource_bridges,
|
||||||
kill_evt,
|
kill_evt,
|
||||||
state: Frontend::new(Backend::new(
|
state: Frontend::new(Backend::new(
|
||||||
device,
|
device,
|
||||||
|
|
43
src/linux.rs
43
src/linux.rs
|
@ -552,7 +552,7 @@ fn create_gpu_device(
|
||||||
cfg: &Config,
|
cfg: &Config,
|
||||||
exit_evt: &EventFd,
|
exit_evt: &EventFd,
|
||||||
gpu_device_socket: VmMemoryControlRequestSocket,
|
gpu_device_socket: VmMemoryControlRequestSocket,
|
||||||
gpu_socket: virtio::resource_bridge::ResourceResponseSocket,
|
gpu_sockets: Vec<virtio::resource_bridge::ResourceResponseSocket>,
|
||||||
wayland_socket_path: &Path,
|
wayland_socket_path: &Path,
|
||||||
) -> DeviceResult {
|
) -> DeviceResult {
|
||||||
let jailed_wayland_path = Path::new("/wayland-0");
|
let jailed_wayland_path = Path::new("/wayland-0");
|
||||||
|
@ -560,7 +560,7 @@ fn create_gpu_device(
|
||||||
let dev = virtio::Gpu::new(
|
let dev = virtio::Gpu::new(
|
||||||
exit_evt.try_clone().map_err(Error::CloneEventFd)?,
|
exit_evt.try_clone().map_err(Error::CloneEventFd)?,
|
||||||
Some(gpu_device_socket),
|
Some(gpu_device_socket),
|
||||||
Some(gpu_socket),
|
gpu_sockets,
|
||||||
if cfg.sandbox {
|
if cfg.sandbox {
|
||||||
&jailed_wayland_path
|
&jailed_wayland_path
|
||||||
} else {
|
} else {
|
||||||
|
@ -835,36 +835,45 @@ fn create_virtio_devices(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "gpu"), allow(unused_mut))]
|
#[cfg_attr(not(feature = "gpu"), allow(unused_mut))]
|
||||||
let mut resource_bridge_wl_socket = None::<virtio::resource_bridge::ResourceRequestSocket>;
|
let mut resource_bridges = Vec::<virtio::resource_bridge::ResourceResponseSocket>::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::<virtio::resource_bridge::ResourceRequestSocket>;
|
||||||
|
|
||||||
|
#[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")]
|
#[cfg(feature = "gpu")]
|
||||||
{
|
{
|
||||||
if cfg.gpu {
|
if cfg.gpu {
|
||||||
if let Some(wayland_socket_path) = &cfg.wayland_socket_path {
|
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(
|
devs.push(create_gpu_device(
|
||||||
cfg,
|
cfg,
|
||||||
_exit_evt,
|
_exit_evt,
|
||||||
gpu_device_socket,
|
gpu_device_socket,
|
||||||
gpu_socket,
|
resource_bridges,
|
||||||
wayland_socket_path,
|
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 {
|
if let Some(cid) = cfg.cid {
|
||||||
devs.push(create_vhost_vsock_device(cfg, cid, mem)?);
|
devs.push(create_vhost_vsock_device(cfg, cid, mem)?);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue