Wednesday 16 January 2013

Optimus and Ubuntu 12.10 (Part 3)

This post is the third of a series of posts on tweaking Ubuntu 12.10 to exploit Optimus technology on my Lenovo W530 to the extent I need. Make sure you are familiar with the context, especially the objectives and constraints as described in Part 1 and Part 2.

My previous post on the topic describes how to control the power state of the DIS with vgaswitheroo that is part of the stock Ubuntu 12.10 kernel. It explains key terms related to X also shows alternative ways to use both the DIS and IGD within the same X server.

As the "single X server with 2 screens" approach is not an option until the related bugfix is available in the official repositories, I investigated how a second X server could be used to reach my goals. As a first step I analysed existing solutions in the area. Starting a second X server is core concept of Bumblebee, that enables rendering on the DIS, and then uses VisualGL to copy the content of individual windows back to the screen handled by the primary X server that uses the IGD only. Unfortunately, this project does not support external monitors in the case when ports are wired to DIS only. Also, it currently does not seem to be mature and stable enough for my production thinkpad. Nevertheless, it gave me a starting point...

Two X servers with one screen each

Starting a separate X instance to handle the DIS enables better isolation/sandboxing but also introduces additional issues.

  • First of all, the primary X instance has to be configured in a way that it will not grab any resources of the DIS, else the secondary instance fails to starts up with the message "No screens found".
  • Similarly, the second instance has to be configured explicitly to only use the DIS and related monitors.
  • I used configuration to override the actual connection status of the external VGA port and always enable VGA internally. Without an enabled monitor X would not start up.
  • The desktop cannot be extended to a monitor of the second X instance.
  • One could use a separate window manager on the second X instance - twm is very lightweight one. I stayed with a naked X for reasons described below.
  • With two X instances, I get a cursor on both displays. Without a pointing device, X would not start either. There are solution to use a mock input device, but anyway, having a two cursors that move in tandem on the two monitors is not critical. With my current configuration, the touchpad only controls the cursor on my primary X, while the trackpoint controls both.
  • Finally, the second X server will run as root, essentially with access control disabled so mortals can open windows on the second X as well.

$ cd ~
$ mkdir optimus && cd optimus
$ cat >>xorg.conf.nouveau<<EOF
Section "Modes"
 Identifier "FallbackModes" # Mode to use if External-VGA is diconnected
 Modeline "1024x768"   65.00  1024 1048 1184 1344  768 771 777 806 -hsync -vsync
EndSection

Section "ServerLayout"
 Identifier "Layout0"
 Screen "Screen0"
 Option "AutoAddDevices" "false"
 Option "AutoEnableDevices" "false"
 Option "AutoAddGPU" "false"
EndSection

Section "Monitor"
 Identifier "External-VGA"
 UseModes "FallbackModes"
 Option "Enable" "true" # always enabled
 Option "PreferredMode" "1024x768"
EndSection

Section "Monitor"
 Identifier "LCD"
 Option "Enable" "false" # always disabled
EndSection

Section "Device"
 Identifier "DIS"
 Driver "nouveau"
 BusID "PCI:1:0:0"
 Option "HWCursor" "true"
 # The numbers in output names change based on whether IGD or DIS is           
 # initialized first by the kernel. This tweak takes care of both cases.
 Option "Monitor-VGA-1" "External-VGA"
 Option "Monitor-VGA-2" "External-VGA"
 Option "Monitor-LVDS-1" "LCD"
 Option "Monitor-LVDS-2" "LCD"
EndSection

Section "Screen"
 Identifier "Screen0"
 Device "DIS"
 Monitor "External-VGA"
 DefaultDepth 24
 SubSection "Display"
  Depth 24
 EndSubSection
EndSection
EOF

$ cat >>xorg.conf.intel<<EOF
Section "ServerLayout"
   Identifier "Layout0"
   Screen "Screen0"
   Option "AutoAddDevices" "true"
   Option "AutoEnableDevices" "true"
   Option "AutoAddGPU" "false"
EndSection

Section "Device"
   Identifier "IGD"
   Driver "intel"
   BusID "PCI:0:2:0"
EndSection

Section "Screen"
   Identifier "Screen0"
   Device "IGD"
   DefaultDepth 24
   SubSection "Display"
      Depth 24
   EndSubSection
