Multihead and Compiz

Scope of this document

This document is mainly intended for developers or advanced users. It does not cover configuration of X for specific video cards or situations. It is meant to explain how Compiz deals with multihead, not how to set up X.

Two fundamentally different ways of doing multihead

Multihead is when more than one monitor, projector, TV, etc. (ie. head) is hooked up to the same computer.

There are two fundamentally different approaches to this in X:

Note that there are different implementations of bigscreen multihead. As far as Compiz is concerned, Xinerama, MergedFB, TwinView and XRandR are the same. XRandR does have a different way of getting information, but for plugins, all of these different approaches are transparent.

In the traditional multihead setup, each head provides one screen. For Compiz, this means one CompScreen each. They share the same display. For two heads, this would give us a DISPLAY variable :0.0 for the first screen, and :0.1 for the second. These heads are mostly independent of each other. This means that windows can't be moved between them, among other things. The main reason for using this setup is to be able to use multiple video cards. It is easier to provide several screens with the needed functionality (DRI, Composite, etc.) when you are using several video cards than it is to provide a single big screen. Another rather neat result is that you get one cube per head; these can rotate independently of each other.

What Compiz needs from X

Compiz supports both bigscreen multihead, and multiscreen. However, that does not mean it will work.

With nVidia, you should have no real problems. Just set up TwinView and you should be good to go. nVidia users can also use multiscreen, although it is not as polished driver-wise as TwinView.

ATI users might run into problems, as the open source drivers do not provide DRI on both screens in multihead.

Intel users using the i810 driver generally will not have problems; they will just need to make sure that each head is the same resolution. The new world (intel) driver with 7.3, with XRandR 1.2 support, should fix this.

Compiz needs a working AIGLX, Xgl or nVidia rendering path for all screens to work. Compiz also needs Composite working on all screens. Check for these in the X log if you are having trouble starting Compiz on multiscreen.

Code-related concerns

There isn't much to think about for most programmers when it comes to multiscreen. Just make sure you don't mix the CompDisplay and CompScreen data. Also, never use d->screens without cycling through it. On normal setups, d->screens refers to the one and only screen, but on multiscreen, it only refers to the first one. A rule of thumb is to pass the CompScreen somehow whenever you know the function will use it. It's safe to get CompDisplay from screen->display, but not vice versa.

The biggest challenge with multiscreen is knowing when to share what. If you're unsure, save on a per-screen basis. It might duplicate information in multiscreen, but at least it will work.

For multiscreen you also have to make sure the OpenGL context is correct before modifying textures. This can easily be done by passing makeScreenCurrent (s) before modifying a texture. All core functions that deals with textures do this.

Bigscreen, however, is slightly more complicated. With bigscreen, we only deal with one CompScreen, but the screen->outputDev comes into play. For instance, remember the difference between the monitor width and screen width. In addition to that, Compiz also sets up different CompOutput targets for drawing.

For each head in a bigscreen environment, the paintOutput() procs are called. They are called at the "bottom" of the paintScreen (), which is only called once per actual screen. The fullscreenOutput also makes things even more complicated, which is a special CompOutput which causes us to draw to the entire screen, not just one head.

The reason you have to deal with fullscreenOutput is the OpenGL viewport. Usually we draw each head by it self, and that's fine, but this means we move the OpenGL viewport for each draw, but we do not adjust the projection matrix. That means that if you zoom out to the same coordinates on two heads without s->fullscreenOutput, you will break the picture, because you are zooming two different images to the center of EACH output head. Using s->fullscreenOutput means that you draw "both" images as one, and therefore don't break them when you zoom them, because they are transformed as one.

You want to use fullscreenOutput whenever you are doing animations that affect the entire viewport, like cube rotations, expo and more.

It is always a good idea to give the user a few options in this area. A setup like this can be split over two identical monitors, or maybe one of them is a TV that is usually turned off.

Common pitfalls