Multi-GPU systems
(If you just have monitors connected to a single graphics card, no need to be here)
Introduction
Consider the following setup:
You have 2 graphic cards (GPUs)
Each card is connected to 4 monitors
You want to build a video wall with 8 monitors
The two graphic cards are physically separate entities with their own resources, so it actually makes sense to keep them that way in the software side as well.
For creating such a separation, Linux offers a robust, well-tested and ancient (!) solution: multiple X-Screens.
Let’s state the example case graphically:
+----> monitor 1-1 |
| | X-Screen 0
GPU1 --+----> monitor 1-2 | Spanning four monitors
| |
+----> monitor 1-3 |
| |
+----> monitor 1-4 |
+----> monitor 2-1 |
| | X-Screen 1
GPU2 --+----> monitor 2-2 | Spanning four monitors
| |
+----> monitor 2-3 |
| |
+----> monitor 2-4 |
The advantage of this setup is, that the different GPUs don’t have to communicate or cross-over data between them. In OpenGL, they do not have to share contexes. The disadvantage is that one can’t move a program window from GPU1 to GPU2, just the mouse pointer.
On the contrary, if you form a “macro” desktop (with a single X-Screen), spanning all 8 monitors, prepare yourself for performance bottlenecks. A nice demo is to run “glxgears” and observe what happens to the framerate when you move the glxgears window from one GPU to another. For a deeper discussion on the subject, see for example this page.
Unfortunately, many Linux desktop environments (KDE for example) have deprecated their ability to handle several X-Screens: do check out this rather frustrating discussion thread / bug report on the subject.
Our approach
As you learned from the tutorials and from the PyQt testsuite, Valkka uses a dedicated thread (OpenGLThread) to pre-reserve resources from the GPU and to communicate with it.
In a multi-gpu case, one simply launches an OpenGLThread for each GPU: OpenGLThread takes as a parameter a string defining the connection to the X-server (e.g. “:0.0”, “:0.1”, .. “:0.n”, where n is the GPU number).
It is up to the API user to send the decoded frames to the correct OpenGLThread (and GPU). A simple example, where all decoded frames are sent to all GPUs in the system can be found in
valkka_examples/api_level_2/qt/
test_studio_3.py
Configuration
We’ve been succesful in setting up multi-gpu systems with the following setup:
Use identical Nvidia graphic cards
Use the NVidia proprietary driver
With the nvidia-settings applet, configure your system as follows:
Do not use Xinerama
Configure each graphic card as a separate X-screen
Use “relative” not “absolute” positioning of the screens and monitors
Use the Xcfe desktop/window manager instead of Kwin/KDE
Can be installed with sudo apt-get install xubuntu-desktop
Turn off window-manager composition: Settings Manager -> Window Manager Tweaks -> Compositor -> uncheck Enable Display Compositor
Use Pyside2 or PyQt5 version 5.11.2 or greater (you probably have to install with pip3 install)
Finally, test the configuration with the PyQt testsuite’s “test_studio_3.py”
Note on $DISPLAY
The environmental variable DISPLAY defines the “display” (aka X-server) and “screen” (logical screen that can span multiple monitors) with the following format
[host]:display[.screen]
where [] is something optional (see also in here).