How to Fix Broken Steam Linux Client With Radeon Graphics Driver (Workaround)

Short Version
If Steam gives out the error: “OpenGL GLX context is not using direct rendering, which may cause performance problems.” and you’re sure the graphics driver is loaded properly try the following script to run Steam:

#!/bin/bash
export LD_PRELOAD='/usr/$LIB/libstdc++.so.6' #Export so all child processes are affected as well
export DISPLAY=:0
#export LIBGL_DEBUG=verbose
steam

Long Version
In the past 6 months my livingroom PC is a Linux box with AMD graphics card. I could never get AMD’s binary driver (FGLRX) to work with Steam reliably but the open source Radeon driver is surprisingly good and keeps improving. The downside is that every so often Steam client updates break for weeks until another update fix it. After going through this several times I decided to actually figure out the root cause and fix it. Here’s a quick walkthrough on how to debug your Steam client setup and how to fix a common problem that may pop up with open source graphics driver.

Running steam from the command line gives out the venerable ‘GLX direct rendering’ error but there’s a hint in the lines before it:

Running Steam on ubuntu 14.10 64-bit
STEAM_RUNTIME is enabled automatically
Installing breakpad exception handler for appid(steam)/version(1420770381)
libGL error: unable to load driver: radeonsi_dri.so
libGL error: driver pointer missing
libGL error: failed to load driver: radeonsi
libGL error: unable to load driver: swrast_dri.so
libGL error: failed to load driver: swrast
Installing breakpad exception handler for appid(steam)/version(1420770381)

Steam can’t open radeonsi_dri.so, the shared library responsible for communicating with the graphics driver. To rule out a problem with the driver itself, let’s verify an OpenGL enabled graphics driver is loaded by running:
DISPLAY=:0 glxinfo | grep -i direct
The output should be:

direct rendering: Yes

Next, to debug Steam load run the Steam client from commandline in verbose mode:
DISPLAY=:0 LIBGL_DEBUG=verbose steam

And now the output is:
Running Steam on ubuntu 14.10 64-bit
STEAM_RUNTIME is enabled automatically
Installing breakpad exception handler for appid(steam)/version(1420770381)
libGL: screen 0 does not appear to be DRI3 capable
libGL: pci id for fd 7: 1002:6798, driver radeonsi
libGL: OpenDriver: trying /usr/lib/i386-linux-gnu/dri/tls/radeonsi_dri.so
libGL: OpenDriver: trying /usr/lib/i386-linux-gnu/dri/radeonsi_dri.so
libGL: dlopen /usr/lib/i386-linux-gnu/dri/radeonsi_dri.so failed (/home/user/.local/share/Steam/ubuntu12_32/steam-runtime/i386/usr/lib/i386-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by /usr/lib/i386-linux-gnu/dri/radeonsi_dri.so))
libGL: OpenDriver: trying ${ORIGIN}/dri/tls/radeonsi_dri.so
libGL: OpenDriver: trying ${ORIGIN}/dri/radeonsi_dri.so

The dlopen error tells us the file exist but there was an error with the LibC6 version the driver requires. Let’s check which LibC6 version is actually behind the libstdc++.so.6 that’s loaded:

~$ ls -l /home/user/.local/share/Steam/ubuntu12_32/steam-runtime/i386/usr/lib/i386-linux-gnu/libstdc++.so.6

lrwxrwxrwx 1 user user 19 Jul 19 00:52 /home/user/.local/share/Steam/ubuntu12_32/steam-runtime/i386/usr/lib/i386-linux-gnu/libstdc++.so.6 -> libstdc++.so.6.0.18

Let’s check what version is installed on the global /usr/lib path:
~$ ls -l /usr/lib/i386-linux-gnu/libstdc++.so.6

lrwxrwxrwx 1 root root 19 Oct 11 14:58 /usr/lib/i386-linux-gnu/libstdc++.so.6 -> libstdc++.so.6.0.20

So Steam loaded LibC6 with ABI version 18 where Radeonsi expects version 20.

Hold on for a second, why does this happen in the first place?

The answer is STEAM_RUNTIME. Steam for Linux packs a set of (standard) shared libraries called STEAM_RUNTIME. This allows the guys at Valve to optimize the client for specific dependencies without fearing the target machine will have different version. This is somewhat similar to static compilation where you compile the program’s dependencies in the main binary.

The problem is that Steam can’t come preloaded with ALL the libraries it needs and has to rely on the OS to supply some. This is exactly the case with radeonsi_dri.so. This library is in charge of the client’s OpenGL interface with the actual driver. Radeonsi also needs libstdc++ from LibC6 and gets updated independently every once in a while. Whenever an update changes the ABI, the global LibC6 and Steam’s gets out of sync.

So the only thing we need is to get Steam to load the newer version of the library.

Some forums advise you to remove Steam’s version of LibC6 by running:

rm /home/user/.local/share/Steam/ubuntu12_32/steam-runtime/i386/usr/lib/i386-linux-gnu/libstdc++.so.6

etc. This won’t work since Steam checks the integrity of its runtime and will fix the missing files on load.

A more elegant solution would be to have the proper LibC6 version loaded by the OS, by running:
LD_PRELOAD=/usr/lib/i386-linux-gnu/libstdc++.so.6 DISPLAY=:0 steam

This seems to work but puts out a lot of errors in the form of:
ERROR: ld.so: object '/usr/lib/i386-linux-gnu/libstdc++.so.6' from LD_PRELOAD cannot be preloaded (wrong ELF class: ELFCLASS32): ignored.

