[[!meta title="How to use Xorg's wsfb display driver with a UEFI/BIOS framebuffer, and change its resolution"]] [[!toc levels=3]] Background ---------- [wsfb(4)](https://man.netbsd.org/wsfb.4) is the Xorg graphics driver for the NetBSD [wsdisplay(4)](https://man.netbsd.org/wsdisplay.4) framebuffer device. `wsdisplay(4)`, similar to Linux's `/dev/fb` devices, provide access to _non-accelerated_ framebuffers, which are provided by _almost all_ modern cards. Most, if not all, _modern_ graphics cards provide what's called a _linear_ framebuffer: a chunk of memory where contiguous address locations map onto adjacent (X, Y) _pixels_. For example, assuming a 32 bits-per-pixel colour depth display, memory location `fbmem + 0` will hold the pixel at position (0,0); `fbmem + 4` corresponds to the pixel at (1, 0), and so on. (We'll skip the complication known as `stride` or `line_length` here.) `wsdisplay(4)` can run on top of: 1. `genfb(4)`, the Generic PCI VGA framebuffer device (provided by UEFI or BIOS on x86), and other simple software framebuffers provided by hardware or firmware (e.g. simplefb on ARM) 2. the accelerated [`drm(4)`](https://man.netbsd.org/drm.4) graphics devices (in `/dev/dri/card?`--which `wsfb` will use as a plain framebuffer). Using `wsfb` ------------ ### Step 1: Configuring `Xorg` Use this `wsfb.conf` Xorg config fragment: ``` Section "Device" Identifier "Card0" Driver "wsfb" EndSection ``` That is all that is needed. Xorg will autoconfigure everything else. Make sure you dump the `wsfb.conf` file into the correct Xorg config. directory. `/etc/X11/xorg.conf.d/` is the correct location for the Xorg in base. If you've installed the `modular-xorg` package, then the path will need change. Use this command to find your `config directory`: ``` $ fgrep directory /var/log/Xorg.0.log [ 72.697] (==) Using config directory: "/usr/local/etc/X11/xorg.conf.d" [ 72.697] (==) Using system config directory "/usr/local/share/X11/xorg.conf.d" ``` If your DRM kernel driver has loaded OK and is active, then it will have configured your graphics card with the best resolution for your screen and you can just run `X` right away (this wil be X with `wsfb` on `drmkms`, minus the DRM-provided accelerations). You don't need Step 2. If you don't have a DRM driver, or if you can't load it, then if you start `X` now, you'll most probably get the bog-standard 1024x768x32 screen resolution provided by `genfb`, which might be OK, but, is not ideal. As the `wsfb`/`wsdisplay`/`genfb` combo. doesn't let you change resolutions on the fly (`xrandr`, for instance, doesn't work), we'll have to set a better resolution elsewhere: in the bootloader. ### Step 2: Setting a better display mode. Reboot, then at the bootloader menu, choose the option to get to the bootloader prompt. Here, on UEFI systems, we use the `gop` (Graphics Output Protocol) command like this: List available video modes first: ``` > gop list 0: 1366x768 BGRR pitch 1376 bpp 32 1: 640x480 BGRR pitch 640 bpp 32 *2: 800x600 BGRR pitch 800 bpp 32 3: 1024x768 BGRR pitch 1024 bpp 32 > ``` The `*` indicates the (safe) mode that the bootloader will use by default. Generally, if the UEFI/BIOS is working properly, it will have queried the monitor via EDID and populated the list of modes from that. On a 2019-era Dell with Intel UHD 630, it successfully detected 1680x1050, 1280x1024, and 1600x1200 over VGA (3 separate old monitors) and 2560x1440 over DisplayPort, and worked with all of them. Note that on one laptop, mode `0` has a pitch (aka stride) of 1376 pixels. This means that on this graphics card (Asus X202E laptop), the framebuffer is _linear_, but, **not** fully contiguous. The 10 unusable pixels at the end of each row have to taken into account, or else, you'll be treated to a characteristic jagged, streaky display. Choose the best mode, which is generally mode `0`: ``` > gop 0 > ``` The screen resolution will switch immediately. (And hopefully, your display won't go blank, which, these days, usually indicates a graphics card/BIOS/UEFI/whatever that doesn't implement the published standards correctly.) If you have/use BIOS instead of UEFI, you can try the `vesa` command instead of `gop`: ``` > vesa list ... > vesa 0xhhh > ``` If the mode you've chosen works, then you can add that `gop 0` or `vesa mode` command to `boot.cfg` so that it is activated automatically. This is not the default because if the UEFI/BIOS is buggy it is difficult to deal with. This is what `dmesg` will show, if you've disabled DRM (see below), or don't have it: ``` $ dmesg | fgrep genfb [ 1.015430] genfb0 at pci0 dev 2 function 0: vendor 8086 product 0166 (rev. 0x09) [ 1.015430] genfb0: framebuffer at 0xe0000000, size 1366x768, depth 32, stride 5504 [ 1.015430] genfb0: shadow framebuffer enabled, size 4128 KB [ 1.015430] wsdisplay0 at genfb0 kbdmux 1: console (default, vt100 emulation), using wskbd0 [ 1.015430] drm at genfb0 not configured ``` The resolution, depth and stride are all OK. And inside the Xorg server: ``` $ xdpyinfo | fgrep -B1 -A1 resolution dimensions: 1366x768 pixels (310x174 millimeters) resolution: 112x112 dots per inch depths (7): 24, 1, 4, 8, 15, 16, 32 $ xrandr xrandr: Failed to get size of gamma for output default Screen 0: minimum 1366 x 768, current 1366 x 768, maximum 1366 x 768 default connected 1366x768+0+0 0mm x 0mm 1366x768 0.00* $ ``` Limitations ----------- 1. No OpenGL hardware acceleration - on x86 and aarch64, llvmpipe (a parallel CPU-based just-in-time renderer) will be used instead 2. No X Display Power Management Signaling 3. No X video extension (used for accelerated video playback) 4. No DRI ## Extra: How to disable built-in DRM driver using kernel's `userconf` manager For testing, or if running `wsfb` on top of the DRM graphics driver does not work--it mostly should, actually). At the bootloader prompt, pass the `-c` flag to the kernel: ``` > boot -c ``` The kernel will display a few lines, then immediately drop into the `userconf` prompt: ``` uc> list # list all devs; look for your drmkms entry uc> disable i915drmkms # disable Intel DRM uc> quit ``` Once you've determined the device name using `userconf`, or, by trawling through the GENERIC kernel config file, you can disable the device using the bootloader like this: ``` > userconf disable i915drmkms ``` You can of course, add `userconf` commands also to `boot.conf`