EndSection
EOF
$ sudo cp xorg.conf.intel /etc/X11/
$ sudo rm /etc/X11/xorg.conf # this is the link to the 2 screen config
$ sudo ln -s /etc/X11/xorg.conf.intel /etc/X11/xorg.conf
$ sudo lightdm restart

If there is no explicit default xorg configuration, then the X server will hold both /dev/dri/card[01] in which case the second X instance could not start up.

Starting, disabling and restoring external VGA output

I used the following small script to ensure DIS is powered on, spawn the X server, decorate it with a random background. After pressing Enter, X is terminated and DIS powered off.


#!/bin/bash

msg() {
 echo "******* $1"
}

msg "Ensuring DIS is powered on."
echo ON | sudo tee /sys/kernel/debug/vgaswitcheroo/switch
msg "Launching X server on display :1."
sudo /usr/bin/X -ac -audit 0 -config /home/tibi/optimus/xorg.conf.nouveau -sharevts -verbose 1 -logverbose 9 -logfile /tmp/Xorg.1.log -nolisten tcp -noreset :1 &

PID=$!
sleep 2
msg "PID is $PID, log goes to /tmp/Xorg.1.log."
# bonus: get a random background
BACKGROUND=$(find /home/tibi/Pictures -maxdepth 1 -name '*.jpg' | sort --random-sort | head -1)
msg "Setting background: $BACKGROUND"
gm display -window root -display :1.0 $BACKGROUND
msg "DONE."

msg "Press Enter to terminate and clean up."
read
msg "Terminating X server..."
sudo kill $PID
sleep 2
echo OFF | sudo tee /sys/kernel/debug/vgaswitcheroo/switch
msg "Discrete graphics device powered off."

I can safely disable and restore the external display without stopping the X server with the following commands:


### DISABLE
# numbers change across reboot, one of the two will work, other will print an error.
xrandr -d :1 --output VGA-1 --off
xrandr -d :1 --output VGA-2 --off
echo OFF | sudo tee /sys/kernel/debug/vgaswitcheroo/switch

### RESTORE
echo ON | sudo tee /sys/kernel/debug/vgaswitcheroo/switch
# numbers change across reboot, one of the two will work, other will print an error.
xrandr -d :1 --output VGA-1 --auto
xrandr -d :1 --output VGA-2 --auto

Usplash and plymouth issues

As it has been stated earlier, the issue around missing usplash/plymouth turned out to be connected to the random order in which the kernel initialized the graphics devices.


$ lspci | grep VGA
00:02.0 VGA compatible controller: Intel Corporation 3rd Gen Core processor Graphics Controller (rev 09)
01:00.0 VGA compatible controller: NVIDIA Corporation GK107 [Quadro K1000M] (rev a1)
$ # framebuffers - the order (0 and 1) changes randomly across reboots
$ cat /proc/fb
0 inteldrmfb
1 nouveaufb

Usplash is hardcoded to render to /dev/fb0 which is fine if the IGD is initialized first by the kernel, but not good if /dev/fb0 is associated with the DIS framebuffer. Kernel boot fbcon=map:1 is of no help in solving this issue. One workaround to mediate this problem is blacklisting nouveau, and loading it later, after usplash is started on the IGD framebuffer.


$ cat <<EOF | sudo tee /etc/modprobe.d/blacklist-nouveau.conf
# blacklist nouveau to force IGD framebuffer to take precedence
blacklist nouveau
EOF
$ sudo update-initramfs -c -k all

### and later during the boot process...

modprobe nouveau # we need modprobe as it was blacklisted during boot
udevadm settle # wait until all udev events are handled
echo OFF > /sys/kernel/debug/vgaswitcheroo/switch

This approach is rather a quick and dirty workaround. Technically, it would be enough - and much more elegant - to merely ensure the proper order of module loading by tinkering around with initram scripts; this is subject to further investigation.

About Part 4

Part 4 shows how this second naked X server can be used to achieve the objectives outlined in the previous post.