This error is an artifact of the fact Steam is a 32-bit binary running on a 64-bit machine. LibC6 has two versions (32-bit and 64-bit). The Steam binary needs the 32-bit version but other parts of the client run as native 64-bit and when they start they will get the LD_PRELOAD environment specifying a library with the wrong format. So how do we tell LD_PRELOAD to take the right one?

LD_PRELOAD='/usr/$LIB/libstdc++.so.6' DISPLAY=:0 steam

The somewhat non-intuitive $LIB parameter gets expanded in ld.so to the right path based on the platform of the process being started (man 8 ld.so for details).
The quotes around the environment are mandatory. It tells the shell not to try and expand the $LIB but rather pass it as is.

So finally Steam will load cleanly. A more permanent solution can be implemented in a loading script that checks if the global LibC6 version is newer than the one in STEAM_RUNTIME and only then LD_PRELOAD’s. I’ll leave this as an exercise to the reader.

Happy Linux beta gaming!

Advertisements

11 Comments

Filed under Uncategorized

11 responses to “How to Fix Broken Steam Linux Client With Radeon Graphics Driver (Workaround)

  1. Thanks for this. It got me one step closer to getting Steam games to work with the open source ATi drivers. However, Im still getting the following error when trying to launch a game (CIV5)

    ERROR: ld.so: object ‘/home/user/.local/share/Steam/ubuntu12_32/gameoverlayrenderer.so’ from LD_PRELOAD cannot be preloaded (wrong ELF class: ELFCLASS32): ignored.

    Any ideas?

    • Unfortunately seems like you’re right. This workaround doesn’t allow CIV5 to work. In the past I was actually able to run CIV5 quite a lot before the libc6 update.

      The root cause are the following errors seen when running CIV5:
      /home/user/.local/share/Steam/SteamApps/common/Sid Meier’s Civilization V/./Civ5XP: Symbol `_ZTVN10__cxxabiv120__si_class_type_infoE’ has different size in shared object, consider re-linking
      /home/user/.local/share/Steam/SteamApps/common/Sid Meier’s Civilization V/./Civ5XP: Symbol `_ZTVN10__cxxabiv117__class_type_infoE’ has different size in shared object, consider re-linking
      /home/user/.local/share/Steam/SteamApps/common/Sid Meier’s Civilization V/./Civ5XP: Symbol `_ZTVN10__cxxabiv121__vmi_class_type_infoE’ has different size in shared object, consider re-linking

      This is actually quite strange. libc6stdc++ has these symbols:
      nm -D /usr/lib/{i386,x86_64}-linux-gnu/libstdc++.so.6.0.20 | grep _ZTVN10__cxxabiv121__vmi_class_type_infoE
      shows:
      000ea220 V _ZTVN10__cxxabiv121__vmi_class_type_infoE
      00000000002f2180 V _ZTVN10__cxxabiv121__vmi_class_type_infoE

      To get more details I’ll need to disassemble and compare Steam’s version with Ubuntu’s. Meantime some other games seems to work nicely. Hopefully Valve will update Steam soon to the latest libstdc++.

  2. wallacoloo

    Thank you thank you! This is a *fantastic* fix. Of course, I didn’t find your post until after I had already uninstalled my graphics drivers to try to fix the steam issue (which had no effect, of course), and then I had to spend another 2 hours fighting through dependency hell to get them reinstalled and yet another hour to figure out why my driver wasn’t getting loaded. But nice work with the debugging, and great job with making the explanation easy to understand.

  3. it works great for me though why cant i open steam without using the terminal??

  4. That really helped me, thx!
    I have Steam now running on my KUbuntu Laptop

  5. Erm.. I might be a bit late… but this doesn’t work with games…
    I contacted Valve

  6. Platfus

    Hello, is there a way to put this script into an easy exetutable or make it so it will launch everytime PC starts? I want steam on my HTPC

  7. Sparksman

    I can confirm right now this bug is still alive with an freshly installed Ubuntu 15.10, used with the default Gallium driver [Gallium 0.4 on AMD CAPE VERDE (DRM 2.43.0, LLVM 3.6.2)] and an AMD Radeon HD 7750 graphics card.

    I got the exactly same error like described by you after installing the current steam deb from steam itself , and your workaround fixed the start nicely, right after running your script the steam client started with updating itself and opening the steam app without problem.

    Thanks a lot for your hint and the comprehensive informations about it!

    Yours

    Sparksman

    *bows till floor* 😉

  8. Nicholas

    This is an excellent writeup, a valuable benefit to a small corner of the internet. I already saw the answer (LD_PRELOAD=’/usr/$LIB/libstdc++.so.6′ DISPLAY=:0 steam) on another forum but I was wondering why, and you covered that from top to bottom. Kudos.

  9. Thank you so much! I really thought there was no way around this problem. My GPU is still rather crappy and many games are quite slow, but they _do_ work! Also, thanks for the great explanation.
    Btw, for me, making the symbolic links:

    * ~/.steam/ubuntu12_32/steam-runtime/amd64/usr/lib/x86_64-linux-gnu/libstdc++.so.6 -> /usr/lib/x86_64-linux-gnu/libstdc++.so.6
    * ~/.steam/ubuntu12_64/steam-runtime/i386/usr/lib/i386-linux-gnu/libstdc++.so.6 -> /usr/lib/i386-linux-gnu/libstdc++.so.6

    Did the trick, although, as you said, maybe after one update or some integrity check it will fail again.

  10. Thanks bro! Normally, the post about fixes in Gnu – Linux world are limited to a isolated command, that is a strange line of code. In this case you are using a good pedagogical and open method, thanks for that

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s