OpenGL Driver
The OpenGL driver renders an LVGL display into an OpenGL texture, for embedding LVGL inside an application that already owns the OpenGL context.
Overview
The OpenGL display driver renders an LVGL display into an OpenGL texture and hands you the texture id. It creates no window and no context: it is the driver to use when something else, a game, a visualization tool or your own engine already owns the OpenGL context and you want LVGL content inside it.
If you do not already have a context, use a driver that creates one for you instead:
- GLFW on PC-like platforms
- EGL, or DRM and Wayland with their EGL backends, on embedded targets
- SDL with its EGL backend
Experimental API
The OpenGL Driver API is experimental. Expect breaking changes.
Configuration
Enable LV_USE_OPENGLES.
There are no libraries for LVGL to resolve, the GL entry points come from the context you already created.
To render on the GPU rather than uploading software-rendered pixels into the texture, also enable a draw
unit: LV_USE_DRAW_NANOVG (recommended) or LV_USE_DRAW_OPENGLES. See
OpenGL Overview.
Usage
The OpenGL context must already be current when you call lv_opengles_texture_create. It
allocates the texture for you; lv_opengles_texture_get_texture_id returns the id to use in
your own rendering.
#include "lvgl/lvgl.h"
#define WIDTH 640
#define HEIGHT 480
int main(void)
{
lv_init();
/* Don't forget the tick callback */
/* NOTE: the OpenGL context must be created and current before this point */
lv_display_t * disp = lv_opengles_texture_create(WIDTH, HEIGHT);
/* The texture id, for use in your application's rendering */
unsigned int texture_id = lv_opengles_texture_get_texture_id(disp);
lv_demo_widgets();
while(1) {
uint32_t time_until_next = lv_timer_handler();
if(time_until_next == LV_NO_TIMER_READY) time_until_next = LV_DEF_REFR_PERIOD;
lv_delay_ms(time_until_next);
/* Draw texture_id in your own scene, then swap buffers */
}
return 0;
}If you have already allocated a texture yourself, wrap it instead of letting LVGL create one with
lv_opengles_texture_create_from_texture_id.
lv_opengles_texture_get_from_texture_id looks up the display belonging to a texture id,
and lv_opengles_texture_reshape resizes a texture and its display together.
Private API
Resizing a texture requires using LVGL's Private API.
Create as many displays as you need, each gets its own texture.
Drawing the texture yourself
The driver flushes into the texture and stops there; putting it on screen is your job.
lv_opengles_render_texture draws a texture into the current framebuffer if you want LVGL
to do it, and lv_opengles_render_display_texture does the same for a display's own
texture.
To take over presentation entirely, set your own flush callback. This one works in both the full and direct render modes:
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
{
LV_UNUSED(area);
LV_UNUSED(px_map);
if(lv_display_flush_is_last(disp)) {
const int32_t w = lv_display_get_horizontal_resolution(disp);
const int32_t h = lv_display_get_vertical_resolution(disp);
/* The texture always covers the full screen, even when `area` does not,
* which is the case in the direct render mode */
lv_area_t full_area;
lv_area_set(&full_area, 0, 0, w, h);
unsigned int texture_id = lv_opengles_texture_get_texture_id(disp);
/* Renders into the current context */
lv_opengles_render_texture(texture_id, &full_area, LV_OPA_COVER, w, h, &full_area, false, true);
}
lv_display_flush_ready(disp);
}Register it after creating the display, together with the render mode you want:
lv_display_set_render_mode(disp, LV_DISPLAY_RENDER_MODE_FULL);
lv_display_set_flush_cb(disp, flush_cb);lv_opengles_viewport sets the viewport LVGL renders through, if your application needs
LVGL confined to part of the framebuffer.
OpenGL Texture Caching Renderer
LV_USE_DRAW_OPENGLES enables a renderer that caches software-rendered areas as OpenGL
textures and reuses them whenever a later frame asks for the same thing. In most UIs this is a large
improvement, because most of the screen does not change between frames.
Known Limitations
- Performance is the same or slightly worse when drawn areas never hit the cache — widgets whose color or shape changes every frame, such as a label recolored randomly each frame (the "Multiple labels" scene of the benchmark demo).
- Layers that have both transparent pixels and an overall layer opacity do not blend correctly. Visible in the border corners of the benchmark demo's "Containers with opa_layer" scene.
- Layers with rotation are not supported. Rotated images are fine.
LV_USE_DRAW_NANOVG avoids these limitations and performs better; prefer it unless you
specifically need the texture cache. See
NanoVG Draw Unit.
Support
| Capability | Value |
|---|---|
| Rotation | Hardware (GPU) |
| Runtime resolution change | With lv_opengles_texture_reshape (Private API) |
| Runtime color format change | No |
| Color formats | From LV_COLOR_FORMAT_DEFAULT (RGB565 or XRGB8888) |
| Multiple displays / windows | Yes. One display per texture. Windows are not this driver's concern |
| Hardware acceleration | OpenGL ES, via LV_USE_DRAW_NANOVG or LV_USE_DRAW_OPENGLES |
| Render mode | Direct by default |
| Input | None built in. The window belongs to your application, so feed LVGL input yourself |
See Also
- GLFW - creates the window and context for you, and can composite these textures
- EGL - context creation on embedded targets, including off-screen rendering
- OpenGL Overview - how the drivers and draw units fit together
- NanoVG Draw Unit - the recommended GPU renderer
- OpenGL ES Draw Unit - the texture-caching renderer
Last updated on
GLFW
The GLFW driver opens a window with an OpenGL context and reads mouse and keyboard input. It is the quickest way to get LVGL running with GPU rendering on a PC-like platform.
EGL
EGL is the platform layer that binds OpenGL ES to a native windowing system. In LVGL it underpins the hardware-accelerated backends of the DRM, Wayland and SDL drivers, and can also render off-screen with no display server at all.