Ubuntu Multi-monitor Setup

January 15, 2011

My current computing platform is a ThinkPad T61p running Ubuntu. I recently picked up a Mini Dock and a pair of 24" Samsung monitors. This post describes how I got the multi-monitor setup working.

The ThinkPad has an NVidia Quadro FX 570M GPU. Your best reference for configuring dual displays on Linux with NVidia GPUs is the NVidia Linux driver README

There are a number of ways to get multiple monitors working on an X server. I decided to use NVidia's proprietary TwinView approach. Under TwinView, X thinks there's one large display space, and the NVidia driver divides this up into multiple monitors.

The easiest way to get this working is to install the Ubuntu nvidia-settings package and fiddle with the GUI application it installs under the System > Administration menu. The problem is that there doesn't seem to be a way to clearly switch between two modes when I'm docked (the two external displays) or un-docked (the laptop's panel). Luckily, like most things in Linux, we can fix things up with a bit of scripting.

Building nv-control-dpy

The nv-control-dpy utility gives us the functionality we need to dynamically control our display configuration. This utility is actually just a sample program that NVidia distributes with the driver source to illustrate how to use their API. We can build nv-control-dpy from the the Ubuntu source package. The following instructions are based on a a post to the Ubuntu forums site, but have been tweaked to work on Ubuntu 10.10.

sudo apt-get install build-essential libxext-dev libx11-dev
cd
mkdir nvidia-source
cd nvidia-source/
apt-get source nvidia-settings
cd nvidia-settings-*/
cd src/libXNVCtrl
make
cd ../../samples
make

At this point I got a compile error when compiling nv-control-events.c.

nv-control-events.c:705: error: ‘NV_CTRL_FLATPANEL_DITHERING_MODE’ undeclared here (not in a function)

I didn't need this particular program; however, running make nv-control-dpy as suggested in the Ubuntu forums post didn't work either. The solution was to edit nv-control-events.c and comment out the offending line:

//MAKE_ENTRY(NV_CTRL_FLATPANEL_DITHERING_MODE),

Run make again, and you should find nv-control-dpy in the _out/Linux_x86_64 directory. I suggest you copy it /usr/local/bin.

Switching Display Modes

X detects the installed displays when it starts. This can be a challenge for laptop users whose display configuration changes depending on whether or not they're docked. The way I've handled this is to remove all TwinView-related settings from /etc/X11/xorg.conf (TwinView, MetaModes, etc.), and to set things up dynamically at runtime.

Suppose we've rebooted our laptop un-docked. X will be unaware of our external displays. We can remedy this by running nv-control-dpy --probe-dpys. On my system the output is as follows:

Using NV-CONTROL extension 1.24 on :0.0
Connected Display Devices:
  DFP-0 (0x00010000): LEN

Display Device Probed Information:

  number of GPUs: 1
  display devices on GPU-0 (Quadro FX 570M):
    CRT-0 (0x00000001): Samsung SyncMaster
    DFP-0 (0x00010000): LEN
    DFP-1 (0x00020000): Samsung SyncMaster

To the NVidia driver, DFP-0 refers to the laptops attached panel, while CRT-0 is the external monitor connected to the dock's VGA port and DFP-1 is the external monitor connected to the dock's DVI port.

Now that the driver sees the new displays, we have to "associate" them (I'm not exactly sure what that means, but we have to do it for things to work.) If you look at the output of nv-control-dpy --probe-dpys you'll notice that each display has an associated hexadecimal number. To associated multiple displays, you have to call nv-control-dpy --set-associated-dpys X, where X is the result of or-ing these numbers together. On my system the proper command is nv-control-dpy --set-associated-dpys 0x00030001.

Now we must create a "meta mode" that describes a configuration that incorporates the external displays. In my case, I want them displayed side-by-side, with the internal laptop display disabled. Here is the appropriate setting:

nv-control-dpy --add-metamode "DFP-0: NULL, CRT-0: nvidia-auto-select +0+0, DFP-1: nvidia-auto-select +1920+0"

Refer to the NVidia documentation for a full treatment of meta modes.

Finally, we use the xrandr utility to switch between configurations. xrandr is not directly aware of meta modes, but we can switch based on the fact that one of the configurations has a display resolution of 1920x1200 and the other a resolution of 3840x1200:

xrandr -s 3840x1200

Tying It All Together

I put the required commnds together in a shell script that toggles the display configuration:

#!/bin/sh
nv-control-dpy --probe-dpys
nv-control-dpy --set-associated-dpys 0x00030001
nv-control-dpy --add-metamode "DFP-0: NULL, CRT-0: nvidia-auto-select +0+0, DFP-1: nvidia-auto-select +1920+0"

if xrandr | grep 'current 1920'; then
    xrandr -s 3840x1200
else
    xrandr -s 1920x1200
fi

In Gnome, you can bind this to a keystroke by running System > Preferences > Keyboard Shortcuts. Click Add, and specify the shell script with a name and the full path to the script, and click Apply. Finally, bind the new shortcut to a key. (I used `Ctrl-Alt-```.)