diff --git a/docker/devenv/Dockerfile b/docker/devenv/Dockerfile index 0d8f85586b..082ee3f2b6 100644 --- a/docker/devenv/Dockerfile +++ b/docker/devenv/Dockerfile @@ -431,6 +431,8 @@ RUN set -ex; \ fontforge \ \ xvfb \ + xauth \ + libvulkan1 \ fonts-noto-color-emoji \ fonts-unifont \ libfontconfig1 \ diff --git a/docker/devenv/docker-compose.gpu.yml b/docker/devenv/docker-compose.gpu.yml new file mode 100644 index 0000000000..99c21037b0 --- /dev/null +++ b/docker/devenv/docker-compose.gpu.yml @@ -0,0 +1,14 @@ +services: + main: + environment: + - NVIDIA_DRIVER_CAPABILITIES=all + - PENPOT_GPU=1 + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: [gpu] + volumes: + - /usr/share/vulkan/icd.d:/usr/share/vulkan/icd.d:ro diff --git a/docs/technical-guide/developer/devenv.md b/docs/technical-guide/developer/devenv.md index 89144fd399..6ec4c8fc25 100644 --- a/docs/technical-guide/developer/devenv.md +++ b/docs/technical-guide/developer/devenv.md @@ -12,7 +12,7 @@ in order to correctly set up the development environment. You can [look here][1] for complete instructions. -[1]: /technical-guide/getting-started/#install-with-docker +[1]: /technical-guide/getting-started/docker Optionally, to improve performance, you can also increase the maximum number of @@ -119,8 +119,9 @@ Container-internal ports stay fixed. Target a specific instance with accepts a **non-negative integer only** — `--ws main` or `--ws ws1` is rejected, keeping the flag shape uniform across commands. `run-devenv` is ws0-only and takes no workspace flag. `run-devenv` also accepts -`--serena-context CTX` (used together with `--agentic`) and `--git-user-name NAME` / `--git-user-email -EMAIL` (see below). +`--serena-context CTX` (used together with `--agentic`), `--gpu` to enable +hardware rendering in Chromium (e.g. for benchmarks), and `--git-user-name NAME` +/ `--git-user-email EMAIL` (see below). Configuration lives in one tracked file, `docker/devenv/defaults.env` (the ws0 baseline); `ws1+` values (offset ports, `wsN` container/volume names) are @@ -166,6 +167,49 @@ container (same UID mapping as the source tree). Opencode's own state (sessions, `auth.json`) lives in `~/.local/share/opencode`, which stays in the container's data volume regardless of this flag. +### NVIDIA GPU access + +On Linux, `run-devenv --gpu` grants the selected container access to NVIDIA +GPUs. The host needs an NVIDIA driver, NVIDIA Container Toolkit configured +with a Docker runtime named `nvidia`, and a readable Vulkan driver manifest +at `/usr/share/vulkan/icd.d/nvidia_icd.json`. The option checks the runtime +and manifest before provisioning. + +Build an image from this checkout to include `xauth` and the Vulkan loader +(`libvulkan1`), then use the same tag when starting the container: + +```bash +./manage.sh build-devenv --tag gpu-local +DEVENV_TAG=gpu-local ./manage.sh run-devenv --gpu +``` + +`--gpu` works with `--ws N`, `--agentic`, `--attach`, and +`--opencode-config-dir DIR`. For example: + +```bash +DEVENV_TAG=gpu-local ./manage.sh run-devenv --gpu --ws 1 --agentic +``` + +The GPU overlay requests all NVIDIA devices and driver capabilities and +mounts the host Vulkan manifest directory read-only. Processes inside the +container inherit `PENPOT_GPU=1` and `NVIDIA_DRIVER_CAPABILITIES=all`. +`PENPOT_GPU` signals GPU access to applications. The explicit `--gpu` flag +selects the overlay. + +GPU mode applies at container creation and lasts for that container's +lifetime. To change it, stop the selected instance and run it again with +or without `--gpu`: + +```bash +./manage.sh stop-devenv --ws 1 +DEVENV_TAG=gpu-local ./manage.sh run-devenv --ws 1 +``` + +Run browser commands inside devenv. The Chromium ANGLE Vulkan backend +needs an X display in this setup, so run those commands under +`xvfb-run -a`. Each caller starts its own Xvfb display. Applications choose +their rendering backend. + ### Shared state and workers All instances share one Penpot database and one RustFS bucket; users, teams, @@ -385,7 +429,7 @@ Warning: by default Cursor won't support HTTPS with a self-signed certificate. I An example of your cursor configuration can be: -```javascript +```json { "mcpServers": { "penpot-devenv": { diff --git a/manage.sh b/manage.sh index 9ef5fb72ad..540ce98c77 100755 --- a/manage.sh +++ b/manage.sh @@ -236,6 +236,24 @@ function infra-compose { "$@" } +function check-devenv-gpu-support { + local runtimes + if ! runtimes=$(env -i HOME="$HOME" PATH="$PATH" PWD="$PWD" \ + docker info --format '{{range $name, $_ := .Runtimes}}{{$name}} {{end}}'); then + echo "run-devenv: cannot query Docker runtimes; check that Docker is running and accessible." >&2 + return 1 + fi + if [[ " $runtimes " != *" nvidia "* ]]; then + echo "run-devenv: --gpu requires Docker runtime 'nvidia'; install and configure NVIDIA Container Toolkit." >&2 + return 1 + fi + local icd=/usr/share/vulkan/icd.d/nvidia_icd.json + if [[ ! -f "$icd" || ! -r "$icd" ]]; then + echo "run-devenv: --gpu requires a readable $icd; install the host NVIDIA Vulkan driver." >&2 + return 1 + fi +} + function instance-compose { local instance="$1"; shift local source_path @@ -258,6 +276,10 @@ function instance-compose { compose_files+=(-f docker/devenv/docker-compose.opencode.yml) opencode_env=("PENPOT_OPENCODE_CONFIG_DIR=${PENPOT_OPENCODE_CONFIG_DIR}") fi + # Bash dynamic scope exposes run-devenv's local option here. + if [[ "${devenv_gpu:-false}" == "true" ]]; then + compose_files+=(-f docker/devenv/docker-compose.gpu.yml) + fi env -i HOME="$HOME" PATH="$PATH" PWD="$PWD" \ CURRENT_USER_ID="${CURRENT_USER_ID:-$(id -u)}" \ @@ -875,6 +897,7 @@ function run-devenv { local do_sync=false local do_attach=false local agentic=false + local devenv_gpu=false local serena_context="desktop-app" local git_user_name="" local git_user_email="" @@ -889,6 +912,8 @@ function run-devenv { do_sync=true; shift;; --agentic) agentic=true; shift;; + --gpu) + devenv_gpu=true; shift;; --attach) do_attach=true; shift;; --serena-context) @@ -904,12 +929,13 @@ function run-devenv { -e*) extra_env_args+=(-e "${1#-e}"); shift;; -h|--help) - echo "Usage: run-devenv [--ws N] [--sync] [--attach] [--agentic] [--serena-context CTX] [--opencode-config-dir DIR] [--git-user-name NAME] [--git-user-email EMAIL] [-e KEY=VAL]" + echo "Usage: run-devenv [--ws N] [--sync] [--attach] [--agentic] [--gpu] [--serena-context CTX] [--opencode-config-dir DIR] [--git-user-name NAME] [--git-user-email EMAIL] [-e KEY=VAL]" echo " Bring a single workspace up." echo " --ws N target workspace (default: 0)." echo " --sync re-seed the wsN clone from the live repo (forbidden on ws0)." echo " --attach attach to the tmux session after startup." echo " --agentic enable MCP + Serena (AI-agent mode)." + echo " --gpu grant NVIDIA GPU access at container creation." echo " --serena-context CTX context passed to Serena (default: desktop-app)." echo " --opencode-config-dir DIR bind-mount DIR at ~/.config/opencode inside the" echo " container (personal agents/prompts/skills kept in a" @@ -963,6 +989,10 @@ function run-devenv { return 1 fi + if [[ "$devenv_gpu" == "true" ]]; then + check-devenv-gpu-support || return 1 + fi + pull-devenv-if-not-exists ensure-devenv-network ensure-infra-up @@ -1485,6 +1515,7 @@ function usage { echo " start of a wsN with no on-disk workspace yet)." echo " --attach attach to the tmux session after startup." echo " --agentic enable MCP + Serena (AI-agent mode)." + echo " --gpu grant NVIDIA GPU access at container creation." echo " --serena-context CTX passed to Serena (default: desktop-app)." echo " --opencode-config-dir DIR" echo " bind-mount DIR over the container's"