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 IOMMUi915.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 instancesi915-GVTg_V5_2— 1GB VRAM, up to 3 instancesi915-GVTg_V5_4— 2GB VRAM, up to 1 instancei915-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.

