There is very little by the way of official documentation regarding how to use multiple GPUs on Linux.
What you see everywhere is "set DRI_PRIME=1 in your environment to use your discrete GPU". Optimus is the closest thing I've found to upstream documentation; this applies to non-NVIDIA GPUs even though it's only mentioned on the Nouveau project's wiki. But what does 1 actually mean? DRI_PRIME=2 doesn't seem to work, so what if you have more than two GPUs? And what if you want a stable GPU identifier rather than relying on enumeration order?
As far as I'm aware this is completely undocumented, but some tools hint that DRI_PRIME can be set to a string identifying a PCI device which can be used as a stable identifier:
$ switcherooctl list Device: 0 Name: IntelĀ® HD Graphics 620 Default: yes Environment: DRI_PRIME=pci-0000_00_0s_0
This tool tells you the value of DRI_PRIME for each enumerated GPU.
How does it enumerate devices? Going back to switcheroo-control, it basically asks udev for all drm subsystem devices, filters for devices starting with /dev/dri/render and then looks at the ID_PATH_TAG property of the device. For instance:
$ udevadm info -q property /sys/class/drm/renderD128 | grep ^ID_PATH_TAG= ID_PATH_TAG=pci-0000_00_02_0
Now, let's look for code that consumes the DRI_PRIME environment variable. I ended up looking at the Mesa 3D Graphics Library.
get_default_device in the VkLayer_MESA_device_select shared library consults DRI_PRIME, among other things.
It also consults MESA_VK_DEVICE_SELECT, which can be set to the special value list to enumerate GPUs:
$ MESA_VK_DEVICE_SELECT=list vulkaninfo selectable deviecs: GPU 0: 8086:5916 "Intel(R) HD Graphics 620 (KBL GT2)" integrated GPU 0000:02.0 GPU 1: 100005:0 "llvmpipe (LLVM 11.0.1, 256 bits)" CPU 0000:00:00.0
According to the code, MESA_VK_DEVICE_SELECT=10005:0 will use my emulated llvmpipe GPU instead of the default Intel GPU.
This overrides any value of DRI_PRIME.
According to Phoronix, this was all added in Mesa 20.1.
loader_get_user_preferred_fd in the loader static library consults DRI_PRIME.
DRI2Connect of the GL shared library consults DRI_PRIME.