Configuring Intel GVT-g on Proxmox VE: Sharing Your iGPU Across Multiple VMs Simultaneously

Virtualization tutorial - IT technology blog
Virtualization tutorial - IT technology blog

Background: When the iGPU Sits Idle While the CPU Chokes

I run a homelab with Proxmox VE managing 12 VMs and containers — it’s my playground for testing everything before pushing to production. One day I wanted to run Jellyfin on a VM for H.265 4K video transcoding, but software transcoding on the CPU was painfully slow and consumed the entire cluster’s resources. Buying a discrete GPU just for transcoding felt wasteful, especially when the Intel i7-8700 already on the board had a UHD 630 iGPU sitting completely idle.

That’s when I discovered Intel GVT-g (Graphics Virtualization Technology – graphics). Instead of passing through the entire iGPU to a single VM like standard VFIO, GVT-g lets you create multiple virtual vGPUs from one physical iGPU and share them across multiple VMs simultaneously. Each VM sees its own dedicated graphics device, operating independently.

On hardware compatibility: GVT-g is supported from Intel Broadwell (5th gen) and newer. In practice, Skylake (6th gen, i-6xxx series) is where things are stable and well-tested — if you have an older board, test before getting your hopes up.

When Does GVT-g Make Sense?

  • Hardware video transcoding (H.264/H.265) in Plex or Jellyfin running on a VM
  • Windows VMs that need a lightweight GPU for rendering the interface or running office graphics applications
  • Linux desktop VMs that need hardware acceleration (WebGL, VA-API)
  • Developing/testing OpenCL applications in a virtualized environment

To be clear: GVT-g is not a solution for gaming or heavy 3D rendering — those still require a discrete GPU with full VFIO passthrough. GVT-g is suited for light to moderate workloads. For a homelab, it’s the perfect way to squeeze value out of existing hardware without spending a dime.

Preparing Your Environment

Checking Your Hardware

First, confirm that the Proxmox host has recognized the Intel iGPU:

lspci | grep -i vga
# Expected output:
# 00:02.0 VGA compatible controller: Intel Corporation UHD Graphics 630 (rev 02)

# Check if the i915 driver is loaded
lsmod | grep i915

No output from lspci? Check the BIOS to see if the iGPU has been disabled — some boards automatically disable the iGPU when a discrete GPU is installed.

Software Requirements

  • Proxmox VE 7.x or 8.x (8.x recommended with kernel 6.2+)
  • Linux kernel 5.4 or higher (Proxmox VE 7 uses 5.15, VE 8 uses 6.2+)

Installation: Enabling GVT-g Step by Step

Step 1: Enable VT-d in BIOS/UEFI

Go into the BIOS and find the VT-d (Intel Virtualization Technology for Directed I/O) setting and enable it. The exact name varies by board — it’s usually under Advanced CPU Configuration or Chipset Settings.

Step 2: Add Kernel Parameters

Edit /etc/default/grub on the Proxmox host:

nano /etc/default/grub

Find the GRUB_CMDLINE_LINUX_DEFAULT line and change it to:

GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on iommu=pt i915.enable_gvt=1"

What these three flags do:

  • intel_iommu=on — Enables Intel’s IOMMU (VT-d)
  • iommu=pt — Pass-through mode, reduces overhead for devices that don’t need IOMMU
  • i915.enable_gvt=1 — Enables GVT functionality in the i915 driver
update-grub
reboot

Step 3: Load the Required Kernel Modules

After rebooting, add the modules to /etc/modules:

echo "kvmgt" >> /etc/modules
echo "vfio-mdev" >> /etc/modules
echo "mdev" >> /etc/modules

# Load immediately without rebooting
modprobe kvmgt
modprobe vfio-mdev
modprobe mdev

Verify that GVT-g is activated:

dmesg | grep -i gvt
# Output OK:
# [    5.12] i915 0000:00:02.0: GVT-g enabled

# List available vGPU types
ls /sys/bus/pci/devices/0000:00:02.0/mdev_supported_types/
# i915-GVTg_V5_1  i915-GVTg_V5_2  i915-GVTg_V5_4  i915-GVTg_V5_8

Detailed Configuration: Creating vGPUs and Assigning Them to VMs

Choosing the Right vGPU Type

