Linux Framebuffer

The Linux framebuffer (fbdev) driver renders LVGL into /dev/fb through the kernel's framebuffer interface, with no libraries and no display server required.

Edit on GitHub

Overview

The Linux framebuffer (fbdev) is a kernel subsystem that exposes a video framebuffer to user space through a device file, typically /dev/fb0. It is hardware-independent and needs no user-space graphics libraries at all, which makes this the simplest way to put LVGL on a screen: open the device, write pixels.

That simplicity is also its limit. fbdev has no modesetting, no GPU path and no page-flip guarantees. It is the right choice for minimal systems and for kernels that expose nothing else; on anything modern prefer DRM/KMS, which supersedes fbdev and can reach the GPU.

Prerequisites

A framebuffer device, usually /dev/fb0, and permission to open it.

Configuration

Enable LV_USE_LINUX_FBDEV.

Options

SymbolDefaultEffect
LV_LINUX_FBDEV_RENDER_MODELV_DISPLAY_RENDER_MODE_PARTIALRender mode; see below.
LV_LINUX_FBDEV_BUFFER_COUNT11 or 2 screen-sized buffers, or 0 for a custom-sized partial buffer.
LV_LINUX_FBDEV_BUFFER_SIZE60Height in rows of the partial buffer. Only used when the buffer count is 0.
LV_LINUX_FBDEV_MMAPonAccess the framebuffer via mmap() instead of write() calls.
LV_LINUX_FBDEV_BSDoffUse the BSD flavour of the framebuffer device.

LV_LINUX_FBDEV_RENDER_MODE accepts LV_DISPLAY_RENDER_MODE_PARTIAL, LV_DISPLAY_RENDER_MODE_DIRECT or LV_DISPLAY_RENDER_MODE_FULL.

The buffer count and the render mode constrain each other: two screen-sized buffers require a non-partial render mode, and a custom-sized buffer requires the partial one.

Usage

LVGL's linux port can be used to quickly get started with LVGL's FBDEV backend.

Create the display with lv_linux_fbdev_create, then point it at a device node with lv_linux_fbdev_set_file.

 
lv_display_t * disp = lv_linux_fbdev_create();
lv_linux_fbdev_set_file(disp, "/dev/fb0");

The resolution and color format come from the device, the driver reads them from the framebuffer's ioctl info, so there is nothing to configure.

If the screen stays black or draws partially

Try LV_DISPLAY_RENDER_MODE_DIRECT first. If that does not help, force a refresh of the whole screen on every flush with lv_linux_fbdev_set_force_refresh. This costs performance, so only enable it when it is genuinely needed.

Hide the blinking cursor

The kernel console leaves a blinking cursor on the framebuffer. How to disable it depends on the platform; on a Raspberry Pi, add vt.global_cursor_default=0 to /boot/cmdline.txt.

Wrong resolution after boot

The kernel sizes the framebuffer when it initializes, based on what the display reports. If the board powers up before the screen (common with HDMI) the kernel may pick the wrong resolution, leaving both the visible and virtual resolutions incorrect.

Check what the kernel actually chose:

sh
fbset -fb /dev/fb0

The fix is procedural: make sure the display is connected and powered before the board boots.

Support

CapabilityValue
RotationSoftware
Runtime resolution changeNo
Runtime color format changeNo
Color formatsL8, RGB565, RGB888 or XRGB8888, chosen from the framebuffer's bit depth (8, 16, 24 or 32)
Multiple displays / windowsYes
Hardware accelerationNone
Render modePartial (default) — configurable via LV_LINUX_FBDEV_RENDER_MODE
InputNone built in. Pair with evdev or libinput

8bpp needs a grayscale framebuffer

An 8bpp framebuffer maps to LV_COLOR_FORMAT_L8, which writes one luminance byte per pixel, so the device has to report a grayscale format. Colour 8bpp framebuffers (palette-indexed, packed RGB332, or FOURCC) are rejected and lv_linux_fbdev_set_file returns LV_RESULT_INVALID.

Check what yours reports with fbset -i -fb /dev/fb0.

See Also

  • DRM - the modern replacement, with modesetting and a GPU path
  • evdev - simplest input pairing for this driver
  • libinput - input with device quirks and full keyboard support
  • lv_port_linux - reference project

Last updated on

On this page