From e4edfa3d64e86eff798c2eb176c06c463fbf5483 Mon Sep 17 00:00:00 2001 From: Eugenio Paolantonio Date: Sat, 21 May 2022 11:02:23 +0000 Subject: [PATCH] Allow runtime selection of the lvgl display driver ("backend"), enable DRM backend --- CHANGELOG.md | 2 ++ README.md | 27 +++++++++++++++++++++++- backends.c | 48 ++++++++++++++++++++++++++++++++++++++++++ backends.h | 50 ++++++++++++++++++++++++++++++++++++++++++++ command_line.c | 10 ++++++++- command_line.h | 2 ++ config.c | 7 +++++++ config.h | 4 ++++ main.c | 53 ++++++++++++++++++++++++++++++++++++++--------- meson.build | 21 +++++++++++++------ meson_options.txt | 1 + unl0kr.conf | 1 + 12 files changed, 208 insertions(+), 18 deletions(-) create mode 100644 backends.c create mode 100644 backends.h create mode 100644 meson_options.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index c01aa49..9e83606 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ - fix: Prevent scrolling when keyboard hides (#21) - feat!: Do not show last typed character when typing (#25) - feat: Update lvgl & lv_drivers to git master (2022-02-21) +- feat: allow runtime selection of the lvgl display driver ("backend") +- feat: allow overriding dpi with the --dpi command line parameter ## 0.1.0 (2021-11-15) diff --git a/README.md b/README.md index f0b5c3f..f7a8a46 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Unl0kr ====== -Framebuffer-based disk unlocker for the initramfs based on [LVGL]. +Disk unlocker for the initramfs based on [LVGL]. [[_TOC_]] @@ -72,6 +72,7 @@ Mandatory arguments to long options are mandatory for short options too. order. -g, --geometry=NxM Force a display size of N horizontal times M vertical pixels + -d --dpi=N Overrides the DPI -h, --help Print this message and exit -v, --verbose Enable more detailed logging output on STDERR -V, --version Print the unl0kr version and exit @@ -89,6 +90,7 @@ For an example configuration file, see [unl0kr.conf]. - [squeek2lvgl] (git submodule / linked statically) - [libinput] - [libxkbcommon] +- [libdrm] (optional, required for the DRM backend) - evdev kernel module ## Building & running @@ -104,6 +106,28 @@ $ sudo ./_build/unl0kr With meson <0\.55 use `ninja` instead of `meson compile`\. +### Optional features + +If [libdrm] is installed, the DRM backend will be compiled automatically. It's possible to +change this behaviour using the `with-drm` meson feature. For example, + +``` +$ meson _build -Dwith-drm=disabled +``` + +will forcibly disable the DRM backend regardless if libdrm is installed or not. + +## Backends + +Unl0kr supports multiple lvgl display drivers, which are herein referred as "backends". + +Currently supported backends: + +- fbdev +- drm (optional) + +The backend can be switched at runtime by modifying the `general.backend` configuration. + ## Fonts In order to work with [LVGL], fonts need to be converted to bitmaps, stored as C arrays. Unl0kr currently uses a combination of the [OpenSans] font for text and the [FontAwesome] font for pictograms. For both fonts only limited character ranges are included to reduce the binary size. To (re)generate the C file containing the combined font, run the following command @@ -200,6 +224,7 @@ The [FontAwesome] font is licensed under the Open Font License version 1.1. [inih]: https://github.com/benhoyt/inih [libinput]: https://gitlab.freedesktop.org/libinput/libinput [libxkbcommon]: https://github.com/xkbcommon/libxkbcommon +[libdrm]: https://gitlab.freedesktop.org/mesa/drm [lv_drivers]: https://github.com/lvgl/lv_drivers [lv_port_linux_frame_buffer]: https://github.com/lvgl/lv_port_linux_frame_buffer [lv_sim_emscripten]: https://github.com/lvgl/lv_sim_emscripten/blob/master/mouse_cursor_icon.c diff --git a/backends.c b/backends.c new file mode 100644 index 0000000..7ac3af9 --- /dev/null +++ b/backends.c @@ -0,0 +1,48 @@ +/** + * Copyright 2022 Eugenio Paolantonio (g7) + * + * This file is part of unl0kr, hereafter referred to as the program. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backends.h" + +#include + +/** + * Public interface + */ + +const char *ul_backends_backends[] = { +#if USE_FBDEV + "fbdev", +#endif /* USE_FBDEV */ +#if USE_DRM + "drm", +#endif /* USE_DRM */ + NULL +}; + +ul_backends_backend_id_t ul_backends_find_backend_with_name(const char *name) { + for (int i = 0; ul_backends_backends[i] != NULL; ++i) { + if (strcmp(ul_backends_backends[i], name) == 0) { + ul_log(UL_LOG_LEVEL_VERBOSE, "Found backend: %s\n", name); + return i; + } + } + ul_log(UL_LOG_LEVEL_WARNING, "Backend %s not found\n", name); + return UL_BACKENDS_BACKEND_NONE; +} diff --git a/backends.h b/backends.h new file mode 100644 index 0000000..5e1dc1c --- /dev/null +++ b/backends.h @@ -0,0 +1,50 @@ +/** + * Copyright 2022 Eugenio Paolantonio (g7) + * + * This file is part of unl0kr, hereafter referred to as the program. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#ifndef UL_BACKENDS_H +#define UL_BACKENDS_H + +#include "lv_drv_conf.h" + +#include "log.h" + +/* NOTE: Only UL_BACKENDS_BACKEND_NONE is ought to have an explicit value assigned */ +typedef enum { + UL_BACKENDS_BACKEND_NONE = -1, +#if USE_FBDEV + UL_BACKENDS_BACKEND_FBDEV, +#endif /* USE_FBDEV */ +#if USE_DRM + UL_BACKENDS_BACKEND_DRM, +#endif /* USE_DRM */ +} ul_backends_backend_id_t; + +/* Backends */ +extern const char *ul_backends_backends[]; + +/** + * Find the first backend with a given name. + * + * @param name backend name + * @return ID of the first matching backend or UL_BACKENDS_BACKEND_NONE if no backend matched + */ +ul_backends_backend_id_t ul_backends_find_backend_with_name(const char *name); + +#endif /* UL_BACKENDS_H */ diff --git a/command_line.c b/command_line.c index 183496d..872717c 100644 --- a/command_line.c +++ b/command_line.c @@ -82,6 +82,7 @@ static void print_usage() { " order.\n" " -g, --geometry=NxM Force a display size of N horizontal times M\n" " vertical pixels\n" + " -d --dpi=N Overrides the DPI\n" " -h, --help Print this message and exit\n" " -v, --verbose Enable more detailed logging output on STDERR\n" " -V, --version Print the unl0kr version and exit\n"); @@ -100,6 +101,7 @@ void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *opts) { { "config", required_argument, NULL, 'c' }, { "config-override", required_argument, NULL, 'C' }, { "geometry", required_argument, NULL, 'g' }, + { "dpi", required_argument, NULL, 'd' }, { "help", no_argument, NULL, 'h' }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, @@ -108,7 +110,7 @@ void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *opts) { int opt, index = 0; - while ((opt = getopt_long(argc, argv, "c:C:g:hvV", long_opts, &index)) != -1) { + while ((opt = getopt_long(argc, argv, "c:C:g:d:hvV", long_opts, &index)) != -1) { switch (opt) { case 'c': opts->config_files[0] = optarg; @@ -128,6 +130,12 @@ void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *opts) { exit(EXIT_FAILURE); } break; + case 'd': + if (sscanf(optarg, "%i", &(opts->dpi)) != 1) { + ul_log(UL_LOG_LEVEL_ERROR, "Invalid dpi argument \"%s\"\n", optarg); + exit(EXIT_FAILURE); + } + break; case 'h': print_usage(); exit(EXIT_SUCCESS); diff --git a/command_line.h b/command_line.h index beb357d..5a98923 100644 --- a/command_line.h +++ b/command_line.h @@ -35,6 +35,8 @@ typedef struct { int hor_res; /* Vertical display resolution */ int ver_res; + /* DPI */ + int dpi; /* Verbose mode. If true, provide more detailed logging output on STDERR. */ bool verbose; } ul_cli_opts; diff --git a/config.c b/config.c index 71e4bb4..da4c985 100644 --- a/config.c +++ b/config.c @@ -73,6 +73,7 @@ static bool parse_bool(const char *value, bool *result); static void init_opts(ul_config_opts *opts) { opts->general.animations = false; + opts->general.backend = ul_backends_backends[0] == NULL ? UL_BACKENDS_BACKEND_NONE : 0; opts->keyboard.autohide = true; opts->keyboard.layout_id = SQ2LV_LAYOUT_US; opts->keyboard.popovers = false; @@ -95,6 +96,12 @@ static int parsing_handler(void* user_data, const char* section, const char* key if (parse_bool(value, &(opts->general.animations))) { return 1; } + } else if (strcmp(key, "backend") == 0) { + ul_backends_backend_id_t id = ul_backends_find_backend_with_name(value); + if (id != UL_BACKENDS_BACKEND_NONE) { + opts->general.backend = id; + return 1; + } } } else if (strcmp(section, "keyboard") == 0) { if (strcmp(key, "autohide") == 0) { diff --git a/config.h b/config.h index 5c582e6..948f29c 100644 --- a/config.h +++ b/config.h @@ -21,6 +21,8 @@ #ifndef UL_CONFIG_H #define UL_CONFIG_H +#include "backends.h" + #include "themes.h" #include "sq2lv_layouts.h" @@ -31,6 +33,8 @@ * General options */ typedef struct { + /* Backend to use */ + ul_backends_backend_id_t backend; /* If true, use animations */ bool animations; } ul_config_opts_general; diff --git a/main.c b/main.c index 5e7c506..3054031 100644 --- a/main.c +++ b/main.c @@ -18,6 +18,7 @@ */ +#include "backends.h" #include "command_line.h" #include "config.h" #include "indev.h" @@ -27,7 +28,14 @@ #include "theme.h" #include "themes.h" +#include "lv_drv_conf.h" + +#if USE_FBDEV #include "lv_drivers/display/fbdev.h" +#endif /* USE_FBDEV */ +#if USE_DRM +#include "lv_drivers/display/drm.h" +#endif /* USE_DRM */ #include "lvgl/lvgl.h" @@ -338,19 +346,45 @@ int main(int argc, char *argv[]) { lv_init(); lv_log_register_print_cb(ul_log_print_cb); - /* Initialise framebuffer driver and query display size */ - fbdev_init(); - uint32_t hor_res; - uint32_t ver_res; - fbdev_get_sizes(&hor_res, &ver_res); + /* Initialise display driver */ + static lv_disp_drv_t disp_drv; + lv_disp_drv_init(&disp_drv); - /* Override display size with command line options if necessary */ + /* Initialise framebuffer driver and query display size */ + uint32_t hor_res = 0; + uint32_t ver_res = 0; + uint32_t dpi = 0; + + switch (conf_opts.general.backend) { +#if USE_FBDEV + case UL_BACKENDS_BACKEND_FBDEV: + fbdev_init(); + fbdev_get_sizes(&hor_res, &ver_res); + disp_drv.flush_cb = fbdev_flush; + break; +#endif /* USE_FBDEV */ +#if USE_DRM + case UL_BACKENDS_BACKEND_DRM: + drm_init(); + drm_get_sizes((lv_coord_t *)&hor_res, (lv_coord_t *)&ver_res, &dpi); + disp_drv.flush_cb = drm_flush; + break; +#endif /* USE_DRM */ + default: + ul_log(UL_LOG_LEVEL_ERROR, "Unable to find suitable backend"); + exit(EXIT_FAILURE); + } + + /* Override display parameters with command line options if necessary */ if (cli_opts.hor_res > 0) { hor_res = LV_MIN(hor_res, cli_opts.hor_res); } if (cli_opts.ver_res > 0) { ver_res = LV_MIN(ver_res, cli_opts.ver_res); } + if (cli_opts.dpi > 0) { + dpi = cli_opts.dpi; + } /* Prepare display buffer */ const size_t buf_size = hor_res * ver_res / 10; /* At least 1/10 of the display size is recommended */ @@ -358,13 +392,12 @@ int main(int argc, char *argv[]) { lv_color_t *buf = (lv_color_t *)malloc(buf_size * sizeof(lv_color_t)); lv_disp_draw_buf_init(&disp_buf, buf, NULL, buf_size); - /* Initialise display driver */ - static lv_disp_drv_t disp_drv; - lv_disp_drv_init(&disp_drv); + + /* Register display driver */ disp_drv.draw_buf = &disp_buf; - disp_drv.flush_cb = fbdev_flush; disp_drv.hor_res = hor_res; disp_drv.ver_res = ver_res; + disp_drv.dpi = dpi; lv_disp_drv_register(&disp_drv); /* Connect input devices */ diff --git a/meson.build b/meson.build index 45d2b9d..359495c 100644 --- a/meson.build +++ b/meson.build @@ -27,6 +27,7 @@ project( add_project_arguments('-DUL_VERSION="@0@"'.format(meson.project_version()), language: ['c']) unl0kr_sources = [ + 'backends.c', 'command_line.c', 'config.c', 'cursor.c', @@ -37,13 +38,25 @@ unl0kr_sources = [ 'sq2lv_layouts.c', 'terminal.c', 'theme.c', - 'themes.c' + 'themes.c', ] squeek2lvgl_sources = [ 'squeek2lvgl/sq2lv.c', ] +unl0kr_dependencies = [ + dependency('inih'), + dependency('libinput'), + dependency('xkbcommon'), +] + +libdrm_dep = dependency('libdrm', required: get_option('with-drm')) +if libdrm_dep.found() + unl0kr_dependencies += [libdrm_dep] + add_project_arguments('-DUSE_DRM=1', language: ['c']) +endif + lvgl_sources = run_command('find-lvgl-sources.sh', 'lvgl', check: true).stdout().strip().split('\n') lv_drivers_sources = run_command('find-lvgl-sources.sh', 'lv_drivers', check: true).stdout().strip().split('\n') @@ -54,10 +67,6 @@ executable( 'unl0kr', sources: unl0kr_sources + squeek2lvgl_sources + lvgl_sources + lv_drivers_sources, include_directories: ['lvgl', 'lv_drivers'], - dependencies: [ - dependency('inih'), - dependency('libinput'), - dependency('xkbcommon') - ], + dependencies: unl0kr_dependencies, install: true ) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..2b2783b --- /dev/null +++ b/meson_options.txt @@ -0,0 +1 @@ +option('with-drm', type : 'feature', value : 'auto', description : 'Enable DRM backend') diff --git a/unl0kr.conf b/unl0kr.conf index 4486809..9e75f31 100644 --- a/unl0kr.conf +++ b/unl0kr.conf @@ -1,5 +1,6 @@ [general] animations=true +#backend=fbdev [keyboard] autohide=true