Skip to content

Commit 4793716

Browse files
committed
WIP --gpu passthrough support
Experimental and untested
1 parent a08c140 commit 4793716

File tree

4 files changed

+65
-0
lines changed

4 files changed

+65
-0
lines changed

src/cli.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,12 @@ pub struct CmdStartArgs {
130130
#[arg(long, value_name = "BOOL", default_missing_value = "true", require_equals = true, num_args = 0..=1, help_heading = START_HEADING_PERMISSIONS)]
131131
pub wayland: Option<bool>,
132132

133+
/// Passes through GPUs by their index, use 0 for all
134+
///
135+
/// If passed without argument then use no gpu
136+
#[arg(long = "gpus", require_equals = true, num_args = 0.., value_delimiter = ',', help_heading = START_HEADING_PERMISSIONS)]
137+
pub gpus: Option<Vec<u8>>,
138+
133139
/// Pass through ssh-agent socket
134140
#[arg(long, value_name = "BOOL", default_missing_value = "true", require_equals = true, num_args = 0..=1, help_heading = START_HEADING_PERMISSIONS)]
135141
pub ssh_agent: Option<bool>,

src/commands/cmd_start.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ pub fn start_container(ctx: Context, mut cli_args: CmdStartArgs) -> Result<()> {
158158
cli_args.pipewire = cli_args.pipewire.or(Some(config.pipewire));
159159
cli_args.pulseaudio = cli_args.pulseaudio.or(Some(config.pulseaudio));
160160
cli_args.wayland = cli_args.wayland.or(Some(config.wayland));
161+
cli_args.gpus = cli_args.gpus.or(Some(config.gpus));
161162
cli_args.ssh_agent = cli_args.ssh_agent.or(Some(config.ssh_agent));
162163
cli_args.session_bus = cli_args.session_bus.or(Some(config.session_bus));
163164
cli_args.ports.extend_from_slice(&config.ports);
@@ -290,6 +291,8 @@ pub fn start_container(ctx: Context, mut cli_args: CmdStartArgs) -> Result<()> {
290291

291292
mount_wayland(&ctx, &cli_args, &mut cmd)?;
292293

294+
gpu_passthrough(&ctx, &cli_args, &mut cmd)?;
295+
293296
mount_ssh_agent(&ctx, &cli_args, &mut cmd)?;
294297

295298
mount_session_bus(&ctx, &cli_args, &mut cmd)?;

src/commands/cmd_start/util.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,58 @@ pub fn mount_wayland(ctx: &Context, cli_args: &CmdStartArgs, cmd: &mut Command)
224224
Ok(())
225225
}
226226

227+
pub fn gpu_passthrough(_ctx: &Context, cli_args: &CmdStartArgs, cmd: &mut Command) -> Result<()> {
228+
use std::fs;
229+
230+
let gpus = cli_args.gpus.clone().unwrap_or_else(|| vec![]);
231+
232+
// no gpus selected do nothing
233+
if gpus.is_empty() {
234+
return Ok(());
235+
}
236+
237+
let mut files: Vec<String> = vec![];
238+
239+
// 0 means copy all
240+
if gpus.contains(&0) {
241+
log::debug!("Adding all GPU devices");
242+
243+
for entry in std::fs::read_dir("/dev/dri").expect("Error reading /dev/dri") {
244+
let entry = entry?;
245+
246+
// just filter paths by name
247+
let filename = entry.file_name().to_string_lossy().to_string();
248+
if filename.starts_with("card") || filename.starts_with("renderD") {
249+
log::debug!("Found {:?}", entry.path());
250+
files.push(entry.path().to_string_lossy().to_string());
251+
}
252+
}
253+
} else {
254+
log::debug!("Adding GPU devices");
255+
256+
for gpu_index in gpus {
257+
// NOTE: for some reason first card is /dev/dri/card1 and /dev/renderD128
258+
let card = format!("/dev/dri/card{gpu_index}");
259+
let render = format!("/dev/dri/renderD{}", 127 + gpu_index);
260+
261+
if fs::exists(&card).is_ok_and(|x| x) && fs::exists(&render).is_ok_and(|x| x) {
262+
log::debug!("Found GPU {gpu_index} at {card:?} and {render:?}");
263+
264+
files.push(card);
265+
files.push(render);
266+
} else {
267+
return Err(anyhow!("Could not find card with index {gpu_index}"));
268+
}
269+
}
270+
}
271+
272+
for path in files {
273+
cmd.args([format!("--device={path}")]);
274+
}
275+
276+
Ok(())
277+
}
278+
227279
pub fn mount_additional_mounts(
228280
ws_dir: &Path,
229281
cli_args: &CmdStartArgs,

src/config/v1.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ code_docs_struct! {
5151
#[serde(default)]
5252
pub wayland: bool,
5353

54+
/// Passthrough GPUs by their index, use 0 for all
55+
#[serde(default)]
56+
pub gpus: Vec<u8>,
57+
5458
/// Passthrough ssh-agent socket, security impact is unknown
5559
#[serde(default)]
5660
pub ssh_agent: bool,

0 commit comments

Comments
 (0)