FBDev (Outputting graphics via frame buffer device)

FBDev (FrameBuffer Device) is a Linux kernel module that provides a simple interface for displaying images on a screen without a graphics server. It works directly with video memory through a linear buffer, where each pixel is defined by a numeric value.

FBDev is used in embedded systems (routers, car panels), during boot (kernel splash screen, Plymouth), and in console graphics applications such as retro console emulators or simple media players. It is often used as a backend for SDL1, DirectFB, or Qt libraries on systems without X11 or Wayland.

Typical problems

Lack of hardware acceleration causes high CPU load and low frame rates for complex graphics. FBDev does not support runtime resolution switching, overlays, or screen rotation without recompiling the kernel. Conflicts with GPU drivers that take over buffer management after loading are also possible.

How it works

The principle is based on mapping video memory into the user process address space via mmap after opening the /dev/fb0 device. The application writes a pixel array into this region, and the display controller automatically sends it to the screen at the refresh rate. For double buffering, FBIO_WAITFORVSYNC operations or page flipping are used. Unlike DRM/KMS (Direct Rendering Manager / Kernel Mode Setting), FBDev does not provide monitor mode control, vertical sync without blocking calls, or render scheduling from multiple applications. DRM/KMS is a more modern and feature-rich replacement that allows safe resolution switching and GPU usage. However, FBDev remains popular in minimalist systems (e.g., BusyBox) due to its extreme simplicity and lack of userspace library dependencies.

FBDev functionality

  1. Graphics server via FBDev. FBDev (FrameBuffer Device) provides an interface between a user application and the Linux kernel frame buffer. It allows direct pixel drawing without X11 or Wayland. It uses standard system calls open, read, write, ioctl, and mmap to manage video memory.
  2. Device access. The application opens the device file /dev/fb0 or subsequent numbers. The O_RDWR flag is required for read and write operations. Lack of permissions returns an EACCES error. Multiple processes can open the same device, but synchronization tasks fall on the developer.
  3. Fixed screen information. Calling ioctl with the FBIOGET_FSCREENINFO request returns struct fb_fix_screeninfo. It contains the scanline length (line_length), physical memory address (smem_start), and its size (smem_len). The fields type, visual, and accel define device hardware specifics.
  4. Variable screen information. The FBIOGET_VSCREENINFO request fills struct fb_var_screeninfo. It sets resolution (xres, yres), color depth (bits_per_pixel), and pixel clock (pixel_clock). Additionally includes red, green, and blue channel masks (red, green, blue). Parameters can be changed via FBIOPUT_VSCREENINFO.
  5. Mapping video memory. Use mmap with MAP_SHARED and the device file descriptor. The mapping length is smem_len from fix_screeninfo. The pointer is passed to the application for direct pixel writing. PROT_READ and PROT_WRITE flags are mandatory. An mmap error results in denied buffer access.
  6. Pixel formats. FBDev supports RGB, BGR, indexed colors, and grayscale. The visual field defines the type: FB_VISUAL_TRUECOLOR for direct RGB, FB_VISUAL_PSEUDOCOLOR for palette. Parsing bit masks requires analyzing var.red, green, blue for color assembly.
  7. Double buffering. Use two virtual screens via the yres_virtual parameter. Set xres_virtual = xres, yres_virtual = yres * 2. Switch the visible screen via ioctl FBIOPAN_DISPLAY by changing yoffset. Ensures seamless tear-free animation.
  8. Waiting for vertical sync. To prevent tearing, use ioctl FBIO_WAITFORVSYNC. Blocks the call until vertical blanking occurs. Available only if the driver supports the FBINFO_HWACCEL_VSYNC flag. Necessary for smooth video and games.
  9. Setting hardware palette. For pseudocolor modes, use the FBIOPUTCMAP request with struct fb_cmap. Pass an array of 256 values for red, green, blue (16 bits per channel). The kernel loads the palette into the hardware LUT. FBIOGETCMAP reads current values.
  10. Changing resolution on the fly. Call FBIOPUT_VSCREENINFO after modifying struct fb_var_screeninfo. The kernel attempts to reconfigure the display. On failure, returns EINVAL. Check the activated fields via FBIOGET_VSCREENINFO — the driver may adjust invalid values.
  11. Backlight and contrast control. Some drivers export sysfs files in /sys/class/backlight. FBDev does not directly control backlight. However, nonstandard ioctl commands may exist for specific chipsets. For portability, use the backlight API on top of FBDev.
  12. Screen rotation. The FBIO_ROTATE flag is defined in some drivers as a nonstandard ioctl. Supports 90, 180, 270 degree rotation via hardware block or kernel-side recalculation. Software rotation is easier to implement in userspace for consistency.
  13. Handling device failures. When an external monitor is disconnected or the video mode switches, the application receives a SIGBUS when accessing the mmap region. Catching the signal allows proper device closure. After reconnection, reopening /dev/fb0 again gives access to the new buffer.
  14. Working with overlay planes. The driver may provide multiple frame buffers /dev/fb0, /dev/fb1. The main buffer is switched via ioctl FBIOPAN_DISPLAY specifying fb_id. Some GPUs support hardware cursors via special ioctls, but the FBDev standard does not define this.
  15. Memory caching and barriers. Video memory mapped via mmap may be cacheable or uncacheable depending on the MAP_NOCACHE flag (nonstandard). For strict write ordering, use instructions like wmb() in the kernel or msync in userspace with the MS_SYNC flag.
  16. Performance at different bit depths. Bits_per_pixel = 32 mode gives maximum byte-addressable access without alignment but requires more bandwidth. 16-bit mode accelerates operations on ARM but reduces color fidelity. The choice affects fill rate and alpha blending.
  17. Competition with DRM driver. FBDev is considered legacy and does not support modern features like atomic commits and GPU job schedulers. DRM with fbcon works through emulation. For embedded systems, FBDev remains a simple solution without complex abstractions.
  18. Getting hotplug events. FBDev does not generate uevents through the device file. You must monitor changes in /dev via inotify or netlink. When /dev/fb1 appears, buffers need reconfiguration. Some applications reopen /dev/fb0 on I/O errors.
  19. Buffered I/O via write. When using write instead of mmap, use lseek and write for individual lines. This is slower due to syscall copying. Suitable for small changes or static images. Mmap remains the preferred method for real-time rendering.
  20. Limitations and alternatives. FBDev does not support hardware 3D acceleration, multi-layer composition, or advanced color spaces (HDR). On modern systems, the replacement is libdrm with KMS. FBDev is only useful for minimalist graphics environments, bootloaders, and diagnostic utilities.

