devices: gpu: add render server support
When "--gpu-render-server path=<path>" is specified, start the render
server shipped with virglrenderer and initialize virglrenderer with
VIRGLRENDERER_MULTI_PROCESS flag.
The flag makes virgl_renderer_context_create_with_flags create proxy
contexts instead of venus contexts. Each proxy context requests the
render server to fork a subprocess and executes GPU commands in the
subprocess.
BUG=b:177267762
TEST=run vk and gl apps on volteer
Change-Id: If5e2dc3353572cadb60b0c25a3e0ad14f633db91
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3283508
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Chia-I Wu <olv@google.com>
diff --git a/src/linux.rs b/src/linux.rs
index 4cadf40..791e61b 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -44,7 +44,7 @@
use devices::virtio::{self, Console, VirtioDevice};
#[cfg(feature = "gpu")]
use devices::virtio::{
- gpu::{DEFAULT_DISPLAY_HEIGHT, DEFAULT_DISPLAY_WIDTH},
+ gpu::{GpuRenderServerParameters, DEFAULT_DISPLAY_HEIGHT, DEFAULT_DISPLAY_WIDTH},
vhost::user::vmm::Gpu as VhostUserGpu,
EventDevice,
};
@@ -802,6 +802,7 @@
resource_bridges: Vec<Tube>,
wayland_socket_path: Option<&PathBuf>,
x_display: Option<String>,
+ render_server_fd: Option<SafeDescriptor>,
event_devices: Vec<EventDevice>,
map_request: Arc<Mutex<Option<ExternalMapping>>>,
) -> DeviceResult {
@@ -830,6 +831,7 @@
resource_bridges,
display_backends,
cfg.gpu_parameters.as_ref().unwrap(),
+ render_server_fd,
event_devices,
map_request,
cfg.sandbox,
@@ -884,6 +886,46 @@
})
}
+#[cfg(feature = "gpu")]
+fn start_gpu_render_server(
+ cfg: &Config,
+ render_server_parameters: &GpuRenderServerParameters,
+) -> Result<SafeDescriptor> {
+ let (server_socket, client_socket) =
+ UnixSeqpacket::pair().context("failed to create render server socket")?;
+
+ let jail = match gpu_jail(cfg, "gpu_render_server")? {
+ Some(mut jail) => {
+ // TODO(olv) bind mount and enable shader cache
+
+ // Run as root in the jail to keep capabilities after execve, which is needed for
+ // mounting to work. All capabilities will be dropped afterwards.
+ add_current_user_as_root_to_jail(&mut jail)?;
+
+ jail
+ }
+ None => Minijail::new().context("failed to create jail")?,
+ };
+
+ let inheritable_fds = [
+ server_socket.as_raw_descriptor(),
+ libc::STDOUT_FILENO,
+ libc::STDERR_FILENO,
+ ];
+
+ let cmd = &render_server_parameters.path;
+ let cmd_str = cmd
+ .to_str()
+ .ok_or_else(|| anyhow!("invalid render server path"))?;
+ let fd_str = server_socket.as_raw_descriptor().to_string();
+ let args = [cmd_str, "--socket-fd", &fd_str];
+
+ jail.run(cmd, &inheritable_fds, &args)
+ .context("failed to start gpu render server")?;
+
+ Ok(SafeDescriptor::from(client_socket))
+}
+
fn create_wayland_device(
cfg: &Config,
control_tube: Tube,
@@ -1549,6 +1591,12 @@
});
event_devices.push(EventDevice::keyboard(event_device_socket));
}
+
+ let mut render_server_fd = None;
+ if let Some(ref render_server_parameters) = gpu_parameters.render_server {
+ render_server_fd = Some(start_gpu_render_server(cfg, render_server_parameters)?);
+ }
+
devs.push(create_gpu_device(
cfg,
_exit_evt,
@@ -1557,6 +1605,7 @@
// Use the unnamed socket for GPU display screens.
cfg.wayland_socket_paths.get(""),
cfg.x_display.clone(),
+ render_server_fd,
event_devices,
map_request,
)?);
@@ -1869,6 +1918,20 @@
})
}
+fn add_current_user_as_root_to_jail(jail: &mut Minijail) -> Result<Ids> {
+ let crosvm_uid = geteuid();
+ let crosvm_gid = getegid();
+ jail.uidmap(&format!("0 {0} 1", crosvm_uid))
+ .context("error setting UID map")?;
+ jail.gidmap(&format!("0 {0} 1", crosvm_gid))
+ .context("error setting GID map")?;
+
+ Ok(Ids {
+ uid: crosvm_uid,
+ gid: crosvm_gid,
+ })
+}
+
trait IntoUnixStream {
fn into_unix_stream(self) -> Result<UnixStream>;
}