Autoconf in a RandR World

Thu, 16 Nov 2006 22:32:14 -0800

While busily rewriting the RandR extension and the Intel driver to match, we decided to tackle another major issue, what to do when the driver isn't given any instruction in the config file about how to light up the screens. And, beyond that, how to make that configurable in reasonable ways while making it driver-independent.

The current scheme is a mish-mash of crufty ancient code and magic driver-specific hacks. The ancient driver-independent code doesn't understand that a single video card can have multiple monitors, so the normal configuration mechanisms are mostly harmful. For the Intel driver, the mode that you specify in the configuration file is almost, but not entirely, ignored.

In the bad old days of BIOS-based mode selection, it would just use the specified mode to try and match some mode present in the BIOS. In the brave new world of native mode setting, we can at least use the mode provided directly, assuming the output is capable of using it. In either case, all screens were programmed with the same mode (more or less). Not very useful when you have a 1024x768 internal panel and a 1600x1200 external monitor.

Almost all of the i830 and later Intel chips have two "pipes". Each pipe can be connected to a variety of "outputs" (where an output is effectively a connector, like a local LCD panel, or an external VGA connector). The "pipes" are important here because it takes a pipe to hold a specific mode, the pipe fetches data from the frame buffer and sends it to the outputs with the timing specified by the mode.

Now, the weird thing is you can sometimes connect multiple outputs to a single pipe. But, when you do that, each output gets exactly the same mode and sees exactly the same pixels out of the frame buffer. Plus, there are other restrictions, like you can't share a pipe with the local LCD panel or the TV output on the 945. Whatever. We mostly ignore this at present because it's not that useful, and it's a pain to think about. Of course RandR supports it and will expose it to the user when it can work, but that's not often.

Ok, with that brief diversion into the oddities of the Intel graphics chip, let's get back to configuration.

To allow the user to customize how modes were set, there were three parameters in the config file:

Option  "Clone"     "yes"
Option  "CloneRefresh"  "60"
Option  "MonitorLayout" "LFP,CRT"

The "Clone" option directed the driver to turn on two of the outputs. The "CloneRefresh" option specified the vertical sync rate for the "other" monitor. "MonitorLayout" gave the user precise control over which outputs are connected to which pipes.

The current BIOS-based driver on the master branch adds a bunch more:

Option  "MergeFB"   "yes"
Option  "MetaModes" "1024x768"
Option  "SecondHSync"   "80-130"
Option  "SecondVRefresh "50-75"
Option  "SecondPosition "RightOf"
Option  "MergedXinerama" "yes"

As you might guess, these all combine to let you place the second monitor somewhere other than right on top of the first monitor. Useful when you have two monitors on your desktop.

To confuse you further, the Radeon driver uses a different set of options to perform exactly the same function. Cool, huh? Even more fun is that these two drivers have completely different semantics of how to interpret the lack of these options. Makes building a configuration tool fairly challenging, and makes the chances that the user will get "random" results high.

So, the first thing to realize is that RandR 1.2 makes all of these things entirely configurable. But, not until you have the server running and can connect and X client. Bummer. With that, you'd have to put the desired configuration into a startup utility and you'd watch the screen flash a couple of times as you were logging in. Fun for some, but annoying for most.

Given that RandR has sufficient power to configure things after the server has started, and that this is expressed in a driver-independent fashion, it seems sensible to figure out how to use that information at startup time to make better choices and ease customization.

The first piece I've done is to replace the existing default mode selection logic with something a bit fancier and (I hope) more generally useful. After that, I'll write up some replacement configuration options and use those to mutate this configuration.

For the initial default configuration (used when no options are present in the configuration file), I made some simplifying assumptions:

Just start up in clone mode. Every display showing the same picture.

Monitors that have preferred modes should use them if possible

96dpi is what Microsoft uses; pick a mode close to that if possible

Give every monitor a similar size.

Given that I wanted to present the same data on every monitor, I started by picking a single monitor to control the size of the screen. For this, the code first looks for a monitor with a preferred mode; those are usually either the laptop LCD panel or an external DVI-connected LCD monitor. If no such monitor is present, the code picks a random monitor and selects a mode that will present data at about 96dpi. I think this makes more sense than picking the highest supported resolution as CRTs often advertise support for incredibly high resolutions that end up fuzzy and dim. Better to just pick a reasonable size by default and let the user change it after login.

Once the first mode is selected, all of the other monitors are set to modes that are close to that size.

Finally, the list of monitors is used to compute the maximum screen size that should be permitted. Yes, we're still stuck with allocating the frame buffer at server init time. This will, eventually, go away, but that's related to rendering infrastructure which we're ignoring this week. In any case, the maximum size is computed by figuring out how much space is needed to place all of the known monitors side-by-side. For outputs which don't have any monitor connected, we just pretend that they'll max out at 1600x1200. The end result is that there shouldn't be any limits on which mode combinations can be used in clone or mergefb mode.

Right now, all of this code is down inside the Intel driver. I will pull the DIX-level functions up to the RandR code. What remains is to decide how to make the remaining code driver independent and (eventually) move it to the xf86 common layer where it can be shared across multiple drivers.

All of this work is available on the modesetting branch of the Intel driver when built against the randr-1.2-for-server-1.2 branch of the X server.