Comparison of FBDev with similar features

  • FBDev vs DRM (Direct Rendering Manager). FBDev works at the framebuffer level, providing basic graphics output without hardware acceleration, while DRM manages the GPU and allows 3D acceleration via KMS. DRM is preferred for modern systems requiring complex scene rendering, whereas FBDev remains a simple solution for embedded devices.
  • FBDev vs Wayland. FBDev is a low-level frame output driver not tied to any windowing system, while Wayland is a full compositing protocol running on top of DRM. Wayland provides smooth graphics, security, and support for modern interfaces, whereas FBDev lacks compositing and input handling.
  • FBDev vs VESA BIOS (VBE). VESA BIOS is a firmware-level video mode standard available in real-mode CPU operation, while FBDev is a Linux kernel driver for linear video memory access. VESA is generally slower and does not work from protected mode, whereas FBDev provides a controlled kernel interface.
  • VBE (Abstraction of graphics hardware via interrupt 10h)
  • FBDev vs DirectFB. DirectFB is built on top of FBDev, adding hardware acceleration for blitting, scaling, and overlays. FBDev without DirectFB only offers minimal frame buffer access without optimizations. However, DirectFB is obsolete and unmaintained, while FBDev remains a standard part of the Linux kernel.
  • FBDev vs UEFI Graphics Output Protocol (GOP). GOP works during UEFI boot, providing a basic framebuffer before the OS starts. FBDev is activated by the Linux kernel and fully manages the video mode after boot. GOP is useful for bootloaders and early initialization, but FBDev ensures long-term stability and compatibility in a running system.

Driver support

FBDev is implemented in the Linux kernel as a direct video memory access subsystem through the /dev/fb* interface. It is supported in FreeBSD and NetBSD via the analogous wscons and configured using fbset. Drivers for various GPUs (e.g. vesafb, efifb, simplefb) register an fb_info structure, providing a unified set of operations fb_ops (fb_setcolreg, fb_fillrect, fb_copyarea) initialized during kernel boot.

Security

FBDev does not support hardware process isolation. Any user with access to /dev/fb0 can read and modify screen contents (including passwords from other applications). The kernel only checks access rights through a standard devnode with mode=0600. To prevent attacks, DRM with fbdev emulation is used, or mandatory use of mmap with PROT_READ|PROT_WRITE without per-process page restrictions.

Logging

In the kernel, FBDev logging is implemented via printk (KERN_INFO, KERN_ERR levels) in drivers/video/fbdev/core/fbcon.c and fbmem.c, which log framebuffer open/close events, video mode changes (FBIOPUT_VSCREENINFO), and mmap or DMA errors. User applications receive debug data only through dmesg, without a separate syslog socket within FBDev itself.

Limitations

FBDev operates in a single owner process mode (fb_open prevents further open without O_EXCL unless FB_ACTIVATE_NOW is set). It does not support hardware acceleration (all fb_ops operations are software-based, via CPU). Color modes are limited to an 8bpp palette or direct RGB at 16/24/32bpp. There is no control for multi-layer overlays or VSync. Virtual console switching requires the kernel VT subsystem and is not controlled from userspace.

History and development

FBDev was developed in 1998–1999 for Linux 2.2 (Geert Uytterhoeven, Martin Schwidefsky) as a simple API for embedded systems and consoles. During the XFree86 3.x era, it was superseded by DRM/KMS (starting with Linux 2.6.29). In modern systems, it persists as a DRM fbdev emulation layer for compatibility and early boot, but on new ARM platforms it is being replaced by simple-framebuffer or drm_panic.