7 comments:

  1. Thank you for taking the time to right up this article series. It really is well presented.


    I did run into a problem, but I guess that has more to being specific to Debian.

    [158873.112982] thinkpad_acpi: EC reports that Thermal Table has changed
    [158873.224531] pci 0000:01:00.0: power state changed by ACPI to D3cold
    [159126.426229] ACPI Warning: \_SB_.PCI0.PEG_.VID_._DSM: Argument #4 type mismatch - Found [Integer], ACPI requires [Package] (20130517/nsarguments-95)
    [159126.426327] ACPI Warning: \_SB_.PCI0.PEG_.VID_._DSM: Argument #4 type mismatch - Found [Buffer], ACPI requires [Package] (20130517/nsarguments-95)
    [159126.426631] VGA switcheroo: detected Optimus DSM method \_SB_.PCI0.PEG_.VID_ handle
    [159126.426943] nouveau ![ DEVICE][0000:01:00.0] unknown Kepler chipset
    [159126.426946] nouveau E[ DEVICE][0000:01:00.0] unknown chipset, 0xffffffff
    [159126.426948] nouveau E[ DRM] failed to create 0x80000080, -22
    [159126.427087] nouveau: probe of 0000:01:00.0 failed with error -22
    [159152.891714] [drm] Module unloaded
    [159152.979012] wmi: Mapper unloaded
    [159156.376728] wmi: Mapper loaded
    [159156.382142] ACPI Warning: \_SB_.PCI0.PEG_.VID_._DSM: Argument #4 type mismatch - Found [Integer], ACPI requires [Package] (20130517/nsarguments-95)
    [159156.382254] ACPI Warning: \_SB_.PCI0.PEG_.VID_._DSM: Argument #4 type mismatch - Found [Buffer], ACPI requires [Package] (20130517/nsarguments-95)
    [159156.382628] VGA switcheroo: detected Optimus DSM method \_SB_.PCI0.PEG_.VID_ handle
    [159156.382963] nouveau ![ DEVICE][0000:01:00.0] unknown Kepler chipset
    [159156.382967] nouveau E[ DEVICE][0000:01:00.0] unknown chipset, 0xffffffff
    [159156.382969] nouveau E[ DRM] failed to create 0x80000080, -22
    [159156.383144] nouveau: probe of 0000:01:00.0 failed with error -22

    ReplyDelete
  2. What kernel are you on currently ???

    I think the issue is specific to newer kernels.

    ReplyDelete
    Replies
    1. I am currently running Linux 3.5.0-42-generic x86_64 GNU/Linux. Stock Ubuntu, not homebrew.
      I have plans to upgrade to 14.04 next year, and document how I get things running.

      Delete
    2. So, for other users reading this comment.....

      If you run into the following error:

      [159156.382963] nouveau ![ DEVICE][0000:01:00.0] unknown Kepler chipset
      [159156.382967] nouveau E[ DEVICE][0000:01:00.0] unknown chipset, 0xffffffff
      [159156.382969] nouveau E[ DRM] failed to create 0x80000080, -22
      [159156.383144] nouveau: probe of 0000:01:00.0 failed with error -22

      You may want to clean your machine off of bumblebee/bbswitch.

      My current problem now is to get the following resolved:

      (II) NOUVEAU driver Date: Wed Jul 31 10:51:03 2013 +1000
      (II) NOUVEAU driver for NVIDIA chipset families :
      RIVA TNT (NV04)
      RIVA TNT2 (NV05)
      GeForce 256 (NV10)
      GeForce 2 (NV11, NV15)
      GeForce 4MX (NV17, NV18)
      GeForce 3 (NV20)
      GeForce 4Ti (NV25, NV28)
      GeForce FX (NV3x)
      GeForce 6 (NV4x)
      GeForce 7 (G7x)
      GeForce 8 (G8x)
      GeForce GTX 200 (NVA0)
      GeForce GTX 400 (NVC0)
      (--) using VT number 7

      (EE) No devices detected.
      (EE)

      From the log, it looks like I need a newer nouveau X driver. Will keep you posted.

      Thank you again for writing this up.

      Delete
  3. So I made some more progress... Now I can get the device detected. But I get the following error:


    Snippets from the Xorg log.

    [ 1006.057] (II) NOUVEAU(0): Printing probed modes for output VGA-2
    [ 1006.057] (II) NOUVEAU(0): Modeline "1024x768"x60.0 65.00 1024 1048 1184 1344 768 771 777 806 -

    ....

    [ 1006.184] (II) NOUVEAU(0): EDID for output DP-1
    [ 1006.312] (II) NOUVEAU(0): EDID for output DP-2
    [ 1006.440] (II) NOUVEAU(0): EDID for output DP-3
    [ 1006.440] (II) NOUVEAU(0): Output LVDS-2 disconnected
    [ 1006.440] (II) NOUVEAU(0): Output VGA-2 enabled by config file
    [ 1006.440] (II) NOUVEAU(0): Output DP-1 disconnected
    [ 1006.440] (II) NOUVEAU(0): Output DP-2 disconnected
    [ 1006.440] (II) NOUVEAU(0): Output DP-3 disconnected
    [ 1006.440] (II) NOUVEAU(0): Using user preference for initial modes
    [ 1006.440] (II) NOUVEAU(0): Output VGA-2 using initial mode 1024x768
    [ 1006.440] (II) NOUVEAU(0): Using default gamma of (1.0, 1.0, 1.0) unless otherwise stated.
    [ 1006.440] (--) NOUVEAU(0): Virtual size is 1024x768 (pitch 0)
    [ 1006.440] (**) NOUVEAU(0): Mode "1024x768": 65.0 MHz (scaled from 0.0 MHz), 48.4 kHz, 60.0 Hz
    [ 1006.440] (II) NOUVEAU(0): Modeline "1024x768"x60.0 65.00 1024 1048 1184 1344 768 771 777 806 -hsync -vsync (48.4 kHz UP)
    [ 1006.440] (==) NOUVEAU(0): DPI set to (96, 96)

    ......

    [ 1006.444] (II) NOUVEAU(0): Opened GPU channel 0
    [ 1006.445] (II) NOUVEAU(0): [DRI2] Setup complete
    [ 1006.445] (II) NOUVEAU(0): [DRI2] DRI driver: nouveau
    [ 1006.445] (II) NOUVEAU(0): [DRI2] VDPAU driver: nouveau
    [ 1006.446] (II) EXA(0): Driver allocated offscreen pixmaps
    [ 1006.446] (II) EXA(0): Driver registered support for the following operations:
    [ 1006.446] (II) Solid
    [ 1006.446] (II) Copy
    [ 1006.446] (II) Composite (RENDER acceleration)
    [ 1006.446] (II) UploadToScreen
    [ 1006.446] (II) DownloadFromScreen
    [ 1006.446] (==) NOUVEAU(0): Backing store disabled
    [ 1006.446] (==) NOUVEAU(0): Silken mouse enabled
    [ 1006.446] (II) NOUVEAU(0): [XvMC] Associated with Nouveau GeForce 8/9 Textured Video.
    [ 1006.446] (II) NOUVEAU(0): [XvMC] Extension initialized.
    [ 1006.446] (==) NOUVEAU(0): DPMS enabled
    [ 1006.446] (II) NOUVEAU(0): RandR 1.2 enabled, ignore the following RandR disabled message.
    [ 1006.446] (WW) NOUVEAU(0): Option "Monitor-VGA-1" is not used
    [ 1006.446] (WW) NOUVEAU(0): Option "Monitor-LVDS-1" is not used
    [ 1006.446] (WW) NOUVEAU(0): Option "Enable" is not used
    [ 1006.446] (WW) NOUVEAU(0): Option "PreferredMode" is not used

    .......


    (II) GLX: Initialized DRI2 GL provider for screen 0
    (II) NOUVEAU(0): NVEnterVT is called.
    (EE) NOUVEAU(0): failed to set mode: Invalid argument
    (EE)
    Fatal server error:
    (EE) failed to create screen resources(EE)
    (EE)
    Please consult the The X.Org Foundation support
    at http://wiki.x.org
    for help.
    (EE) Please also check the log file at "/tmp/Xorg.1.log" for additional information.
    (EE)
    (II) AIGLX: Suspending AIGLX clients for VT switch
    (II) NOUVEAU(0): NVLeaveVT is called.
    (EE) Server terminated with error (1). Closing log file.

    ReplyDelete
  4. Just wanted to share my delight that finally on the new xserver (1.15) and kernel 3.12, I was able to get it all working with nouveau. Now I just need to follow your workflow for re-utilizing this xserver for my current display.

    ReplyDelete
    Replies
    1. Glad to hear you were able to progress. There has been a lot of recent development in both the kernel and xserver especially around switching between devices. As far as I know, some hacks are still needed to get the external displayport/DVI/VGA work properly (with 530 at least, due to wiring). I will upgrade my OS to 14.04 and document the process. Much of the workarounds here should not be needed any more.

      Delete