diff --git a/include/tfblib.h b/include/tfblib.h index 2f809d8..ae8e105 100644 --- a/include/tfblib.h +++ b/include/tfblib.h @@ -12,6 +12,7 @@ #include #include +#include "config.h" #include "pbsplash.h" /// Convenience macro used to shorten the signatures. Undefined at the end. @@ -85,7 +86,11 @@ */ int tfb_acquire_fb(u32 flags, const char *fb_device, const char *tty_device); +#ifdef CONFIG_DRM_SUPPORT int tfb_acquire_drm(uint32_t flags, const char *device); +#else +#define tfb_acquire_drm(f, d) ({ -1; }) +#endif /** * Release the framebuffer device diff --git a/include/framebuffer.h b/include/tfblib_drm.h similarity index 90% rename from include/framebuffer.h rename to include/tfblib_drm.h index e6b7da2..da33865 100644 --- a/include/framebuffer.h +++ b/include/tfblib_drm.h @@ -1,13 +1,17 @@ -#ifndef _FRAMEBUFFER_H -#define _FRAMEBUFFER_H +#pragma once #include +#include "config.h" + +#ifdef CONFIG_DRM_SUPPORT + #include #include #include #include + struct modeset_buf { uint32_t width; uint32_t height; @@ -32,6 +36,8 @@ struct drm_framebuffer { extern struct drm_framebuffer *drm; +#endif + int drm_framebuffer_init(int *handle, const char *card); void drm_framebuffer_close(int handle); -#endif + diff --git a/meson.build b/meson.build index ca2fbad..e0560bb 100644 --- a/meson.build +++ b/meson.build @@ -3,12 +3,39 @@ cc = meson.get_compiler('c') deps = [ cc.find_library('m', required : false), - dependency('libdrm'), dependency('libudev'), ] -inc = [ - include_directories('include'), +conf_data = configuration_data() +use_drm = get_option('drm') + +src = [ + 'src/animate.c', + 'src/nanosvg.c', + 'src/timespec.c', + 'src/pbsplash.c', + 'src/fb.c', + 'src/drawing.c', ] -subdir('src') +if use_drm.enabled() + deps += dependency('libdrm') + src += 'src/drm.c' + conf_data.set('CONFIG_DRM_SUPPORT', true) +else + src += 'src/drm_stub.c' + conf_data.set('CONFIG_DRM_SUPPORT', false) +endif + +configure_file(output : 'config.h', + configuration : conf_data) + +inc = [ + include_directories('include'), + include_directories('.') +] + +executable('pbsplash', src, + include_directories: inc, + dependencies: deps, + install: true) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..aa355b5 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1 @@ +option('drm', type : 'feature', value : 'disabled') diff --git a/src/drawing.c b/src/drawing.c index c00a9e6..a25c48f 100644 --- a/src/drawing.c +++ b/src/drawing.c @@ -8,9 +8,10 @@ #include #include "pbsplash.h" -#include "framebuffer.h" #include "tfblib.h" +#include "tfblib_drm.h" + #define DEBUGRENDER 0 extern inline uint32_t tfb_make_color(uint8_t red, uint8_t green, uint8_t blue); @@ -145,8 +146,10 @@ void tfb_fill_rect(int x, int y, int w, int h, uint32_t color) dest = __fb_buffer + y * __fb_pitch + (x * 4); /* drm alignment weirdness */ +#ifdef CONFIG_DRM_SUPPORT if (drm) w *= 4; +#endif for (uint32_t cy = y; cy < yend; cy++, dest += __fb_pitch) memset(dest, color, w); diff --git a/src/drm.c b/src/drm.c index abdcd32..36e2caa 100644 --- a/src/drm.c +++ b/src/drm.c @@ -40,7 +40,7 @@ #include #include -#include "framebuffer.h" +#include "tfblib_drm.h" struct modeset_buf; struct drm_framebuffer; diff --git a/src/drm_stub.c b/src/drm_stub.c new file mode 100644 index 0000000..a69ce30 --- /dev/null +++ b/src/drm_stub.c @@ -0,0 +1,7 @@ + +int drm_framebuffer_init(int *handle, const char *card) { + return -1; +} + +void drm_framebuffer_close(int handle) { +} diff --git a/src/fb.c b/src/fb.c index f115481..193e2b9 100644 --- a/src/fb.c +++ b/src/fb.c @@ -15,10 +15,11 @@ #include #include -#include "framebuffer.h" #include "pbsplash.h" #include "tfblib.h" +#include "tfblib_drm.h" + #define DEFAULT_FB_DEVICE "/dev/fb0" #define DEFAULT_TTY_DEVICE "/dev/tty" @@ -51,6 +52,7 @@ static int tfb_set_window(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32 return 0; } +#ifdef CONFIG_DRM_SUPPORT int tfb_acquire_drm(uint32_t flags, const char *device) { int ret; @@ -86,6 +88,7 @@ int tfb_acquire_drm(uint32_t flags, const char *device) return 0; } +#endif int tfb_acquire_fb(uint32_t flags, const char *fb_device, const char *tty_device) { @@ -259,6 +262,7 @@ void tfb_flush_window(void) int tfb_flush_fb(void) { +#ifdef CONFIG_DRM_SUPPORT int ret; struct modeset_buf *buf; if (drmfd >= 0) { @@ -276,6 +280,7 @@ int tfb_flush_fb(void) __fb_buffer = buf->map; //drm->bufs[drm->front_buf ^ 1].map; return 0; } +#endif __fbi.activate |= FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &__fbi) < 0) { perror("Couldn't flush framebuffer"); @@ -287,15 +292,19 @@ int tfb_flush_fb(void) uint32_t tfb_screen_width_mm(void) { +#ifdef CONFIG_DRM_SUPPORT if (drmfd >= 0) return drm->mm_width; +#endif return __fbi.width; } uint32_t tfb_screen_height_mm(void) { +#ifdef CONFIG_DRM_SUPPORT if (drmfd >= 0) return drm->mm_height; +#endif return __fbi.height; } diff --git a/src/meson.build b/src/meson.build deleted file mode 100644 index 89879e9..0000000 --- a/src/meson.build +++ /dev/null @@ -1,14 +0,0 @@ -src = [ - 'animate.c', - 'nanosvg.c', - 'timespec.c', - 'pbsplash.c', - 'fb.c', - 'drm.c', - 'drawing.c', -] - -executable('pbsplash', src, - include_directories: inc, - dependencies: deps, - install: true) diff --git a/src/pbsplash.c b/src/pbsplash.c index 2f39fe1..fa5cb01 100644 --- a/src/pbsplash.c +++ b/src/pbsplash.c @@ -9,12 +9,13 @@ #include #include -#include -#include +#include "config.h" #include "nanosvg.h" #include "pbsplash.h" #include "tfblib.h" #include "timespec.h" +#include +#include #define MSG_MAX_LEN 4096 #define DEFAULT_FONT_PATH "/usr/share/pbsplash/OpenSans-Regular.svg" @@ -48,17 +49,20 @@ static int usage() fprintf(stderr, "pbsplash [-v] [-h] [-f font] [-s splash image] [-m message]\n"); fprintf(stderr, " [-b message bottom] [-o font size bottom]\n"); fprintf(stderr, " [-p font size] [-q max logo size] [-d] [-e]\n\n"); - fprintf(stderr, " -v enable verbose logging\n"); - fprintf(stderr, " -h show this help\n"); - fprintf(stderr, " -f path to SVG font file (default: %s)\n", DEFAULT_FONT_PATH); - fprintf(stderr, " -s path to splash image to display\n"); - fprintf(stderr, " -m message to show under the splash image\n"); fprintf(stderr, " -b message to show at the bottom\n"); + fprintf(stderr, " -d custom DPI (for testing)\n"); + fprintf(stderr, " -e error (no loading animation)\n"); + fprintf(stderr, " -f path to SVG font file (default: %s)\n", DEFAULT_FONT_PATH); + fprintf(stderr, " -h show this help\n"); + fprintf(stderr, " -m message to show under the splash image\n"); fprintf(stderr, " -o font size bottom in pt (default: %d)\n", FONT_SIZE_B_PT); fprintf(stderr, " -p font size in pt (default: %d)\n", FONT_SIZE_PT); fprintf(stderr, " -q max logo size in mm (default: %d)\n", LOGO_SIZE_MAX_MM); - fprintf(stderr, " -d custom DPI (for testing)\n"); - fprintf(stderr, " -e error (no loading animation)\n"); +#ifdef CONFIG_DRM_SUPPORT + fprintf(stderr, " -r use DRM for rendering instead of framebuffer"); +#endif + fprintf(stderr, " -s path to splash image to display\n"); + fprintf(stderr, " -v enable verbose logging\n"); // clang-format on return 1; @@ -108,7 +112,7 @@ static inline float getShapeWidth(const NSVGimage *font, const NSVGshape *shape) if (shape) { return shape->horizAdvX; } else { - //printf("WARNING: Shape for '%s' is NULL!\n", shape->unicode ?: ""); + // printf("WARNING: Shape for '%s' is NULL!\n", shape->unicode ?: ""); return font->defaultHorizAdv; } } @@ -400,6 +404,7 @@ int main(int argc, char **argv) }; int optflag; bool animation = true; + bool use_drm = false; memset(active_tty, '\0', TTY_PATH_LEN); strcat(active_tty, "/dev/"); @@ -409,7 +414,7 @@ int main(int argc, char **argv) sigaction(SIGTERM, &action, NULL); sigaction(SIGINT, &action, NULL); - while ((optflag = getopt(argc, argv, "hvf:s:m:b:o:p:q:d:e")) != -1) { + while ((optflag = getopt(argc, argv, "hvf:s:m:b:o:p:q:d:er")) != -1) { char *end = NULL; switch (optflag) { case 'h': @@ -452,6 +457,13 @@ int main(int argc, char **argv) return usage(); } break; + case 'r': +#ifndef CONFIG_DRM_SUPPORT + fprintf(stderr, "DRM support not compiled in\n"); + return usage(); +#endif + use_drm = true; + break; case 'd': dpi_info.dpi = strtol(optarg, &end, 10); if (end == optarg || dpi_info.dpi < 0) { @@ -467,27 +479,25 @@ int main(int argc, char **argv) } } - // { - // FILE *fp = fopen("/sys/devices/virtual/tty/tty0/active", "r"); - // int len = strlen(active_tty); - // char *ptr = active_tty + len; - // if (fp != NULL) { - // fgets(ptr, TTY_PATH_LEN - len, fp); - // *(ptr + strlen(ptr) - 1) = '\0'; - // fclose(fp); - // } - // } + /* Framebuffer */ + if (!use_drm) { + FILE *fp = fopen("/sys/devices/virtual/tty/tty0/active", "r"); + int len = strlen(active_tty); + char *ptr = active_tty + len; + if (fp != NULL) { + fgets(ptr, TTY_PATH_LEN - len, fp); + *(ptr + strlen(ptr) - 1) = '\0'; + fclose(fp); + } - // LOG("active tty: '%s'\n", active_tty); + LOG("active tty: '%s'\n", active_tty); - // if ((rc = tfb_acquire_fb(/*TFB_FL_NO_TTY_KD_GRAPHICS */ 0, "/dev/fb0", active_tty)) != - // TFB_SUCCESS) { - // fprintf(stderr, "tfb_acquire_fb() failed with error code: %d\n", rc); - // rc = 1; - // return rc; - // } - - if ((rc = tfb_acquire_drm(0, "/dev/dri/card0")) != 0) { + if ((rc = tfb_acquire_fb(0, "/dev/fb0", active_tty)) != 0) { + fprintf(stderr, "tfb_acquire_fb() failed with error code: %d\n", rc); + rc = 1; + return rc; + } + } else if ((rc = tfb_acquire_drm(0, "/dev/dri/card0")) != 0) { fprintf(stderr, "tfb_acquire_drm() failed with error code: %d\n", rc); rc = 1; return rc; @@ -532,11 +542,15 @@ no_messages: tfb_flush_fb(); int tick = 0; - // int tty = open(active_tty, O_RDWR); - // if (!tty) { - // fprintf(stderr, "Failed to open tty %s (%d)\n", active_tty, errno); - // goto out; - // } + int tty = 0; + + if (!use_drm) { + open(active_tty, O_RDWR); + if (!tty) { + fprintf(stderr, "Failed to open tty %s (%d)\n", active_tty, errno); + goto out; + } + } struct timespec epoch, start, end, diff; int target_fps = 60; @@ -553,7 +567,7 @@ no_messages: tfb_flush_fb(); clock_gettime(CLOCK_REALTIME, &end); diff = timespec_sub(end, start); - //printf("%05d: %09ld\n", tick, diff.tv_nsec); + // printf("%05d: %09ld\n", tick, diff.tv_nsec); if (diff.tv_nsec < 1000000000 / target_fps) { struct timespec sleep_time = { .tv_sec = 0, @@ -564,15 +578,18 @@ no_messages: } out: - // Before we exit print the logo so it will persist - if (image_info.image) { - //ioctl(tty, KDSETMODE, KD_TEXT); - draw_svg(image_info.image, image_info.x, image_info.y, image_info.width, - image_info.height); - } + /* Currently DRM doesn't persist the framebuffer after exiting */ + if (!use_drm) { + // Before we exit print the logo so it will persist + if (image_info.image) { + ioctl(tty, KDSETMODE, KD_TEXT); + draw_svg(image_info.image, image_info.x, image_info.y, image_info.width, + image_info.height); + } - // Draw the messages again so they will persist - show_messages(&msgs, &dpi_info); + // Draw the messages again so they will persist + show_messages(&msgs, &dpi_info); + } nsvgDelete(image_info.image); nsvgDelete(msgs.font);