Remote Off-Screen Rendering with OpenGL

Shehzan ArrayFire, OpenGL 18 Comments

At ArrayFire, we constantly encounter projects that require OpenGL and run on a remote server that does not have a display.
In this blog, we have compiled a list of steps that users can use to run full profile OpenGL applications over SSH on remote systems without a display.

A few notes before we get started.

  • This blog is limited to computers running distributions of Linux.
  • The first part of the blog that shows the configuration of the xorg.conf file is limited to NVIDIA cards (with display).
  • AMD cards support this capability without the modification of xorg.conf file. However, we have not been able to get a comprehensive list of supported devices.

Requirements

You will need access to the remote system over SSH.
To run the tool, you will need libGL.so and libX11.so. Another tool I would recommend strongly is glewinfo. Most linux distributions ship this with the glew-utils package. An alternate to glewinfo is glxinfo which is present on all systems with X. You can substitute glewinfo with glxinfo in all the commands below if needed.

Configuring X (NVIDIA Only)

To get X to running on NVIDIA cards, we need to make changes to the xorg.conf file. Before making the change, make sure you create a back up of the current version on your system (name it xorg.conf.stable).
You can find a sample xorg.conf file here. The sample file is for a NVIDIA GTX 690. The specific things to notice are the use of "UseDisplayDevice" option under "Screen" and the "Virtual" option under "SubSection Display". You can use parts of this file to configure your own config file. Make sure the options listed in the sample file get listed in your config file as well.
Save and close the file.

Now run this command: # nvidia-xconfig -a --use-display-device=None --virtual=1280x1024
Restart the system.

Note: To abort trying this, just copy xorg.conf.stable back to xorg.conf and restart.

The following is only for GeForce cards. Quadro and Tesla cards can skip to Initial Diagnosis section.

On restart, run the command # /usr/bin/X :0 &. Ideally, this command should give an output similar to:

This means X has started successfully on the virtual display.
If it fails, restart the system and try again. You can also look at /var/log/Xorg.0.log for the log of the failure.

Update: Known issue with Starting X

If the output is not similar to the one shown above, run the Initial Diagnosis section below. If the output shows an error as follows:

run the following commands:

Where XXX.YY is the NVIDIA driver version.

Now try starting X again.

Initial Diagnosis

Once X has started successfully, run echo $DISPLAY. It is very likely that the output of this will be empty.
If you have glewinfo installed, run the following command env DISPLAY=:0 glewinfo | less.
The goal of this command is to run glewinfo having temporarily set DISPLAY to :0 (virtual display on remote system). If this command runs successfully, you should be able to see the graphics card on the remote system along with the full OpenGL profile. And now you are ready to deploy applications using X.

If you want to set DISPLAY for the entire session, run export DISPLAY=:0. To set DISPLAY permanently, add the same line to your bashrc file.

Deploying Off-Screen Rendering Applications on Remote System

This is where X becomes crucial. Tools like GLFW may or may not work on remote systems because of their dependence on Xrandr and other software. The trick is use X to create an OpenGL context, and the run everything using off-screen rendering using framebuffers and renderbuffers. I took the source to create an OpenGL context using X from and modified it slighly. Thanks to the folks at OpenGL.org for providing this. The source code with the changes I made can be found here: glContext.hpp.

Include this in your source code. To create context and delete contexts run createGLContext() and deleteGLContext() respectively.

I have specified that the minimum OpenGL version should be 4.4 with forward context enabled. You can modify this version by changing the values at lines 26 and 27 of glContext.hpp.
The forward compatibility can be disabled at line 241 by changing line 241 to None.
If the application fails to create the specified version of the context, the application will exit.

At line 189, we create the window. The API description can be found here. "0, 0, 10, 10" specifies the top-left corner (0,0) and the width and height of the window (10, 10). Since the goal of this is to be used for off-screen rendering, the size of the window has no effect on the rendering.
Line 202 specifies the window title.

If everything goes successfully, you should see an output like this:

If you wish to use a lower minimum version, say 3.0, then the version provided by the output will reflect 3.0 since GL fetches version from the context.

To test the context creation as a stand alone, create a cpp file with the following contents (glContext.cpp):

Compile this with g++ -o gl glContext.cpp -lGL -lX11 and run with ./gl (make sure DISPLAY is :0). If this works successfully, any off-screen rendering code will work perfectly with this.
Note: If you use GLEW, make sure you include glew.h before including gl.h.

If you wish to know about remote OpenGL further or work with us on remote rendering, contact us at technical@arrayfire.com.

Links:
OpenGL Context Creation Tutorial
ArrayFire glContext repo on Github

Facebooktwittergoogle_plusredditlinkedinmail