Proxmox offers 4 vGPU types, differing in VRAM capacity and how many instances can run simultaneously:

  • i915-GVTg_V5_1 — 512MB VRAM, up to 7 instances
  • i915-GVTg_V5_2 — 1GB VRAM, up to 3 instances
  • i915-GVTg_V5_4 — 2GB VRAM, up to 1 instance
  • i915-GVTg_V5_8 — 2GB VRAM (high-res support), 1 instance

For Jellyfin transcoding, I chose V5_2 (1GB VRAM) for 2 VMs running in parallel — enough headroom while still leaving some margin.

Creating the vGPU (Mediated Device)

# Generate a UUID for the vGPU
UUID1=$(uuidgen)
echo $UUID1
# Example: a297db4a-f4c2-11ee-b956-0242ac120002

# Create vGPU with type V5_2
echo "$UUID1" > /sys/bus/pci/devices/0000:00:02.0/mdev_supported_types/i915-GVTg_V5_2/create

# Confirm creation
ls /sys/bus/mdev/devices/
# a297db4a-f4c2-11ee-b956-0242ac120002

To automatically recreate the vGPU after each reboot, create a systemd service:

cat > /etc/systemd/system/gvt-g-create.service << 'EOF'
[Unit]
Description=Create Intel GVT-g vGPU devices
After=syslog.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/bash -c 'echo "a297db4a-f4c2-11ee-b956-0242ac120002" > /sys/bus/pci/devices/0000:00:02.0/mdev_supported_types/i915-GVTg_V5_2/create'

[Install]
WantedBy=multi-user.target
EOF

systemctl enable --now gvt-g-create.service

Assigning the vGPU to a VM in Proxmox

Each VM’s config file in Proxmox is located at /etc/pve/qemu-server/. For VM ID 100:

nano /etc/pve/qemu-server/100.conf

Paste the following line, replacing the UUID with the one you just generated:

hostpci0: 0000:00:02.0,mdev=a297db4a-f4c2-11ee-b956-0242ac120002

One important gotcha that took me a while to figure out: the VM must use SeaBIOS and the machine type i440fx, not OVMF/UEFI or q35. GVT-g legacy mode only works reliably with i440fx:

# Check in the VM config file
bios: seabios
machine: pc-i440fx-8.1

Start the VM and verify from inside:

# Inside the Linux VM
lspci | grep -i vga
# 00:02.0 VGA compatible controller: Intel Corporation ...

# Check GPU information
vainfo
# libva info: VA-API version 1.x.x
# libva info: Trying to open /dev/dri/renderD128
# vainfo: VA-API version: 1.x (libva 2.x.x)
# vainfo: Driver version: Intel i965 driver

Testing and Monitoring

Monitoring GPU Usage on the Host

# Install intel-gpu-tools
apt install intel-gpu-tools

# Real-time GPU usage
intel_gpu_top

# Check residency (whether the GPU is active)
cat /sys/class/drm/card0/gt/gt0/rc6_residency_ms

While Jellyfin is transcoding 4K H.265, I can see the VCS engine (Video Codec) running at 60-80% in intel_gpu_top — that’s the sign that hardware transcoding is doing the work instead of software.

Configuring Jellyfin to Use Hardware Transcoding

# Grant the jellyfin user access to /dev/dri
usermod -aG render,video jellyfin

# Verify the device
ls -la /dev/dri/
# crw-rw---- 1 root video   226, 0   card0
# crw-rw---- 1 root render  226, 128 renderD128

In the Jellyfin Admin Dashboard → Playback → Transcoding: select Intel QuickSync (QSV) and enable H.264, H.265, and VP9.

Common Errors and Fixes

“GVT-g is not enabled” — Run cat /proc/cmdline and check whether the i915.enable_gvt=1 parameter is present. If it’s missing, update-grub wasn’t run correctly.

VM Doesn’t Detect GPU After Boot — Try adding x-vga=1 to the hostpci line: hostpci0: 0000:00:02.0,mdev=UUID,x-vga=1. Some older CPU generations require this flag.

Jellyfin Still Transcoding in Software — Permissions are the culprit 9 times out of 10. Run journalctl -u jellyfin | grep dri to see the specific error, then run usermod -aG render jellyfin and restart the service.

After running this setup for several weeks, Jellyfin transcodes 4K H.265 on the VM using only ~15% CPU instead of 100% with software transcoding — and the entire cluster keeps running smoothly. It’s a great way to get more out of hardware you already have without spending anything on a discrete GPU.

Share: