From b3e49987c5706612ee342c685dea799be596df6a Mon Sep 17 00:00:00 2001 From: Naoto Yamaguchi Date: Sun, 23 Apr 2023 20:25:45 +0900 Subject: Enable drm-lease support at psplash The upstream version of psplash is supporting fb based splash screen. On the other hand, drm lease infrastructure is not support fb. This patch enable drm-lease support at psplash. This work contributed by Hiroyuki Ishii at CES2023 demo development. Bug-AGL: SPEC-4766 Change-Id: I50b382c7f8ca4b46a8fb06fd649d0cfa49800c6d Signed-off-by: Naoto Yamaguchi --- .../0001-Fix-duplicated-definition-of-bool.patch | 35 + .../psplash/files/0002-Trim-trailing-spaces.patch | 535 +++++++++++++++ .../files/0003-Fix-unused-result-warnings.patch | 150 ++++ .../files/0004-Remove-unused-save_termios.patch | 41 ++ .../0005-Remove-psplash-fb.h-from-psplash.h.patch | 81 +++ .../0006-Extract-plot-pixel-from-psplash-fb.patch | 624 +++++++++++++++++ ...7-Extract-draw-rect-image-from-psplash-fb.patch | 299 ++++++++ .../0008-Extract-draw-font-from-psplash-fb.patch | 350 ++++++++++ ...ake-psplash_draw_-msg-progress-independen.patch | 191 ++++++ .../0010-Rework-flip-as-function-pointer.patch | 141 ++++ ...port-drm-howto-modeset.c-as-psplash-drm.c.patch | 764 +++++++++++++++++++++ .../psplash/files/0012-Implement-drm-backend.patch | 507 ++++++++++++++ .../psplash/files/0013-Reverse-modeset_list.patch | 48 ++ ....c-Allocate-resources-only-for-the-first-.patch | 46 ++ ...-psplash-drm.c-Implement-double-buffering.patch | 350 ++++++++++ .../files/0016-Imprement-drm-lease-support.patch | 189 +++++ ...ix-incorrect-drawing-with-portrait-orient.patch | 42 ++ .../recipes-core/psplash/psplash_git.bbappend | 43 ++ 18 files changed, 4436 insertions(+) create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0001-Fix-duplicated-definition-of-bool.patch create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0002-Trim-trailing-spaces.patch create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0003-Fix-unused-result-warnings.patch create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0004-Remove-unused-save_termios.patch create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0005-Remove-psplash-fb.h-from-psplash.h.patch create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0006-Extract-plot-pixel-from-psplash-fb.patch create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0007-Extract-draw-rect-image-from-psplash-fb.patch create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0008-Extract-draw-font-from-psplash-fb.patch create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0009-psplash.c-Make-psplash_draw_-msg-progress-independen.patch create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0010-Rework-flip-as-function-pointer.patch create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0011-Import-drm-howto-modeset.c-as-psplash-drm.c.patch create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0012-Implement-drm-backend.patch create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0013-Reverse-modeset_list.patch create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0014-psplash-drm.c-Allocate-resources-only-for-the-first-.patch create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0015-psplash-drm.c-Implement-double-buffering.patch create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0016-Imprement-drm-lease-support.patch create mode 100644 meta-agl-drm-lease/recipes-core/psplash/files/0017-drm-lease-Fix-incorrect-drawing-with-portrait-orient.patch create mode 100644 meta-agl-drm-lease/recipes-core/psplash/psplash_git.bbappend (limited to 'meta-agl-drm-lease') diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0001-Fix-duplicated-definition-of-bool.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0001-Fix-duplicated-definition-of-bool.patch new file mode 100644 index 00000000..ae533b73 --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/files/0001-Fix-duplicated-definition-of-bool.patch @@ -0,0 +1,35 @@ +From 816b7168c6380ec5a72416d3e0c52e22d891e2d9 Mon Sep 17 00:00:00 2001 +From: Hiroyuki Ishii +Date: Tue, 27 Dec 2022 14:44:14 +0900 +Subject: [PATCH 01/17] Fix duplicated definition of bool + +We'd like to use stdbool.h instead of defining bool type +duplicatedly to avoid build issue in future changes. + +drm-backend backport from: +https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/ + +Signed-off-by: Hiroyuki Ishii +--- + psplash.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/psplash.h b/psplash.h +index 1c42ec7..9be44ba 100644 +--- a/psplash.h ++++ b/psplash.h +@@ -34,10 +34,10 @@ + #include + #include + #include ++#include + + typedef uint8_t uint8; + typedef uint16_t uint16; +-typedef int bool; + + #ifndef FALSE + #define FALSE 0 +-- +2.25.1 + diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0002-Trim-trailing-spaces.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0002-Trim-trailing-spaces.patch new file mode 100644 index 00000000..2980809e --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/files/0002-Trim-trailing-spaces.patch @@ -0,0 +1,535 @@ +From 5f82ef966776c9520af8ca59d12260d7e908e464 Mon Sep 17 00:00:00 2001 +From: Vasyl Vavrychuk +Date: Mon, 25 Apr 2022 10:59:41 +0300 +Subject: [PATCH 02/17] Trim trailing spaces + +drm-backend backport from: +https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/ + +Signed-off-by: Vasyl Vavrychuk +--- + psplash-console.c | 34 +++++++++++----------- + psplash-console.h | 8 ++--- + psplash-fb.c | 4 +-- + psplash-fb.h | 34 +++++++++++----------- + psplash-write.c | 14 ++++----- + psplash.c | 74 +++++++++++++++++++++++------------------------ + psplash.h | 4 +-- + 7 files changed, 86 insertions(+), 86 deletions(-) + +diff --git a/psplash-console.c b/psplash-console.c +index 3a40620..c00c6fe 100644 +--- a/psplash-console.c ++++ b/psplash-console.c +@@ -1,5 +1,5 @@ +-/* +- * pslash - a lightweight framebuffer splashscreen for embedded devices. ++/* ++ * pslash - a lightweight framebuffer splashscreen for embedded devices. + * + * Copyright (c) 2006 Matthew Allum + * +@@ -27,12 +27,12 @@ vt_request (int UNUSED(sig)) + perror("Error cannot switch away from console"); + Visible = 0; + +- /* FIXME: +- * We likely now want to signal the main loop as to exit ++ /* FIXME: ++ * We likely now want to signal the main loop as to exit + * and we've now likely switched to the X tty. Note, this + * seems to happen anyway atm due to select() call getting + * a signal interuption error - not sure if this is really +- * reliable however. ++ * reliable however. + */ + } + else +@@ -49,7 +49,7 @@ psplash_console_ignore_switches (void) + { + struct sigaction act; + struct vt_mode vt_mode; +- ++ + if (ioctl(ConsoleFd, VT_GETMODE, &vt_mode) < 0) + { + perror("Error VT_SETMODE failed"); +@@ -60,7 +60,7 @@ psplash_console_ignore_switches (void) + sigemptyset (&act.sa_mask); + act.sa_flags = 0; + sigaction (SIGUSR1, &act, 0); +- ++ + vt_mode.mode = VT_AUTO; + vt_mode.relsig = 0; + vt_mode.acqsig = 0; +@@ -74,7 +74,7 @@ psplash_console_handle_switches (void) + { + struct sigaction act; + struct vt_mode vt_mode; +- ++ + if (ioctl(ConsoleFd, VT_GETMODE, &vt_mode) < 0) + { + perror("Error VT_SETMODE failed"); +@@ -85,7 +85,7 @@ psplash_console_handle_switches (void) + sigemptyset (&act.sa_mask); + act.sa_flags = 0; + sigaction (SIGUSR1, &act, 0); +- ++ + vt_mode.mode = VT_PROCESS; + vt_mode.relsig = SIGUSR1; + vt_mode.acqsig = SIGUSR1; +@@ -94,8 +94,8 @@ psplash_console_handle_switches (void) + perror("Error VT_SETMODE failed"); + } + +-void +-psplash_console_switch (void) ++void ++psplash_console_switch (void) + { + char vtname[10]; + int fd; +@@ -114,9 +114,9 @@ psplash_console_switch (void) + close(fd); + return; + } +- ++ + close(fd); +- ++ + sprintf(vtname,"/dev/tty%d", VTNum); + + if ((ConsoleFd = open(vtname, O_RDWR|O_NDELAY, 0)) < 0) +@@ -134,12 +134,12 @@ psplash_console_switch (void) + + if (ioctl(ConsoleFd, VT_ACTIVATE, VTNum) != 0) + perror("Error VT_ACTIVATE failed"); +- ++ + if (ioctl(ConsoleFd, VT_WAITACTIVE, VTNum) != 0) + perror("Error VT_WAITACTIVE failed\n"); + + psplash_console_handle_switches (); +- ++ + if (ioctl(ConsoleFd, KDSETMODE, KD_GRAPHICS) < 0) + perror("Error KDSETMODE KD_GRAPHICS failed\n"); + +@@ -156,7 +156,7 @@ psplash_console_reset (void) + return; + + /* Back to text mode */ +- ioctl(ConsoleFd, KDSETMODE, KD_TEXT); ++ ioctl(ConsoleFd, KDSETMODE, KD_TEXT); + + psplash_console_ignore_switches (); + +@@ -175,7 +175,7 @@ psplash_console_reset (void) + + /* Cleanup */ + +- close(ConsoleFd); ++ close(ConsoleFd); + + if ((fd = open ("/dev/tty0", O_RDWR|O_NDELAY, 0)) >= 0) + { +diff --git a/psplash-console.h b/psplash-console.h +index c893bf2..ad51ef2 100644 +--- a/psplash-console.h ++++ b/psplash-console.h +@@ -1,5 +1,5 @@ +-/* +- * pslash - a lightweight framebuffer splashscreen for embedded devices. ++/* ++ * pslash - a lightweight framebuffer splashscreen for embedded devices. + * + * Copyright (c) 2006 Matthew Allum + * +@@ -10,8 +10,8 @@ + #ifndef _HAVE_PSPLASH_CONSOLE_H + #define _HAVE_PSPLASH_CONSOLE_H + +-void +-psplash_console_switch (void); ++void ++psplash_console_switch (void); + + void + psplash_console_reset (void); +diff --git a/psplash-fb.c b/psplash-fb.c +index 2babb5f..1d2d7db 100644 +--- a/psplash-fb.c ++++ b/psplash-fb.c +@@ -429,13 +429,13 @@ psplash_fb_plot_pixel (PSplashFB *fb, + { + case 32: + *(volatile uint32_t *) (fb->bdata + off) +- = ((red >> (8 - fb->red_length)) << fb->red_offset) ++ = ((red >> (8 - fb->red_length)) << fb->red_offset) + | ((green >> (8 - fb->green_length)) << fb->green_offset) + | ((blue >> (8 - fb->blue_length)) << fb->blue_offset); + break; + case 16: + *(volatile uint16_t *) (fb->bdata + off) +- = ((red >> (8 - fb->red_length)) << fb->red_offset) ++ = ((red >> (8 - fb->red_length)) << fb->red_offset) + | ((green >> (8 - fb->green_length)) << fb->green_offset) + | ((blue >> (8 - fb->blue_length)) << fb->blue_offset); + break; +diff --git a/psplash-fb.h b/psplash-fb.h +index 16e2b20..eafa293 100644 +--- a/psplash-fb.h ++++ b/psplash-fb.h +@@ -1,5 +1,5 @@ +-/* +- * pslash - a lightweight framebuffer splashscreen for embedded devices. ++/* ++ * pslash - a lightweight framebuffer splashscreen for embedded devices. + * + * Copyright (c) 2006 Matthew Allum + * +@@ -20,11 +20,11 @@ enum RGBMode { + + typedef struct PSplashFB + { +- int fd; ++ int fd; + struct fb_var_screeninfo fb_var; +- struct termios save_termios; +- int type; +- int visual; ++ struct termios save_termios; ++ int type; ++ int visual; + int width, height; + int bpp; + int stride; +@@ -56,20 +56,20 @@ PSplashFB* + psplash_fb_new (int angle, int fbdev_id); + + void +-psplash_fb_draw_rect (PSplashFB *fb, +- int x, +- int y, +- int width, ++psplash_fb_draw_rect (PSplashFB *fb, ++ int x, ++ int y, ++ int width, + int height, + uint8 red, + uint8 green, + uint8 blue); + + void +-psplash_fb_draw_image (PSplashFB *fb, +- int x, +- int y, +- int img_width, ++psplash_fb_draw_image (PSplashFB *fb, ++ int x, ++ int y, ++ int img_width, + int img_height, + int img_bytes_pre_pixel, + int img_rowstride, +@@ -82,9 +82,9 @@ psplash_fb_text_size (int *width, + const char *text); + + void +-psplash_fb_draw_text (PSplashFB *fb, +- int x, +- int y, ++psplash_fb_draw_text (PSplashFB *fb, ++ int x, ++ int y, + uint8 red, + uint8 green, + uint8 blue, +diff --git a/psplash-write.c b/psplash-write.c +index a12467a..eee0ea3 100644 +--- a/psplash-write.c ++++ b/psplash-write.c +@@ -1,5 +1,5 @@ +-/* +- * pslash - a lightweight framebuffer splashscreen for embedded devices. ++/* ++ * pslash - a lightweight framebuffer splashscreen for embedded devices. + * + * Copyright (c) 2006 Matthew Allum + * +@@ -19,7 +19,7 @@ + #include + #include "psplash.h" + +-int main(int argc, char **argv) ++int main(int argc, char **argv) + { + char *rundir; + int pipe_fd; +@@ -29,17 +29,17 @@ int main(int argc, char **argv) + if (!rundir) + rundir = "/run"; + +- if (argc!=2) ++ if (argc!=2) + { + fprintf(stderr, "Wrong number of arguments\n"); + exit(-1); + } +- ++ + chdir(rundir); +- ++ + if ((pipe_fd = open (PSPLASH_FIFO,O_WRONLY|O_NONBLOCK)) == -1) + { +- /* Silently error out instead of covering the boot process in ++ /* Silently error out instead of covering the boot process in + errors when psplash has exitted due to a VC switch */ + /* perror("Error unable to open fifo"); */ + exit (-1); +diff --git a/psplash.c b/psplash.c +index ee1af6b..838ac13 100644 +--- a/psplash.c ++++ b/psplash.c +@@ -1,9 +1,9 @@ +-/* +- * pslash - a lightweight framebuffer splashscreen for embedded devices. ++/* ++ * pslash - a lightweight framebuffer splashscreen for embedded devices. + * + * Copyright (c) 2006 Matthew Allum + * +- * Parts of this file ( fifo handling ) based on 'usplash' copyright ++ * Parts of this file ( fifo handling ) based on 'usplash' copyright + * Matthew Garret. + * + * SPDX-License-Identifier: GPL-2.0-or-later +@@ -46,15 +46,15 @@ psplash_draw_msg (PSplashFB *fb, const char *msg) + + /* Clear */ + +- psplash_fb_draw_rect (fb, +- 0, +- SPLIT_LINE_POS(fb) - h, ++ psplash_fb_draw_rect (fb, ++ 0, ++ SPLIT_LINE_POS(fb) - h, + fb->width, + h, + PSPLASH_BACKGROUND_COLOR); + + psplash_fb_draw_text (fb, +- (fb->width-w)/2, ++ (fb->width-w)/2, + SPLIT_LINE_POS(fb) - h, + PSPLASH_TEXT_COLOR, + &FONT_DEF, +@@ -70,13 +70,13 @@ psplash_draw_progress (PSplashFB *fb, int value) + /* 4 pix border */ + x = ((fb->width - BAR_IMG_WIDTH)/2) + 4 ; + y = SPLIT_LINE_POS(fb) + 4; +- width = BAR_IMG_WIDTH - 8; ++ width = BAR_IMG_WIDTH - 8; + height = BAR_IMG_HEIGHT - 8; + + if (value > 0) + { + barwidth = (CLAMP(value,0,100) * width) / 100; +- psplash_fb_draw_rect (fb, x + barwidth, y, ++ psplash_fb_draw_rect (fb, x + barwidth, y, + width - barwidth, height, + PSPLASH_BAR_BACKGROUND_COLOR); + psplash_fb_draw_rect (fb, x, y, barwidth, +@@ -85,7 +85,7 @@ psplash_draw_progress (PSplashFB *fb, int value) + else + { + barwidth = (CLAMP(-value,0,100) * width) / 100; +- psplash_fb_draw_rect (fb, x, y, ++ psplash_fb_draw_rect (fb, x, y, + width - barwidth, height, + PSPLASH_BAR_BACKGROUND_COLOR); + psplash_fb_draw_rect (fb, x + width - barwidth, +@@ -93,18 +93,18 @@ psplash_draw_progress (PSplashFB *fb, int value) + PSPLASH_BAR_COLOR); + } + +- DBG("value: %i, width: %i, barwidth :%i\n", value, ++ DBG("value: %i, width: %i, barwidth :%i\n", value, + width, barwidth); + } + #endif /* PSPLASH_SHOW_PROGRESS_BAR */ + +-static int ++static int + parse_command (PSplashFB *fb, char *string) + { + char *command; + + DBG("got cmd %s", string); +- ++ + if (strcmp(string,"QUIT") == 0) + return 1; + +@@ -116,7 +116,7 @@ parse_command (PSplashFB *fb, char *string) + + if (arg) + psplash_draw_msg (fb, arg); +- } ++ } + #ifdef PSPLASH_SHOW_PROGRESS_BAR + else if (!strcmp(command,"PROGRESS")) + { +@@ -124,9 +124,9 @@ parse_command (PSplashFB *fb, char *string) + + if (arg) + psplash_draw_progress (fb, atoi(arg)); +- } ++ } + #endif +- else if (!strcmp(command,"QUIT")) ++ else if (!strcmp(command,"QUIT")) + { + return 1; + } +@@ -135,8 +135,8 @@ parse_command (PSplashFB *fb, char *string) + return 0; + } + +-void +-psplash_main (PSplashFB *fb, int pipe_fd, int timeout) ++void ++psplash_main (PSplashFB *fb, int pipe_fd, int timeout) + { + int err; + ssize_t length = 0; +@@ -154,14 +154,14 @@ psplash_main (PSplashFB *fb, int pipe_fd, int timeout) + + end = command; + +- while (1) ++ while (1) + { +- if (timeout != 0) ++ if (timeout != 0) + err = select(pipe_fd+1, &descriptors, NULL, NULL, &tv); + else + err = select(pipe_fd+1, &descriptors, NULL, NULL, NULL); +- +- if (err <= 0) ++ ++ if (err <= 0) + { + /* + if (errno == EINTR) +@@ -169,10 +169,10 @@ psplash_main (PSplashFB *fb, int pipe_fd, int timeout) + */ + return; + } +- ++ + length += read (pipe_fd, end, sizeof(command) - (end - command)); + +- if (length == 0) ++ if (length == 0) + { + /* Reopen to see if there's anything more for us */ + close(pipe_fd); +@@ -208,10 +208,10 @@ psplash_main (PSplashFB *fb, int pipe_fd, int timeout) + + out: + end = &command[length]; +- ++ + tv.tv_sec = timeout; + tv.tv_usec = 0; +- ++ + FD_ZERO(&descriptors); + FD_SET(pipe_fd,&descriptors); + } +@@ -219,8 +219,8 @@ psplash_main (PSplashFB *fb, int pipe_fd, int timeout) + return; + } + +-int +-main (int argc, char** argv) ++int ++main (int argc, char** argv) + { + char *rundir; + int pipe_fd, i = 0, angle = 0, fbdev_id = 0, ret = 0; +@@ -253,8 +253,8 @@ main (int argc, char** argv) + } + + fail: +- fprintf(stderr, +- "Usage: %s [-n|--no-console-switch][-a|--angle <0|90|180|270>][-f|--fbdev <0..9>]\n", ++ fprintf(stderr, ++ "Usage: %s [-n|--no-console-switch][-a|--angle <0|90|180|270>][-f|--fbdev <0..9>]\n", + argv[0]); + exit(-1); + } +@@ -268,7 +268,7 @@ main (int argc, char** argv) + + if (mkfifo(PSPLASH_FIFO, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) + { +- if (errno!=EEXIST) ++ if (errno!=EEXIST) + { + perror("mkfifo"); + exit(-1); +@@ -276,8 +276,8 @@ main (int argc, char** argv) + } + + pipe_fd = open (PSPLASH_FIFO,O_RDONLY|O_NONBLOCK); +- +- if (pipe_fd==-1) ++ ++ if (pipe_fd==-1) + { + perror("pipe open"); + exit(-2); +@@ -301,8 +301,8 @@ main (int argc, char** argv) + PSPLASH_BACKGROUND_COLOR); + + /* Draw the Poky logo */ +- psplash_fb_draw_image (fb, +- (fb->width - POKY_IMG_WIDTH)/2, ++ psplash_fb_draw_image (fb, ++ (fb->width - POKY_IMG_WIDTH)/2, + #if PSPLASH_IMG_FULLSCREEN + (fb->height - POKY_IMG_HEIGHT)/2, + #else +@@ -317,8 +317,8 @@ main (int argc, char** argv) + + #ifdef PSPLASH_SHOW_PROGRESS_BAR + /* Draw progress bar border */ +- psplash_fb_draw_image (fb, +- (fb->width - BAR_IMG_WIDTH)/2, ++ psplash_fb_draw_image (fb, ++ (fb->width - BAR_IMG_WIDTH)/2, + SPLIT_LINE_POS(fb), + BAR_IMG_WIDTH, + BAR_IMG_HEIGHT, +diff --git a/psplash.h b/psplash.h +index 9be44ba..e8b6660 100644 +--- a/psplash.h ++++ b/psplash.h +@@ -1,5 +1,5 @@ +-/* +- * pslash - a lightweight framebuffer splashscreen for embedded devices. ++/* ++ * pslash - a lightweight framebuffer splashscreen for embedded devices. + * + * Copyright (c) 2006 Matthew Allum + * +-- +2.25.1 + diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0003-Fix-unused-result-warnings.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0003-Fix-unused-result-warnings.patch new file mode 100644 index 00000000..948609d9 --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/files/0003-Fix-unused-result-warnings.patch @@ -0,0 +1,150 @@ +From edb01af9b4789b9c3b908329f6be5819e2cfe954 Mon Sep 17 00:00:00 2001 +From: Vasyl Vavrychuk +Date: Mon, 25 Apr 2022 10:59:42 +0300 +Subject: [PATCH 03/17] Fix 'unused-result' warnings + +This fixes warnings such as: + + ignoring return value of 'chdir', declared with attribute warn_unused_result [-Wunused-result] + +drm-backend backport from: +https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/ + +Signed-off-by: Vasyl Vavrychuk +--- + psplash-systemd.c | 36 +++++++++++++++++++++++++++++++++--- + psplash-write.c | 23 ++++++++++++++++++----- + psplash.c | 5 ++++- + 3 files changed, 55 insertions(+), 9 deletions(-) + +diff --git a/psplash-systemd.c b/psplash-systemd.c +index 840bd4e..dcf7e61 100644 +--- a/psplash-systemd.c ++++ b/psplash-systemd.c +@@ -32,6 +32,7 @@ int get_progress(void) + int r; + char buffer[20]; + int len; ++ ssize_t written; + + /* Connect to the system bus */ + r = sd_bus_new(&bus); +@@ -71,11 +72,36 @@ int get_progress(void) + current_progress = progress; + + len = snprintf(buffer, 20, "PROGRESS %d", (int)(current_progress * 100)); +- write(pipe_fd, buffer, len + 1); ++ written = write(pipe_fd, buffer, len + 1); ++ if (written == -1) { ++ /* EPIPE could mean that psplash detected boot complete sooner ++ then psplash-systemd and exited */ ++ if (errno != EPIPE) { ++ perror("write"); ++ r = -1; ++ goto finish; ++ } ++ } else if (written < len + 1) { ++ fprintf(stderr, "Wrote %zd bytes, less then expected %d bytes\n", ++ written, len + 1); ++ r = -1; ++ goto finish; ++ } + + if (progress == 1.0) { + printf("Systemd reported progress of 1.0, quit psplash.\n"); +- write(pipe_fd, "QUIT", 5); ++ written = write(pipe_fd, "QUIT", 5); ++ if (written == -1) { ++ /* EPIPE could mean that psplash detected boot complete ++ sooner then psplash-systemd and exited */ ++ if (errno != EPIPE) { ++ perror("write"); ++ r = -1; ++ goto finish; ++ } ++ } else if (written < 5) ++ fprintf(stderr, "Wrote %zd bytes, less then expected 5 bytes\n", ++ written); + r = -1; + } + +@@ -123,7 +149,11 @@ int main() + if (!rundir) + rundir = "/run"; + +- chdir(rundir); ++ r = chdir(rundir); ++ if (r < 0) { ++ perror("chdir"); ++ goto finish; ++ } + + if ((pipe_fd = open (PSPLASH_FIFO,O_WRONLY|O_NONBLOCK)) == -1) { + fprintf(stderr, "Error unable to open fifo"); +diff --git a/psplash-write.c b/psplash-write.c +index eee0ea3..16b87e1 100644 +--- a/psplash-write.c ++++ b/psplash-write.c +@@ -21,8 +21,10 @@ + + int main(int argc, char **argv) + { +- char *rundir; +- int pipe_fd; ++ char *rundir; ++ int pipe_fd; ++ size_t count; ++ ssize_t written; + + rundir = getenv("PSPLASH_FIFO_DIR"); + +@@ -35,7 +37,10 @@ int main(int argc, char **argv) + exit(-1); + } + +- chdir(rundir); ++ if (chdir(rundir)) { ++ perror("chdir"); ++ exit(-1); ++ } + + if ((pipe_fd = open (PSPLASH_FIFO,O_WRONLY|O_NONBLOCK)) == -1) + { +@@ -45,8 +50,16 @@ int main(int argc, char **argv) + exit (-1); + } + +- write(pipe_fd, argv[1], strlen(argv[1])+1); ++ count = strlen(argv[1]) + 1; ++ written = write(pipe_fd, argv[1], count); ++ if (written == -1) { ++ perror("write"); ++ exit(-1); ++ } else if ((size_t)written < count) { ++ fprintf(stderr, "Wrote %zd bytes, less then expected %zu bytes\n", ++ written, count); ++ exit(-1); ++ } + + return 0; + } +- +diff --git a/psplash.c b/psplash.c +index 838ac13..62244ba 100644 +--- a/psplash.c ++++ b/psplash.c +@@ -264,7 +264,10 @@ main (int argc, char** argv) + if (!rundir) + rundir = "/run"; + +- chdir(rundir); ++ if (chdir(rundir)) { ++ perror("chdir"); ++ exit(-1); ++ } + + if (mkfifo(PSPLASH_FIFO, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) + { +-- +2.25.1 + diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0004-Remove-unused-save_termios.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0004-Remove-unused-save_termios.patch new file mode 100644 index 00000000..7c105ea0 --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/files/0004-Remove-unused-save_termios.patch @@ -0,0 +1,41 @@ +From 733b6d8ae3ed8d5d2972c717bb9a94f65ff6f194 Mon Sep 17 00:00:00 2001 +From: Vasyl Vavrychuk +Date: Mon, 25 Apr 2022 10:59:43 +0300 +Subject: [PATCH 04/17] Remove unused save_termios + +drm-backend backport from: +https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/ + +Signed-off-by: Vasyl Vavrychuk +--- + psplash-fb.h | 1 - + psplash.h | 1 - + 2 files changed, 2 deletions(-) + +diff --git a/psplash-fb.h b/psplash-fb.h +index eafa293..6c4599c 100644 +--- a/psplash-fb.h ++++ b/psplash-fb.h +@@ -22,7 +22,6 @@ typedef struct PSplashFB + { + int fd; + struct fb_var_screeninfo fb_var; +- struct termios save_termios; + int type; + int visual; + int width, height; +diff --git a/psplash.h b/psplash.h +index e8b6660..02d6f32 100644 +--- a/psplash.h ++++ b/psplash.h +@@ -32,7 +32,6 @@ + #include + #include + #include +-#include + #include + #include + +-- +2.25.1 + diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0005-Remove-psplash-fb.h-from-psplash.h.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0005-Remove-psplash-fb.h-from-psplash.h.patch new file mode 100644 index 00000000..602d703e --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/files/0005-Remove-psplash-fb.h-from-psplash.h.patch @@ -0,0 +1,81 @@ +From 2f1fe1b5233d69cf354ffb5ab182810ef74c7e3d Mon Sep 17 00:00:00 2001 +From: Vasyl Vavrychuk +Date: Mon, 25 Apr 2022 10:59:44 +0300 +Subject: [PATCH 05/17] Remove 'psplash-fb.h' from 'psplash.h' + +psplash might not be necessary based on framebuffer, it could use DRM +in future too. + +drm-backend backport from: +https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/ + +Signed-off-by: Vasyl Vavrychuk +--- + psplash-fb.c | 2 +- + psplash-fb.h | 3 +++ + psplash.c | 1 + + psplash.h | 2 -- + 4 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/psplash-fb.c b/psplash-fb.c +index 1d2d7db..5dea82a 100644 +--- a/psplash-fb.c ++++ b/psplash-fb.c +@@ -8,7 +8,7 @@ + */ + + #include +-#include "psplash.h" ++#include "psplash-fb.h" + + static void + psplash_wait_for_vsync(PSplashFB *fb) +diff --git a/psplash-fb.h b/psplash-fb.h +index 6c4599c..4d5c460 100644 +--- a/psplash-fb.h ++++ b/psplash-fb.h +@@ -10,6 +10,9 @@ + #ifndef _HAVE_PSPLASH_FB_H + #define _HAVE_PSPLASH_FB_H + ++#include ++#include "psplash.h" ++ + enum RGBMode { + RGB565, + BGR565, +diff --git a/psplash.c b/psplash.c +index 62244ba..18c012b 100644 +--- a/psplash.c ++++ b/psplash.c +@@ -11,6 +11,7 @@ + */ + + #include "psplash.h" ++#include "psplash-fb.h" + #include "psplash-config.h" + #include "psplash-colors.h" + #include "psplash-poky-img.h" +diff --git a/psplash.h b/psplash.h +index 02d6f32..ab8e53f 100644 +--- a/psplash.h ++++ b/psplash.h +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -78,7 +77,6 @@ typedef struct PSplashFont + PSplashFont; + + +-#include "psplash-fb.h" + #include "psplash-console.h" + + #endif +-- +2.25.1 + diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0006-Extract-plot-pixel-from-psplash-fb.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0006-Extract-plot-pixel-from-psplash-fb.patch new file mode 100644 index 00000000..5627d5e5 --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/files/0006-Extract-plot-pixel-from-psplash-fb.patch @@ -0,0 +1,624 @@ +From f0504ac0abd16b5e98456fb3ea2777e6b64418ec Mon Sep 17 00:00:00 2001 +From: Vasyl Vavrychuk +Date: Mon, 25 Apr 2022 10:59:45 +0300 +Subject: [PATCH 06/17] Extract plot pixel from psplash-fb + +psplash_fb_plot_pixel is in fact framebuffer independent. + +drm-backend backport from: +https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/ + +Signed-off-by: Vasyl Vavrychuk +--- + Makefile.am | 3 +- + psplash-draw.c | 120 +++++++++++++++++++++++++++++++ + psplash-draw.h | 51 +++++++++++++ + psplash-fb.c | 191 +++++++++++-------------------------------------- + psplash-fb.h | 25 ++----- + psplash.c | 20 +++--- + 6 files changed, 229 insertions(+), 181 deletions(-) + create mode 100644 psplash-draw.c + create mode 100644 psplash-draw.h + +diff --git a/Makefile.am b/Makefile.am +index 310e126..375b926 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -5,7 +5,8 @@ AM_CFLAGS = $(GCC_FLAGS) $(EXTRA_GCC_FLAGS) -D_GNU_SOURCE -DFONT_HEADER=\"$(FONT + psplash_SOURCES = psplash.c psplash.h psplash-fb.c psplash-fb.h \ + psplash-console.c psplash-console.h \ + psplash-colors.h psplash-config.h \ +- psplash-poky-img.h psplash-bar-img.h $(FONT_NAME)-font.h ++ psplash-poky-img.h psplash-bar-img.h $(FONT_NAME)-font.h \ ++ psplash-draw.c psplash-draw.h + BUILT_SOURCES = psplash-poky-img.h psplash-bar-img.h + + psplash_write_SOURCES = psplash-write.c psplash.h +diff --git a/psplash-draw.c b/psplash-draw.c +new file mode 100644 +index 0000000..570cfce +--- /dev/null ++++ b/psplash-draw.c +@@ -0,0 +1,120 @@ ++/* ++ * pslash - a lightweight framebuffer splashscreen for embedded devices. ++ * ++ * Copyright (c) 2006 Matthew Allum ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ * ++ */ ++ ++#include "psplash-draw.h" ++ ++#define OFFSET(canvas, x, y) (((y) * (canvas)->stride) + ((x) * ((canvas)->bpp >> 3))) ++ ++/* TODO: change to 'static inline' as psplash_fb_plot_pixel was before */ ++void ++psplash_plot_pixel(PSplashCanvas *canvas, ++ int x, ++ int y, ++ uint8 red, ++ uint8 green, ++ uint8 blue) ++{ ++ /* Always write to back data (data) which points to the right data with or ++ * without double buffering support */ ++ int off; ++ ++ if (x < 0 || x > canvas->width-1 || y < 0 || y > canvas->height-1) ++ return; ++ ++ switch (canvas->angle) ++ { ++ case 270: ++ off = OFFSET (canvas, canvas->height - y - 1, x); ++ break; ++ case 180: ++ off = OFFSET (canvas, canvas->width - x - 1, canvas->height - y - 1); ++ break; ++ case 90: ++ off = OFFSET (canvas, y, canvas->width - x - 1); ++ break; ++ case 0: ++ default: ++ off = OFFSET (canvas, x, y); ++ break; ++ } ++ ++ if (canvas->rgbmode == RGB565 || canvas->rgbmode == RGB888) { ++ switch (canvas->bpp) ++ { ++ case 24: ++#if __BYTE_ORDER == __BIG_ENDIAN ++ *(canvas->data + off + 0) = red; ++ *(canvas->data + off + 1) = green; ++ *(canvas->data + off + 2) = blue; ++#else ++ *(canvas->data + off + 0) = blue; ++ *(canvas->data + off + 1) = green; ++ *(canvas->data + off + 2) = red; ++#endif ++ break; ++ case 32: ++ *(volatile uint32_t *) (canvas->data + off) ++ = (red << 16) | (green << 8) | (blue); ++ break; ++ ++ case 16: ++ *(volatile uint16_t *) (canvas->data + off) ++ = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3); ++ break; ++ default: ++ /* depth not supported yet */ ++ break; ++ } ++ } else if (canvas->rgbmode == BGR565 || canvas->rgbmode == BGR888) { ++ switch (canvas->bpp) ++ { ++ case 24: ++#if __BYTE_ORDER == __BIG_ENDIAN ++ *(canvas->data + off + 0) = blue; ++ *(canvas->data + off + 1) = green; ++ *(canvas->data + off + 2) = red; ++#else ++ *(canvas->data + off + 0) = red; ++ *(canvas->data + off + 1) = green; ++ *(canvas->data + off + 2) = blue; ++#endif ++ break; ++ case 32: ++ *(volatile uint32_t *) (canvas->data + off) ++ = (blue << 16) | (green << 8) | (red); ++ break; ++ case 16: ++ *(volatile uint16_t *) (canvas->data + off) ++ = ((blue >> 3) << 11) | ((green >> 2) << 5) | (red >> 3); ++ break; ++ default: ++ /* depth not supported yet */ ++ break; ++ } ++ } else { ++ switch (canvas->bpp) ++ { ++ case 32: ++ *(volatile uint32_t *) (canvas->data + off) ++ = ((red >> (8 - canvas->red_length)) << canvas->red_offset) ++ | ((green >> (8 - canvas->green_length)) << canvas->green_offset) ++ | ((blue >> (8 - canvas->blue_length)) << canvas->blue_offset); ++ break; ++ case 16: ++ *(volatile uint16_t *) (canvas->data + off) ++ = ((red >> (8 - canvas->red_length)) << canvas->red_offset) ++ | ((green >> (8 - canvas->green_length)) << canvas->green_offset) ++ | ((blue >> (8 - canvas->blue_length)) << canvas->blue_offset); ++ break; ++ default: ++ /* depth not supported yet */ ++ break; ++ } ++ } ++} +diff --git a/psplash-draw.h b/psplash-draw.h +new file mode 100644 +index 0000000..ab2d4d2 +--- /dev/null ++++ b/psplash-draw.h +@@ -0,0 +1,51 @@ ++/* ++ * pslash - a lightweight framebuffer splashscreen for embedded devices. ++ * ++ * Copyright (c) 2006 Matthew Allum ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ * ++ */ ++ ++#ifndef _HAVE_PSPLASH_CANVAS_H ++#define _HAVE_PSPLASH_CANVAS_H ++ ++#include "psplash.h" ++ ++enum RGBMode { ++ RGB565, ++ BGR565, ++ RGB888, ++ BGR888, ++ GENERIC, ++}; ++ ++typedef struct PSplashCanvas ++{ ++ int width, height; ++ int bpp; ++ int stride; ++ char *data; ++ ++ int angle; ++ ++ enum RGBMode rgbmode; ++ int red_offset; ++ int red_length; ++ int green_offset; ++ int green_length; ++ int blue_offset; ++ int blue_length; ++} ++PSplashCanvas; ++ ++/* TODO: Remove after rest of drawing functions migrated to psplash-draw.c */ ++void ++psplash_plot_pixel(PSplashCanvas *canvas, ++ int x, ++ int y, ++ uint8 red, ++ uint8 green, ++ uint8 blue); ++ ++#endif +diff --git a/psplash-fb.c b/psplash-fb.c +index 5dea82a..a7029c5 100644 +--- a/psplash-fb.c ++++ b/psplash-fb.c +@@ -42,10 +42,11 @@ psplash_fb_flip(PSplashFB *fb, int sync) + tmp = fb->fdata; + fb->fdata = fb->bdata; + fb->bdata = tmp; ++ fb->canvas.data = fb->bdata; + + /* Sync new front to new back when requested */ + if (sync) { +- memcpy(fb->bdata, fb->fdata, fb->stride * fb->real_height); ++ memcpy(fb->bdata, fb->fdata, fb->canvas.stride * fb->real_height); + } + } + } +@@ -220,42 +221,42 @@ psplash_fb_new (int angle, int fbdev_id) + } + } + +- fb->real_width = fb->width = fb_var.xres; +- fb->real_height = fb->height = fb_var.yres; +- fb->bpp = fb_var.bits_per_pixel; +- fb->stride = fb_fix.line_length; ++ fb->real_width = fb->canvas.width = fb_var.xres; ++ fb->real_height = fb->canvas.height = fb_var.yres; ++ fb->canvas.bpp = fb_var.bits_per_pixel; ++ fb->canvas.stride = fb_fix.line_length; + fb->type = fb_fix.type; + fb->visual = fb_fix.visual; + +- fb->red_offset = fb_var.red.offset; +- fb->red_length = fb_var.red.length; +- fb->green_offset = fb_var.green.offset; +- fb->green_length = fb_var.green.length; +- fb->blue_offset = fb_var.blue.offset; +- fb->blue_length = fb_var.blue.length; +- +- if (fb->red_offset == 11 && fb->red_length == 5 && +- fb->green_offset == 5 && fb->green_length == 6 && +- fb->blue_offset == 0 && fb->blue_length == 5) { +- fb->rgbmode = RGB565; +- } else if (fb->red_offset == 0 && fb->red_length == 5 && +- fb->green_offset == 5 && fb->green_length == 6 && +- fb->blue_offset == 11 && fb->blue_length == 5) { +- fb->rgbmode = BGR565; +- } else if (fb->red_offset == 16 && fb->red_length == 8 && +- fb->green_offset == 8 && fb->green_length == 8 && +- fb->blue_offset == 0 && fb->blue_length == 8) { +- fb->rgbmode = RGB888; +- } else if (fb->red_offset == 0 && fb->red_length == 8 && +- fb->green_offset == 8 && fb->green_length == 8 && +- fb->blue_offset == 16 && fb->blue_length == 8) { +- fb->rgbmode = BGR888; ++ fb->canvas.red_offset = fb_var.red.offset; ++ fb->canvas.red_length = fb_var.red.length; ++ fb->canvas.green_offset = fb_var.green.offset; ++ fb->canvas.green_length = fb_var.green.length; ++ fb->canvas.blue_offset = fb_var.blue.offset; ++ fb->canvas.blue_length = fb_var.blue.length; ++ ++ if (fb->canvas.red_offset == 11 && fb->canvas.red_length == 5 && ++ fb->canvas.green_offset == 5 && fb->canvas.green_length == 6 && ++ fb->canvas.blue_offset == 0 && fb->canvas.blue_length == 5) { ++ fb->canvas.rgbmode = RGB565; ++ } else if (fb->canvas.red_offset == 0 && fb->canvas.red_length == 5 && ++ fb->canvas.green_offset == 5 && fb->canvas.green_length == 6 && ++ fb->canvas.blue_offset == 11 && fb->canvas.blue_length == 5) { ++ fb->canvas.rgbmode = BGR565; ++ } else if (fb->canvas.red_offset == 16 && fb->canvas.red_length == 8 && ++ fb->canvas.green_offset == 8 && fb->canvas.green_length == 8 && ++ fb->canvas.blue_offset == 0 && fb->canvas.blue_length == 8) { ++ fb->canvas.rgbmode = RGB888; ++ } else if (fb->canvas.red_offset == 0 && fb->canvas.red_length == 8 && ++ fb->canvas.green_offset == 8 && fb->canvas.green_length == 8 && ++ fb->canvas.blue_offset == 16 && fb->canvas.blue_length == 8) { ++ fb->canvas.rgbmode = BGR888; + } else { +- fb->rgbmode = GENERIC; ++ fb->canvas.rgbmode = GENERIC; + } + + DBG("width: %i, height: %i, bpp: %i, stride: %i", +- fb->width, fb->height, fb->bpp, fb->stride); ++ fb->canvas.width, fb->canvas.height, fb->canvas.bpp, fb->canvas.stride); + + fb->base = (char *) mmap ((caddr_t) NULL, + fb_fix.smem_len, +@@ -279,16 +280,17 @@ psplash_fb_new (int angle, int fbdev_id) + if (fb->fb_var.yoffset == 0) { + printf("to back\n"); + fb->fdata = fb->data; +- fb->bdata = fb->data + fb->stride * fb->height; ++ fb->bdata = fb->data + fb->canvas.stride * fb->canvas.height; + } else { + printf("to front\n"); +- fb->fdata = fb->data + fb->stride * fb->height; ++ fb->fdata = fb->data + fb->canvas.stride * fb->canvas.height; + fb->bdata = fb->data; + } + } else { + fb->fdata = fb->data; + fb->bdata = fb->data; + } ++ fb->canvas.data = fb->bdata; + + #if 0 + /* FIXME: No support for 8pp as yet */ +@@ -312,14 +314,14 @@ psplash_fb_new (int angle, int fbdev_id) + status = 2; + #endif + +- fb->angle = angle; ++ fb->canvas.angle = angle; + +- switch (fb->angle) ++ switch (angle) + { + case 270: + case 90: +- fb->width = fb->real_height; +- fb->height = fb->real_width; ++ fb->canvas.width = fb->real_height; ++ fb->canvas.height = fb->real_width; + break; + case 180: + case 0: +@@ -337,115 +339,6 @@ psplash_fb_new (int angle, int fbdev_id) + return NULL; + } + +-#define OFFSET(fb,x,y) (((y) * (fb)->stride) + ((x) * ((fb)->bpp >> 3))) +- +-static inline void +-psplash_fb_plot_pixel (PSplashFB *fb, +- int x, +- int y, +- uint8 red, +- uint8 green, +- uint8 blue) +-{ +- /* Always write to back data (bdata) which points to the right data with or +- * without double buffering support */ +- int off; +- +- if (x < 0 || x > fb->width-1 || y < 0 || y > fb->height-1) +- return; +- +- switch (fb->angle) +- { +- case 270: +- off = OFFSET (fb, fb->height - y - 1, x); +- break; +- case 180: +- off = OFFSET (fb, fb->width - x - 1, fb->height - y - 1); +- break; +- case 90: +- off = OFFSET (fb, y, fb->width - x - 1); +- break; +- case 0: +- default: +- off = OFFSET (fb, x, y); +- break; +- } +- +- if (fb->rgbmode == RGB565 || fb->rgbmode == RGB888) { +- switch (fb->bpp) +- { +- case 24: +-#if __BYTE_ORDER == __BIG_ENDIAN +- *(fb->bdata + off + 0) = red; +- *(fb->bdata + off + 1) = green; +- *(fb->bdata + off + 2) = blue; +-#else +- *(fb->bdata + off + 0) = blue; +- *(fb->bdata + off + 1) = green; +- *(fb->bdata + off + 2) = red; +-#endif +- break; +- case 32: +- *(volatile uint32_t *) (fb->bdata + off) +- = (red << 16) | (green << 8) | (blue); +- break; +- +- case 16: +- *(volatile uint16_t *) (fb->bdata + off) +- = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3); +- break; +- default: +- /* depth not supported yet */ +- break; +- } +- } else if (fb->rgbmode == BGR565 || fb->rgbmode == BGR888) { +- switch (fb->bpp) +- { +- case 24: +-#if __BYTE_ORDER == __BIG_ENDIAN +- *(fb->bdata + off + 0) = blue; +- *(fb->bdata + off + 1) = green; +- *(fb->bdata + off + 2) = red; +-#else +- *(fb->bdata + off + 0) = red; +- *(fb->bdata + off + 1) = green; +- *(fb->bdata + off + 2) = blue; +-#endif +- break; +- case 32: +- *(volatile uint32_t *) (fb->bdata + off) +- = (blue << 16) | (green << 8) | (red); +- break; +- case 16: +- *(volatile uint16_t *) (fb->bdata + off) +- = ((blue >> 3) << 11) | ((green >> 2) << 5) | (red >> 3); +- break; +- default: +- /* depth not supported yet */ +- break; +- } +- } else { +- switch (fb->bpp) +- { +- case 32: +- *(volatile uint32_t *) (fb->bdata + off) +- = ((red >> (8 - fb->red_length)) << fb->red_offset) +- | ((green >> (8 - fb->green_length)) << fb->green_offset) +- | ((blue >> (8 - fb->blue_length)) << fb->blue_offset); +- break; +- case 16: +- *(volatile uint16_t *) (fb->bdata + off) +- = ((red >> (8 - fb->red_length)) << fb->red_offset) +- | ((green >> (8 - fb->green_length)) << fb->green_offset) +- | ((blue >> (8 - fb->blue_length)) << fb->blue_offset); +- break; +- default: +- /* depth not supported yet */ +- break; +- } +- } +-} +- + void + psplash_fb_draw_rect (PSplashFB *fb, + int x, +@@ -460,7 +353,7 @@ psplash_fb_draw_rect (PSplashFB *fb, + + for (dy=0; dy < height; dy++) + for (dx=0; dx < width; dx++) +- psplash_fb_plot_pixel (fb, x+dx, y+dy, red, green, blue); ++ psplash_plot_pixel(&fb->canvas, x+dx, y+dy, red, green, blue); + } + + void +@@ -493,7 +386,7 @@ psplash_fb_draw_image (PSplashFB *fb, + do + { + if ((img_bytes_per_pixel < 4 || *(p+3)) && dx < img_width) +- psplash_fb_plot_pixel (fb, x+dx, y+dy, *(p), *(p+1), *(p+2)); ++ psplash_plot_pixel(&fb->canvas, x+dx, y+dy, *(p), *(p+1), *(p+2)); + if (++dx * img_bytes_per_pixel >= img_rowstride) { dx=0; dy++; } + } + while (--len); +@@ -507,7 +400,7 @@ psplash_fb_draw_image (PSplashFB *fb, + do + { + if ((img_bytes_per_pixel < 4 || *(p+3)) && dx < img_width) +- psplash_fb_plot_pixel (fb, x+dx, y+dy, *(p), *(p+1), *(p+2)); ++ psplash_plot_pixel(&fb->canvas, x+dx, y+dy, *(p), *(p+1), *(p+2)); + if (++dx * img_bytes_per_pixel >= img_rowstride) { dx=0; dy++; } + p += img_bytes_per_pixel; + } +@@ -613,7 +506,7 @@ psplash_fb_draw_text (PSplashFB *fb, + for (cx = 0; cx < w; cx++) + { + if (g & 0x80000000) +- psplash_fb_plot_pixel (fb, x+dx+cx, y+dy+cy, ++ psplash_plot_pixel(&fb->canvas, x+dx+cx, y+dy+cy, + red, green, blue); + g <<= 1; + } +diff --git a/psplash-fb.h b/psplash-fb.h +index 4d5c460..eb02c62 100644 +--- a/psplash-fb.h ++++ b/psplash-fb.h +@@ -11,25 +11,16 @@ + #define _HAVE_PSPLASH_FB_H + + #include +-#include "psplash.h" +- +-enum RGBMode { +- RGB565, +- BGR565, +- RGB888, +- BGR888, +- GENERIC, +-}; ++#include "psplash-draw.h" + + typedef struct PSplashFB + { ++ PSplashCanvas canvas; ++ + int fd; + struct fb_var_screeninfo fb_var; + int type; + int visual; +- int width, height; +- int bpp; +- int stride; + char *data; + char *base; + +@@ -38,16 +29,8 @@ typedef struct PSplashFB + char *bdata; + char *fdata; + +- int angle, fbdev_id; ++ int fbdev_id; + int real_width, real_height; +- +- enum RGBMode rgbmode; +- int red_offset; +- int red_length; +- int green_offset; +- int green_length; +- int blue_offset; +- int blue_length; + } + PSplashFB; + +diff --git a/psplash.c b/psplash.c +index 18c012b..f23f03d 100644 +--- a/psplash.c ++++ b/psplash.c +@@ -22,10 +22,10 @@ + #include FONT_HEADER + + #define SPLIT_LINE_POS(fb) \ +- ( (fb)->height \ ++ ( (fb)->canvas.height \ + - (( PSPLASH_IMG_SPLIT_DENOMINATOR \ + - PSPLASH_IMG_SPLIT_NUMERATOR) \ +- * (fb)->height / PSPLASH_IMG_SPLIT_DENOMINATOR) \ ++ * (fb)->canvas.height / PSPLASH_IMG_SPLIT_DENOMINATOR) \ + ) + + void +@@ -50,12 +50,12 @@ psplash_draw_msg (PSplashFB *fb, const char *msg) + psplash_fb_draw_rect (fb, + 0, + SPLIT_LINE_POS(fb) - h, +- fb->width, ++ fb->canvas.width, + h, + PSPLASH_BACKGROUND_COLOR); + + psplash_fb_draw_text (fb, +- (fb->width-w)/2, ++ (fb->canvas.width-w)/2, + SPLIT_LINE_POS(fb) - h, + PSPLASH_TEXT_COLOR, + &FONT_DEF, +@@ -69,7 +69,7 @@ psplash_draw_progress (PSplashFB *fb, int value) + int x, y, width, height, barwidth; + + /* 4 pix border */ +- x = ((fb->width - BAR_IMG_WIDTH)/2) + 4 ; ++ x = ((fb->canvas.width - BAR_IMG_WIDTH)/2) + 4 ; + y = SPLIT_LINE_POS(fb) + 4; + width = BAR_IMG_WIDTH - 8; + height = BAR_IMG_HEIGHT - 8; +@@ -301,16 +301,16 @@ main (int argc, char** argv) + #endif + + /* Clear the background with #ecece1 */ +- psplash_fb_draw_rect (fb, 0, 0, fb->width, fb->height, ++ psplash_fb_draw_rect (fb, 0, 0, fb->canvas.width, fb->canvas.height, + PSPLASH_BACKGROUND_COLOR); + + /* Draw the Poky logo */ + psplash_fb_draw_image (fb, +- (fb->width - POKY_IMG_WIDTH)/2, ++ (fb->canvas.width - POKY_IMG_WIDTH)/2, + #if PSPLASH_IMG_FULLSCREEN +- (fb->height - POKY_IMG_HEIGHT)/2, ++ (fb->canvas.height - POKY_IMG_HEIGHT)/2, + #else +- (fb->height * PSPLASH_IMG_SPLIT_NUMERATOR ++ (fb->canvas.height * PSPLASH_IMG_SPLIT_NUMERATOR + / PSPLASH_IMG_SPLIT_DENOMINATOR - POKY_IMG_HEIGHT)/2, + #endif + POKY_IMG_WIDTH, +@@ -322,7 +322,7 @@ main (int argc, char** argv) + #ifdef PSPLASH_SHOW_PROGRESS_BAR + /* Draw progress bar border */ + psplash_fb_draw_image (fb, +- (fb->width - BAR_IMG_WIDTH)/2, ++ (fb->canvas.width - BAR_IMG_WIDTH)/2, + SPLIT_LINE_POS(fb), + BAR_IMG_WIDTH, + BAR_IMG_HEIGHT, +-- +2.25.1 + diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0007-Extract-draw-rect-image-from-psplash-fb.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0007-Extract-draw-rect-image-from-psplash-fb.patch new file mode 100644 index 00000000..2e897d4c --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/files/0007-Extract-draw-rect-image-from-psplash-fb.patch @@ -0,0 +1,299 @@ +From d0f899114600ee25eb2d7d2c089deb549c371bd2 Mon Sep 17 00:00:00 2001 +From: Vasyl Vavrychuk +Date: Mon, 25 Apr 2022 10:59:46 +0300 +Subject: [PATCH 07/17] Extract draw rect/image from psplash-fb + +drm-backend backport from: +https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/ + +Signed-off-by: Vasyl Vavrychuk +--- + psplash-draw.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++ + psplash-draw.h | 20 +++++++++++++++ + psplash-fb.c | 70 -------------------------------------------------- + psplash-fb.h | 20 --------------- + psplash.c | 16 ++++++------ + 5 files changed, 98 insertions(+), 98 deletions(-) + +diff --git a/psplash-draw.c b/psplash-draw.c +index 570cfce..6887e22 100644 +--- a/psplash-draw.c ++++ b/psplash-draw.c +@@ -118,3 +118,73 @@ psplash_plot_pixel(PSplashCanvas *canvas, + } + } + } ++ ++void ++psplash_draw_rect(PSplashCanvas *canvas, ++ int x, ++ int y, ++ int width, ++ int height, ++ uint8 red, ++ uint8 green, ++ uint8 blue) ++{ ++ int dx, dy; ++ ++ for (dy=0; dy < height; dy++) ++ for (dx=0; dx < width; dx++) ++ psplash_plot_pixel(canvas, x+dx, y+dy, red, green, blue); ++} ++ ++void ++psplash_draw_image(PSplashCanvas *canvas, ++ int x, ++ int y, ++ int img_width, ++ int img_height, ++ int img_bytes_per_pixel, ++ int img_rowstride, ++ uint8 *rle_data) ++{ ++ uint8 *p = rle_data; ++ int dx = 0, dy = 0, total_len; ++ unsigned int len; ++ ++ total_len = img_rowstride * img_height; ++ ++ /* FIXME: Optimise, check for over runs ... */ ++ while ((p - rle_data) < total_len) ++ { ++ len = *(p++); ++ ++ if (len & 128) ++ { ++ len -= 128; ++ ++ if (len == 0) break; ++ ++ do ++ { ++ if ((img_bytes_per_pixel < 4 || *(p+3)) && dx < img_width) ++ psplash_plot_pixel(canvas, x+dx, y+dy, *(p), *(p+1), *(p+2)); ++ if (++dx * img_bytes_per_pixel >= img_rowstride) { dx=0; dy++; } ++ } ++ while (--len); ++ ++ p += img_bytes_per_pixel; ++ } ++ else ++ { ++ if (len == 0) break; ++ ++ do ++ { ++ if ((img_bytes_per_pixel < 4 || *(p+3)) && dx < img_width) ++ psplash_plot_pixel(canvas, x+dx, y+dy, *(p), *(p+1), *(p+2)); ++ if (++dx * img_bytes_per_pixel >= img_rowstride) { dx=0; dy++; } ++ p += img_bytes_per_pixel; ++ } ++ while (--len && (p - rle_data) < total_len); ++ } ++ } ++} +diff --git a/psplash-draw.h b/psplash-draw.h +index ab2d4d2..f8361da 100644 +--- a/psplash-draw.h ++++ b/psplash-draw.h +@@ -48,4 +48,24 @@ psplash_plot_pixel(PSplashCanvas *canvas, + uint8 green, + uint8 blue); + ++void ++psplash_draw_rect(PSplashCanvas *canvas, ++ int x, ++ int y, ++ int width, ++ int height, ++ uint8 red, ++ uint8 green, ++ uint8 blue); ++ ++void ++psplash_draw_image(PSplashCanvas *canvas, ++ int x, ++ int y, ++ int img_width, ++ int img_height, ++ int img_bytes_per_pixel, ++ int img_rowstride, ++ uint8 *rle_data); ++ + #endif +diff --git a/psplash-fb.c b/psplash-fb.c +index a7029c5..07839d5 100644 +--- a/psplash-fb.c ++++ b/psplash-fb.c +@@ -339,76 +339,6 @@ psplash_fb_new (int angle, int fbdev_id) + return NULL; + } + +-void +-psplash_fb_draw_rect (PSplashFB *fb, +- int x, +- int y, +- int width, +- int height, +- uint8 red, +- uint8 green, +- uint8 blue) +-{ +- int dx, dy; +- +- for (dy=0; dy < height; dy++) +- for (dx=0; dx < width; dx++) +- psplash_plot_pixel(&fb->canvas, x+dx, y+dy, red, green, blue); +-} +- +-void +-psplash_fb_draw_image (PSplashFB *fb, +- int x, +- int y, +- int img_width, +- int img_height, +- int img_bytes_per_pixel, +- int img_rowstride, +- uint8 *rle_data) +-{ +- uint8 *p = rle_data; +- int dx = 0, dy = 0, total_len; +- unsigned int len; +- +- total_len = img_rowstride * img_height; +- +- /* FIXME: Optimise, check for over runs ... */ +- while ((p - rle_data) < total_len) +- { +- len = *(p++); +- +- if (len & 128) +- { +- len -= 128; +- +- if (len == 0) break; +- +- do +- { +- if ((img_bytes_per_pixel < 4 || *(p+3)) && dx < img_width) +- psplash_plot_pixel(&fb->canvas, x+dx, y+dy, *(p), *(p+1), *(p+2)); +- if (++dx * img_bytes_per_pixel >= img_rowstride) { dx=0; dy++; } +- } +- while (--len); +- +- p += img_bytes_per_pixel; +- } +- else +- { +- if (len == 0) break; +- +- do +- { +- if ((img_bytes_per_pixel < 4 || *(p+3)) && dx < img_width) +- psplash_plot_pixel(&fb->canvas, x+dx, y+dy, *(p), *(p+1), *(p+2)); +- if (++dx * img_bytes_per_pixel >= img_rowstride) { dx=0; dy++; } +- p += img_bytes_per_pixel; +- } +- while (--len && (p - rle_data) < total_len); +- } +- } +-} +- + /* Font rendering code based on BOGL by Ben Pfaff */ + + static int +diff --git a/psplash-fb.h b/psplash-fb.h +index eb02c62..1eecb47 100644 +--- a/psplash-fb.h ++++ b/psplash-fb.h +@@ -40,26 +40,6 @@ psplash_fb_destroy (PSplashFB *fb); + PSplashFB* + psplash_fb_new (int angle, int fbdev_id); + +-void +-psplash_fb_draw_rect (PSplashFB *fb, +- int x, +- int y, +- int width, +- int height, +- uint8 red, +- uint8 green, +- uint8 blue); +- +-void +-psplash_fb_draw_image (PSplashFB *fb, +- int x, +- int y, +- int img_width, +- int img_height, +- int img_bytes_pre_pixel, +- int img_rowstride, +- uint8 *rle_data); +- + void + psplash_fb_text_size (int *width, + int *height, +diff --git a/psplash.c b/psplash.c +index f23f03d..2aeb583 100644 +--- a/psplash.c ++++ b/psplash.c +@@ -47,7 +47,7 @@ psplash_draw_msg (PSplashFB *fb, const char *msg) + + /* Clear */ + +- psplash_fb_draw_rect (fb, ++ psplash_draw_rect(&fb->canvas, + 0, + SPLIT_LINE_POS(fb) - h, + fb->canvas.width, +@@ -77,19 +77,19 @@ psplash_draw_progress (PSplashFB *fb, int value) + if (value > 0) + { + barwidth = (CLAMP(value,0,100) * width) / 100; +- psplash_fb_draw_rect (fb, x + barwidth, y, ++ psplash_draw_rect(&fb->canvas, x + barwidth, y, + width - barwidth, height, + PSPLASH_BAR_BACKGROUND_COLOR); +- psplash_fb_draw_rect (fb, x, y, barwidth, ++ psplash_draw_rect(&fb->canvas, x, y, barwidth, + height, PSPLASH_BAR_COLOR); + } + else + { + barwidth = (CLAMP(-value,0,100) * width) / 100; +- psplash_fb_draw_rect (fb, x, y, ++ psplash_draw_rect(&fb->canvas, x, y, + width - barwidth, height, + PSPLASH_BAR_BACKGROUND_COLOR); +- psplash_fb_draw_rect (fb, x + width - barwidth, ++ psplash_draw_rect(&fb->canvas, x + width - barwidth, + y, barwidth, height, + PSPLASH_BAR_COLOR); + } +@@ -301,11 +301,11 @@ main (int argc, char** argv) + #endif + + /* Clear the background with #ecece1 */ +- psplash_fb_draw_rect (fb, 0, 0, fb->canvas.width, fb->canvas.height, ++ psplash_draw_rect(&fb->canvas, 0, 0, fb->canvas.width, fb->canvas.height, + PSPLASH_BACKGROUND_COLOR); + + /* Draw the Poky logo */ +- psplash_fb_draw_image (fb, ++ psplash_draw_image(&fb->canvas, + (fb->canvas.width - POKY_IMG_WIDTH)/2, + #if PSPLASH_IMG_FULLSCREEN + (fb->canvas.height - POKY_IMG_HEIGHT)/2, +@@ -321,7 +321,7 @@ main (int argc, char** argv) + + #ifdef PSPLASH_SHOW_PROGRESS_BAR + /* Draw progress bar border */ +- psplash_fb_draw_image (fb, ++ psplash_draw_image(&fb->canvas, + (fb->canvas.width - BAR_IMG_WIDTH)/2, + SPLIT_LINE_POS(fb), + BAR_IMG_WIDTH, +-- +2.25.1 + diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0008-Extract-draw-font-from-psplash-fb.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0008-Extract-draw-font-from-psplash-fb.patch new file mode 100644 index 00000000..a62e939c --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/files/0008-Extract-draw-font-from-psplash-fb.patch @@ -0,0 +1,350 @@ +From 532e889486ed4c6b254893e89c63cc4395cc83da Mon Sep 17 00:00:00 2001 +From: Vasyl Vavrychuk +Date: Mon, 25 Apr 2022 10:59:47 +0300 +Subject: [PATCH 08/17] Extract draw font from psplash-fb + +drm-backend backport from: +https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/ + +Signed-off-by: Vasyl Vavrychuk +--- + psplash-draw.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++- + psplash-draw.h | 25 ++++++++---- + psplash-fb.c | 108 ------------------------------------------------ + psplash-fb.h | 16 -------- + psplash.c | 4 +- + 5 files changed, 125 insertions(+), 137 deletions(-) + +diff --git a/psplash-draw.c b/psplash-draw.c +index 6887e22..aa9887a 100644 +--- a/psplash-draw.c ++++ b/psplash-draw.c +@@ -11,8 +11,7 @@ + + #define OFFSET(canvas, x, y) (((y) * (canvas)->stride) + ((x) * ((canvas)->bpp >> 3))) + +-/* TODO: change to 'static inline' as psplash_fb_plot_pixel was before */ +-void ++static inline void + psplash_plot_pixel(PSplashCanvas *canvas, + int x, + int y, +@@ -188,3 +187,109 @@ psplash_draw_image(PSplashCanvas *canvas, + } + } + } ++ ++/* Font rendering code based on BOGL by Ben Pfaff */ ++ ++static int ++psplash_font_glyph (const PSplashFont *font, wchar_t wc, u_int32_t **bitmap) ++{ ++ int mask = font->index_mask; ++ int i; ++ ++ for (;;) ++ { ++ for (i = font->offset[wc & mask]; font->index[i]; i += 2) ++ { ++ if ((wchar_t)(font->index[i] & ~mask) == (wc & ~mask)) ++ { ++ if (bitmap != NULL) ++ *bitmap = &font->content[font->index[i+1]]; ++ return font->index[i] & mask; ++ } ++ } ++ } ++ return 0; ++} ++ ++void ++psplash_text_size(int *width, ++ int *height, ++ const PSplashFont *font, ++ const char *text) ++{ ++ char *c = (char*)text; ++ wchar_t wc; ++ int k, n, w, h, mw; ++ ++ n = strlen (text); ++ mw = h = w = 0; ++ ++ mbtowc (0, 0, 0); ++ for (; (k = mbtowc (&wc, c, n)) > 0; c += k, n -= k) ++ { ++ if (*c == '\n') ++ { ++ if (w > mw) ++ mw = w; ++ w = 0; ++ h += font->height; ++ continue; ++ } ++ ++ w += psplash_font_glyph (font, wc, NULL); ++ } ++ ++ *width = (w > mw) ? w : mw; ++ *height = (h == 0) ? font->height : h; ++} ++ ++void ++psplash_draw_text(PSplashCanvas *canvas, ++ int x, ++ int y, ++ uint8 red, ++ uint8 green, ++ uint8 blue, ++ const PSplashFont *font, ++ const char *text) ++{ ++ int h, w, k, n, cx, cy, dx, dy; ++ char *c = (char*)text; ++ wchar_t wc; ++ ++ n = strlen (text); ++ h = font->height; ++ dx = dy = 0; ++ ++ mbtowc (0, 0, 0); ++ for (; (k = mbtowc (&wc, c, n)) > 0; c += k, n -= k) ++ { ++ u_int32_t *glyph = NULL; ++ ++ if (*c == '\n') ++ { ++ dy += h; ++ dx = 0; ++ continue; ++ } ++ ++ w = psplash_font_glyph (font, wc, &glyph); ++ ++ if (glyph == NULL) ++ continue; ++ ++ for (cy = 0; cy < h; cy++) ++ { ++ u_int32_t g = *glyph++; ++ ++ for (cx = 0; cx < w; cx++) ++ { ++ if (g & 0x80000000) ++ psplash_plot_pixel(canvas, x+dx+cx, y+dy+cy, red, green, blue); ++ g <<= 1; ++ } ++ } ++ ++ dx += w; ++ } ++} +diff --git a/psplash-draw.h b/psplash-draw.h +index f8361da..44546b0 100644 +--- a/psplash-draw.h ++++ b/psplash-draw.h +@@ -39,15 +39,6 @@ typedef struct PSplashCanvas + } + PSplashCanvas; + +-/* TODO: Remove after rest of drawing functions migrated to psplash-draw.c */ +-void +-psplash_plot_pixel(PSplashCanvas *canvas, +- int x, +- int y, +- uint8 red, +- uint8 green, +- uint8 blue); +- + void + psplash_draw_rect(PSplashCanvas *canvas, + int x, +@@ -68,4 +59,20 @@ psplash_draw_image(PSplashCanvas *canvas, + int img_rowstride, + uint8 *rle_data); + ++void ++psplash_text_size(int *width, ++ int *height, ++ const PSplashFont *font, ++ const char *text); ++ ++void ++psplash_draw_text(PSplashCanvas *canvas, ++ int x, ++ int y, ++ uint8 red, ++ uint8 green, ++ uint8 blue, ++ const PSplashFont *font, ++ const char *text); ++ + #endif +diff --git a/psplash-fb.c b/psplash-fb.c +index 07839d5..dd50a5a 100644 +--- a/psplash-fb.c ++++ b/psplash-fb.c +@@ -338,111 +338,3 @@ psplash_fb_new (int angle, int fbdev_id) + + return NULL; + } +- +-/* Font rendering code based on BOGL by Ben Pfaff */ +- +-static int +-psplash_font_glyph (const PSplashFont *font, wchar_t wc, u_int32_t **bitmap) +-{ +- int mask = font->index_mask; +- int i; +- +- for (;;) +- { +- for (i = font->offset[wc & mask]; font->index[i]; i += 2) +- { +- if ((wchar_t)(font->index[i] & ~mask) == (wc & ~mask)) +- { +- if (bitmap != NULL) +- *bitmap = &font->content[font->index[i+1]]; +- return font->index[i] & mask; +- } +- } +- } +- return 0; +-} +- +-void +-psplash_fb_text_size (int *width, +- int *height, +- const PSplashFont *font, +- const char *text) +-{ +- char *c = (char*)text; +- wchar_t wc; +- int k, n, w, h, mw; +- +- n = strlen (text); +- mw = h = w = 0; +- +- mbtowc (0, 0, 0); +- for (; (k = mbtowc (&wc, c, n)) > 0; c += k, n -= k) +- { +- if (*c == '\n') +- { +- if (w > mw) +- mw = w; +- w = 0; +- h += font->height; +- continue; +- } +- +- w += psplash_font_glyph (font, wc, NULL); +- } +- +- *width = (w > mw) ? w : mw; +- *height = (h == 0) ? font->height : h; +-} +- +-void +-psplash_fb_draw_text (PSplashFB *fb, +- int x, +- int y, +- uint8 red, +- uint8 green, +- uint8 blue, +- const PSplashFont *font, +- const char *text) +-{ +- int h, w, k, n, cx, cy, dx, dy; +- char *c = (char*)text; +- wchar_t wc; +- +- n = strlen (text); +- h = font->height; +- dx = dy = 0; +- +- mbtowc (0, 0, 0); +- for (; (k = mbtowc (&wc, c, n)) > 0; c += k, n -= k) +- { +- u_int32_t *glyph = NULL; +- +- if (*c == '\n') +- { +- dy += h; +- dx = 0; +- continue; +- } +- +- w = psplash_font_glyph (font, wc, &glyph); +- +- if (glyph == NULL) +- continue; +- +- for (cy = 0; cy < h; cy++) +- { +- u_int32_t g = *glyph++; +- +- for (cx = 0; cx < w; cx++) +- { +- if (g & 0x80000000) +- psplash_plot_pixel(&fb->canvas, x+dx+cx, y+dy+cy, +- red, green, blue); +- g <<= 1; +- } +- } +- +- dx += w; +- } +-} +- +diff --git a/psplash-fb.h b/psplash-fb.h +index 1eecb47..1b16bd5 100644 +--- a/psplash-fb.h ++++ b/psplash-fb.h +@@ -40,22 +40,6 @@ psplash_fb_destroy (PSplashFB *fb); + PSplashFB* + psplash_fb_new (int angle, int fbdev_id); + +-void +-psplash_fb_text_size (int *width, +- int *height, +- const PSplashFont *font, +- const char *text); +- +-void +-psplash_fb_draw_text (PSplashFB *fb, +- int x, +- int y, +- uint8 red, +- uint8 green, +- uint8 blue, +- const PSplashFont *font, +- const char *text); +- + void + psplash_fb_flip(PSplashFB *fb, int sync); + +diff --git a/psplash.c b/psplash.c +index 2aeb583..1a5e543 100644 +--- a/psplash.c ++++ b/psplash.c +@@ -41,7 +41,7 @@ psplash_draw_msg (PSplashFB *fb, const char *msg) + { + int w, h; + +- psplash_fb_text_size (&w, &h, &FONT_DEF, msg); ++ psplash_text_size(&w, &h, &FONT_DEF, msg); + + DBG("displaying '%s' %ix%i\n", msg, w, h); + +@@ -54,7 +54,7 @@ psplash_draw_msg (PSplashFB *fb, const char *msg) + h, + PSPLASH_BACKGROUND_COLOR); + +- psplash_fb_draw_text (fb, ++ psplash_draw_text(&fb->canvas, + (fb->canvas.width-w)/2, + SPLIT_LINE_POS(fb) - h, + PSPLASH_TEXT_COLOR, +-- +2.25.1 + diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0009-psplash.c-Make-psplash_draw_-msg-progress-independen.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0009-psplash.c-Make-psplash_draw_-msg-progress-independen.patch new file mode 100644 index 00000000..9cd2692c --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/files/0009-psplash.c-Make-psplash_draw_-msg-progress-independen.patch @@ -0,0 +1,191 @@ +From 1046e65f7cca2b592fbb7e8f0d1392fb742a67b1 Mon Sep 17 00:00:00 2001 +From: Vasyl Vavrychuk +Date: Mon, 25 Apr 2022 10:59:48 +0300 +Subject: [PATCH 09/17] psplash.c: Make psplash_draw_{msg,progress} independent + of FB + +drm-backend backport from: +https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/ + +Signed-off-by: Vasyl Vavrychuk +--- + psplash.c | 64 ++++++++++++++++++++++++++++--------------------------- + 1 file changed, 33 insertions(+), 31 deletions(-) + +diff --git a/psplash.c b/psplash.c +index 1a5e543..c234d46 100644 +--- a/psplash.c ++++ b/psplash.c +@@ -21,11 +21,11 @@ + #endif + #include FONT_HEADER + +-#define SPLIT_LINE_POS(fb) \ +- ( (fb)->canvas.height \ +- - (( PSPLASH_IMG_SPLIT_DENOMINATOR \ +- - PSPLASH_IMG_SPLIT_NUMERATOR) \ +- * (fb)->canvas.height / PSPLASH_IMG_SPLIT_DENOMINATOR) \ ++#define SPLIT_LINE_POS(canvas) \ ++ ( (canvas)->height \ ++ - (( PSPLASH_IMG_SPLIT_DENOMINATOR \ ++ - PSPLASH_IMG_SPLIT_NUMERATOR) \ ++ * (canvas)->height / PSPLASH_IMG_SPLIT_DENOMINATOR) \ + ) + + void +@@ -37,7 +37,7 @@ psplash_exit (int UNUSED(signum)) + } + + void +-psplash_draw_msg (PSplashFB *fb, const char *msg) ++psplash_draw_msg(PSplashCanvas *canvas, const char *msg) + { + int w, h; + +@@ -47,16 +47,16 @@ psplash_draw_msg (PSplashFB *fb, const char *msg) + + /* Clear */ + +- psplash_draw_rect(&fb->canvas, ++ psplash_draw_rect(canvas, + 0, +- SPLIT_LINE_POS(fb) - h, +- fb->canvas.width, ++ SPLIT_LINE_POS(canvas) - h, ++ canvas->width, + h, + PSPLASH_BACKGROUND_COLOR); + +- psplash_draw_text(&fb->canvas, +- (fb->canvas.width-w)/2, +- SPLIT_LINE_POS(fb) - h, ++ psplash_draw_text(canvas, ++ (canvas->width-w)/2, ++ SPLIT_LINE_POS(canvas) - h, + PSPLASH_TEXT_COLOR, + &FONT_DEF, + msg); +@@ -64,32 +64,32 @@ psplash_draw_msg (PSplashFB *fb, const char *msg) + + #ifdef PSPLASH_SHOW_PROGRESS_BAR + void +-psplash_draw_progress (PSplashFB *fb, int value) ++psplash_draw_progress(PSplashCanvas *canvas, int value) + { + int x, y, width, height, barwidth; + + /* 4 pix border */ +- x = ((fb->canvas.width - BAR_IMG_WIDTH)/2) + 4 ; +- y = SPLIT_LINE_POS(fb) + 4; ++ x = ((canvas->width - BAR_IMG_WIDTH)/2) + 4 ; ++ y = SPLIT_LINE_POS(canvas) + 4; + width = BAR_IMG_WIDTH - 8; + height = BAR_IMG_HEIGHT - 8; + + if (value > 0) + { + barwidth = (CLAMP(value,0,100) * width) / 100; +- psplash_draw_rect(&fb->canvas, x + barwidth, y, ++ psplash_draw_rect(canvas, x + barwidth, y, + width - barwidth, height, + PSPLASH_BAR_BACKGROUND_COLOR); +- psplash_draw_rect(&fb->canvas, x, y, barwidth, ++ psplash_draw_rect(canvas, x, y, barwidth, + height, PSPLASH_BAR_COLOR); + } + else + { + barwidth = (CLAMP(-value,0,100) * width) / 100; +- psplash_draw_rect(&fb->canvas, x, y, ++ psplash_draw_rect(canvas, x, y, + width - barwidth, height, + PSPLASH_BAR_BACKGROUND_COLOR); +- psplash_draw_rect(&fb->canvas, x + width - barwidth, ++ psplash_draw_rect(canvas, x + width - barwidth, + y, barwidth, height, + PSPLASH_BAR_COLOR); + } +@@ -116,7 +116,7 @@ parse_command (PSplashFB *fb, char *string) + char *arg = strtok(NULL, "\0"); + + if (arg) +- psplash_draw_msg (fb, arg); ++ psplash_draw_msg(&fb->canvas, arg); + } + #ifdef PSPLASH_SHOW_PROGRESS_BAR + else if (!strcmp(command,"PROGRESS")) +@@ -124,7 +124,7 @@ parse_command (PSplashFB *fb, char *string) + char *arg = strtok(NULL, "\0"); + + if (arg) +- psplash_draw_progress (fb, atoi(arg)); ++ psplash_draw_progress(&fb->canvas, atoi(arg)); + } + #endif + else if (!strcmp(command,"QUIT")) +@@ -226,6 +226,7 @@ main (int argc, char** argv) + char *rundir; + int pipe_fd, i = 0, angle = 0, fbdev_id = 0, ret = 0; + PSplashFB *fb; ++ PSplashCanvas *canvas; + bool disable_console_switch = FALSE; + + signal(SIGHUP, psplash_exit); +@@ -295,22 +296,23 @@ main (int argc, char** argv) + ret = -1; + goto fb_fail; + } ++ canvas = &fb->canvas; + + #ifdef HAVE_SYSTEMD + sd_notify(0, "READY=1"); + #endif + + /* Clear the background with #ecece1 */ +- psplash_draw_rect(&fb->canvas, 0, 0, fb->canvas.width, fb->canvas.height, ++ psplash_draw_rect(canvas, 0, 0, canvas->width, canvas->height, + PSPLASH_BACKGROUND_COLOR); + + /* Draw the Poky logo */ +- psplash_draw_image(&fb->canvas, +- (fb->canvas.width - POKY_IMG_WIDTH)/2, ++ psplash_draw_image(canvas, ++ (canvas->width - POKY_IMG_WIDTH)/2, + #if PSPLASH_IMG_FULLSCREEN +- (fb->canvas.height - POKY_IMG_HEIGHT)/2, ++ (canvas->height - POKY_IMG_HEIGHT)/2, + #else +- (fb->canvas.height * PSPLASH_IMG_SPLIT_NUMERATOR ++ (canvas->height * PSPLASH_IMG_SPLIT_NUMERATOR + / PSPLASH_IMG_SPLIT_DENOMINATOR - POKY_IMG_HEIGHT)/2, + #endif + POKY_IMG_WIDTH, +@@ -321,20 +323,20 @@ main (int argc, char** argv) + + #ifdef PSPLASH_SHOW_PROGRESS_BAR + /* Draw progress bar border */ +- psplash_draw_image(&fb->canvas, +- (fb->canvas.width - BAR_IMG_WIDTH)/2, +- SPLIT_LINE_POS(fb), ++ psplash_draw_image(canvas, ++ (canvas->width - BAR_IMG_WIDTH)/2, ++ SPLIT_LINE_POS(canvas), + BAR_IMG_WIDTH, + BAR_IMG_HEIGHT, + BAR_IMG_BYTES_PER_PIXEL, + BAR_IMG_ROWSTRIDE, + BAR_IMG_RLE_PIXEL_DATA); + +- psplash_draw_progress (fb, 0); ++ psplash_draw_progress(canvas, 0); + #endif + + #ifdef PSPLASH_STARTUP_MSG +- psplash_draw_msg (fb, PSPLASH_STARTUP_MSG); ++ psplash_draw_msg(canvas, PSPLASH_STARTUP_MSG); + #endif + + /* Scene set so let's flip the buffers. */ +-- +2.25.1 + diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0010-Rework-flip-as-function-pointer.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0010-Rework-flip-as-function-pointer.patch new file mode 100644 index 00000000..2d897a37 --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/files/0010-Rework-flip-as-function-pointer.patch @@ -0,0 +1,141 @@ +From e1004cd1a1252a17219f5ebd13749c91e8ddc09b Mon Sep 17 00:00:00 2001 +From: Vasyl Vavrychuk +Date: Mon, 25 Apr 2022 10:59:49 +0300 +Subject: [PATCH 10/17] Rework flip as function pointer + +It allows making parse_command and psplash_main independent of FB. + +drm-backend backport from: +https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/ + +Signed-off-by: Vasyl Vavrychuk +--- + psplash-draw.h | 3 +++ + psplash-fb.c | 8 +++++--- + psplash-fb.h | 3 --- + psplash.c | 16 ++++++++-------- + 4 files changed, 16 insertions(+), 14 deletions(-) + +diff --git a/psplash-draw.h b/psplash-draw.h +index 44546b0..292ddd9 100644 +--- a/psplash-draw.h ++++ b/psplash-draw.h +@@ -36,6 +36,9 @@ typedef struct PSplashCanvas + int green_length; + int blue_offset; + int blue_length; ++ ++ void *priv; ++ void (*flip)(struct PSplashCanvas *canvas, int sync); + } + PSplashCanvas; + +diff --git a/psplash-fb.c b/psplash-fb.c +index dd50a5a..d41c477 100644 +--- a/psplash-fb.c ++++ b/psplash-fb.c +@@ -18,9 +18,10 @@ psplash_wait_for_vsync(PSplashFB *fb) + fprintf(stderr, "Error, FB vsync ioctl [%d]\n", err); + } + +-void +-psplash_fb_flip(PSplashFB *fb, int sync) ++static void ++psplash_fb_flip(PSplashCanvas *canvas, int sync) + { ++ PSplashFB *fb = canvas->priv; + char *tmp; + + if (fb->double_buffering) { +@@ -154,7 +155,8 @@ psplash_fb_new (int angle, int fbdev_id) + } + + memset (fb, 0, sizeof(PSplashFB)); +- ++ fb->canvas.priv = fb; ++ fb->canvas.flip = psplash_fb_flip; + fb->fd = -1; + + if ((fb->fd = open (fbdev, O_RDWR)) < 0) +diff --git a/psplash-fb.h b/psplash-fb.h +index 1b16bd5..979d23a 100644 +--- a/psplash-fb.h ++++ b/psplash-fb.h +@@ -40,7 +40,4 @@ psplash_fb_destroy (PSplashFB *fb); + PSplashFB* + psplash_fb_new (int angle, int fbdev_id); + +-void +-psplash_fb_flip(PSplashFB *fb, int sync); +- + #endif +diff --git a/psplash.c b/psplash.c +index c234d46..036dfb1 100644 +--- a/psplash.c ++++ b/psplash.c +@@ -100,7 +100,7 @@ psplash_draw_progress(PSplashCanvas *canvas, int value) + #endif /* PSPLASH_SHOW_PROGRESS_BAR */ + + static int +-parse_command (PSplashFB *fb, char *string) ++parse_command(PSplashCanvas *canvas, char *string) + { + char *command; + +@@ -116,7 +116,7 @@ parse_command (PSplashFB *fb, char *string) + char *arg = strtok(NULL, "\0"); + + if (arg) +- psplash_draw_msg(&fb->canvas, arg); ++ psplash_draw_msg(canvas, arg); + } + #ifdef PSPLASH_SHOW_PROGRESS_BAR + else if (!strcmp(command,"PROGRESS")) +@@ -124,7 +124,7 @@ parse_command (PSplashFB *fb, char *string) + char *arg = strtok(NULL, "\0"); + + if (arg) +- psplash_draw_progress(&fb->canvas, atoi(arg)); ++ psplash_draw_progress(canvas, atoi(arg)); + } + #endif + else if (!strcmp(command,"QUIT")) +@@ -132,12 +132,12 @@ parse_command (PSplashFB *fb, char *string) + return 1; + } + +- psplash_fb_flip(fb, 0); ++ canvas->flip(canvas, 0); + return 0; + } + + void +-psplash_main (PSplashFB *fb, int pipe_fd, int timeout) ++psplash_main(PSplashCanvas *canvas, int pipe_fd, int timeout) + { + int err; + ssize_t length = 0; +@@ -200,7 +200,7 @@ psplash_main (PSplashFB *fb, int pipe_fd, int timeout) + continue; + } + +- if (parse_command(fb, cmd)) ++ if (parse_command(canvas, cmd)) + return; + + length -= cmdlen; +@@ -345,9 +345,9 @@ main (int argc, char** argv) + * text and progress bar change which overwrite the specific areas with every + * update. + */ +- psplash_fb_flip(fb, 1); ++ canvas->flip(canvas, 1); + +- psplash_main (fb, pipe_fd, 0); ++ psplash_main(canvas, pipe_fd, 0); + + psplash_fb_destroy (fb); + +-- +2.25.1 + diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0011-Import-drm-howto-modeset.c-as-psplash-drm.c.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0011-Import-drm-howto-modeset.c-as-psplash-drm.c.patch new file mode 100644 index 00000000..767dbf4b --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/files/0011-Import-drm-howto-modeset.c-as-psplash-drm.c.patch @@ -0,0 +1,764 @@ +From d5a9fb5cd8505c16d4d75c695af1e64597d36c86 Mon Sep 17 00:00:00 2001 +From: Vasyl Vavrychuk +Date: Mon, 25 Apr 2022 10:59:50 +0300 +Subject: [PATCH 11/17] Import drm-howto modeset.c as psplash-drm.c + +Imported as is from +repo: https://github.com/dvdhrm/docs.git +branch: master +commit: fc5c63f +path: drm-howto/modeset.c + +drm-backend backport from: +https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/ + +Signed-off-by: Vasyl Vavrychuk +--- + psplash-drm.c | 735 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 735 insertions(+) + create mode 100644 psplash-drm.c + +diff --git a/psplash-drm.c b/psplash-drm.c +new file mode 100644 +index 0000000..c9a9f5c +--- /dev/null ++++ b/psplash-drm.c +@@ -0,0 +1,735 @@ ++/* ++ * modeset - DRM Modesetting Example ++ * ++ * Written 2012 by David Rheinsberg ++ * Dedicated to the Public Domain. ++ */ ++ ++/* ++ * DRM Modesetting Howto ++ * This document describes the DRM modesetting API. Before we can use the DRM ++ * API, we have to include xf86drm.h and xf86drmMode.h. Both are provided by ++ * libdrm which every major distribution ships by default. It has no other ++ * dependencies and is pretty small. ++ * ++ * Please ignore all forward-declarations of functions which are used later. I ++ * reordered the functions so you can read this document from top to bottom. If ++ * you reimplement it, you would probably reorder the functions to avoid all the ++ * nasty forward declarations. ++ * ++ * For easier reading, we ignore all memory-allocation errors of malloc() and ++ * friends here. However, we try to correctly handle all other kinds of errors ++ * that may occur. ++ * ++ * All functions and global variables are prefixed with "modeset_*" in this ++ * file. So it should be clear whether a function is a local helper or if it is ++ * provided by some external library. ++ */ ++ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct modeset_dev; ++static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn, ++ struct modeset_dev *dev); ++static int modeset_create_fb(int fd, struct modeset_dev *dev); ++static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn, ++ struct modeset_dev *dev); ++static int modeset_open(int *out, const char *node); ++static int modeset_prepare(int fd); ++static void modeset_draw(void); ++static void modeset_cleanup(int fd); ++ ++/* ++ * When the linux kernel detects a graphics-card on your machine, it loads the ++ * correct device driver (located in kernel-tree at ./drivers/gpu/drm/) and ++ * provides two character-devices to control it. Udev (or whatever hotplugging ++ * application you use) will create them as: ++ * /dev/dri/card0 ++ * /dev/dri/controlID64 ++ * We only need the first one. You can hard-code this path into your application ++ * like we do here, but it is recommended to use libudev with real hotplugging ++ * and multi-seat support. However, this is beyond the scope of this document. ++ * Also note that if you have multiple graphics-cards, there may also be ++ * /dev/dri/card1, /dev/dri/card2, ... ++ * ++ * We simply use /dev/dri/card0 here but the user can specify another path on ++ * the command line. ++ * ++ * modeset_open(out, node): This small helper function opens the DRM device ++ * which is given as @node. The new fd is stored in @out on success. On failure, ++ * a negative error code is returned. ++ * After opening the file, we also check for the DRM_CAP_DUMB_BUFFER capability. ++ * If the driver supports this capability, we can create simple memory-mapped ++ * buffers without any driver-dependent code. As we want to avoid any radeon, ++ * nvidia, intel, etc. specific code, we depend on DUMB_BUFFERs here. ++ */ ++ ++static int modeset_open(int *out, const char *node) ++{ ++ int fd, ret; ++ uint64_t has_dumb; ++ ++ fd = open(node, O_RDWR | O_CLOEXEC); ++ if (fd < 0) { ++ ret = -errno; ++ fprintf(stderr, "cannot open '%s': %m\n", node); ++ return ret; ++ } ++ ++ if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 || ++ !has_dumb) { ++ fprintf(stderr, "drm device '%s' does not support dumb buffers\n", ++ node); ++ close(fd); ++ return -EOPNOTSUPP; ++ } ++ ++ *out = fd; ++ return 0; ++} ++ ++/* ++ * As a next step we need to find our available display devices. libdrm provides ++ * a drmModeRes structure that contains all the needed information. We can ++ * retrieve it via drmModeGetResources(fd) and free it via ++ * drmModeFreeResources(res) again. ++ * ++ * A physical connector on your graphics card is called a "connector". You can ++ * plug a monitor into it and control what is displayed. We are definitely ++ * interested in what connectors are currently used, so we simply iterate ++ * through the list of connectors and try to display a test-picture on each ++ * available monitor. ++ * However, this isn't as easy as it sounds. First, we need to check whether the ++ * connector is actually used (a monitor is plugged in and turned on). Then we ++ * need to find a CRTC that can control this connector. CRTCs are described ++ * later on. After that we create a framebuffer object. If we have all this, we ++ * can mmap() the framebuffer and draw a test-picture into it. Then we can tell ++ * the DRM device to show the framebuffer on the given CRTC with the selected ++ * connector. ++ * ++ * As we want to draw moving pictures on the framebuffer, we actually have to ++ * remember all these settings. Therefore, we create one "struct modeset_dev" ++ * object for each connector+crtc+framebuffer pair that we successfully ++ * initialized and push it into the global device-list. ++ * ++ * Each field of this structure is described when it is first used. But as a ++ * summary: ++ * "struct modeset_dev" contains: { ++ * - @next: points to the next device in the single-linked list ++ * ++ * - @width: width of our buffer object ++ * - @height: height of our buffer object ++ * - @stride: stride value of our buffer object ++ * - @size: size of the memory mapped buffer ++ * - @handle: a DRM handle to the buffer object that we can draw into ++ * - @map: pointer to the memory mapped buffer ++ * ++ * - @mode: the display mode that we want to use ++ * - @fb: a framebuffer handle with our buffer object as scanout buffer ++ * - @conn: the connector ID that we want to use with this buffer ++ * - @crtc: the crtc ID that we want to use with this connector ++ * - @saved_crtc: the configuration of the crtc before we changed it. We use it ++ * so we can restore the same mode when we exit. ++ * } ++ */ ++ ++struct modeset_dev { ++ struct modeset_dev *next; ++ ++ uint32_t width; ++ uint32_t height; ++ uint32_t stride; ++ uint32_t size; ++ uint32_t handle; ++ uint8_t *map; ++ ++ drmModeModeInfo mode; ++ uint32_t fb; ++ uint32_t conn; ++ uint32_t crtc; ++ drmModeCrtc *saved_crtc; ++}; ++ ++static struct modeset_dev *modeset_list = NULL; ++ ++/* ++ * So as next step we need to actually prepare all connectors that we find. We ++ * do this in this little helper function: ++ * ++ * modeset_prepare(fd): This helper function takes the DRM fd as argument and ++ * then simply retrieves the resource-info from the device. It then iterates ++ * through all connectors and calls other helper functions to initialize this ++ * connector (described later on). ++ * If the initialization was successful, we simply add this object as new device ++ * into the global modeset device list. ++ * ++ * The resource-structure contains a list of all connector-IDs. We use the ++ * helper function drmModeGetConnector() to retrieve more information on each ++ * connector. After we are done with it, we free it again with ++ * drmModeFreeConnector(). ++ * Our helper modeset_setup_dev() returns -ENOENT if the connector is currently ++ * unused and no monitor is plugged in. So we can ignore this connector. ++ */ ++ ++static int modeset_prepare(int fd) ++{ ++ drmModeRes *res; ++ drmModeConnector *conn; ++ unsigned int i; ++ struct modeset_dev *dev; ++ int ret; ++ ++ /* retrieve resources */ ++ res = drmModeGetResources(fd); ++ if (!res) { ++ fprintf(stderr, "cannot retrieve DRM resources (%d): %m\n", ++ errno); ++ return -errno; ++ } ++ ++ /* iterate all connectors */ ++ for (i = 0; i < res->count_connectors; ++i) { ++ /* get information for each connector */ ++ conn = drmModeGetConnector(fd, res->connectors[i]); ++ if (!conn) { ++ fprintf(stderr, "cannot retrieve DRM connector %u:%u (%d): %m\n", ++ i, res->connectors[i], errno); ++ continue; ++ } ++ ++ /* create a device structure */ ++ dev = malloc(sizeof(*dev)); ++ memset(dev, 0, sizeof(*dev)); ++ dev->conn = conn->connector_id; ++ ++ /* call helper function to prepare this connector */ ++ ret = modeset_setup_dev(fd, res, conn, dev); ++ if (ret) { ++ if (ret != -ENOENT) { ++ errno = -ret; ++ fprintf(stderr, "cannot setup device for connector %u:%u (%d): %m\n", ++ i, res->connectors[i], errno); ++ } ++ free(dev); ++ drmModeFreeConnector(conn); ++ continue; ++ } ++ ++ /* free connector data and link device into global list */ ++ drmModeFreeConnector(conn); ++ dev->next = modeset_list; ++ modeset_list = dev; ++ } ++ ++ /* free resources again */ ++ drmModeFreeResources(res); ++ return 0; ++} ++ ++/* ++ * Now we dig deeper into setting up a single connector. As described earlier, ++ * we need to check several things first: ++ * * If the connector is currently unused, that is, no monitor is plugged in, ++ * then we can ignore it. ++ * * We have to find a suitable resolution and refresh-rate. All this is ++ * available in drmModeModeInfo structures saved for each crtc. We simply ++ * use the first mode that is available. This is always the mode with the ++ * highest resolution. ++ * A more sophisticated mode-selection should be done in real applications, ++ * though. ++ * * Then we need to find an CRTC that can drive this connector. A CRTC is an ++ * internal resource of each graphics-card. The number of CRTCs controls how ++ * many connectors can be controlled indepedently. That is, a graphics-cards ++ * may have more connectors than CRTCs, which means, not all monitors can be ++ * controlled independently. ++ * There is actually the possibility to control multiple connectors via a ++ * single CRTC if the monitors should display the same content. However, we ++ * do not make use of this here. ++ * So think of connectors as pipelines to the connected monitors and the ++ * CRTCs are the controllers that manage which data goes to which pipeline. ++ * If there are more pipelines than CRTCs, then we cannot control all of ++ * them at the same time. ++ * * We need to create a framebuffer for this connector. A framebuffer is a ++ * memory buffer that we can write XRGB32 data into. So we use this to ++ * render our graphics and then the CRTC can scan-out this data from the ++ * framebuffer onto the monitor. ++ */ ++ ++static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn, ++ struct modeset_dev *dev) ++{ ++ int ret; ++ ++ /* check if a monitor is connected */ ++ if (conn->connection != DRM_MODE_CONNECTED) { ++ fprintf(stderr, "ignoring unused connector %u\n", ++ conn->connector_id); ++ return -ENOENT; ++ } ++ ++ /* check if there is at least one valid mode */ ++ if (conn->count_modes == 0) { ++ fprintf(stderr, "no valid mode for connector %u\n", ++ conn->connector_id); ++ return -EFAULT; ++ } ++ ++ /* copy the mode information into our device structure */ ++ memcpy(&dev->mode, &conn->modes[0], sizeof(dev->mode)); ++ dev->width = conn->modes[0].hdisplay; ++ dev->height = conn->modes[0].vdisplay; ++ fprintf(stderr, "mode for connector %u is %ux%u\n", ++ conn->connector_id, dev->width, dev->height); ++ ++ /* find a crtc for this connector */ ++ ret = modeset_find_crtc(fd, res, conn, dev); ++ if (ret) { ++ fprintf(stderr, "no valid crtc for connector %u\n", ++ conn->connector_id); ++ return ret; ++ } ++ ++ /* create a framebuffer for this CRTC */ ++ ret = modeset_create_fb(fd, dev); ++ if (ret) { ++ fprintf(stderr, "cannot create framebuffer for connector %u\n", ++ conn->connector_id); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/* ++ * modeset_find_crtc(fd, res, conn, dev): This small helper tries to find a ++ * suitable CRTC for the given connector. We have actually have to introduce one ++ * more DRM object to make this more clear: Encoders. ++ * Encoders help the CRTC to convert data from a framebuffer into the right ++ * format that can be used for the chosen connector. We do not have to ++ * understand any more of these conversions to make use of it. However, you must ++ * know that each connector has a limited list of encoders that it can use. And ++ * each encoder can only work with a limited list of CRTCs. So what we do is ++ * trying each encoder that is available and looking for a CRTC that this ++ * encoder can work with. If we find the first working combination, we are happy ++ * and write it into the @dev structure. ++ * But before iterating all available encoders, we first try the currently ++ * active encoder+crtc on a connector to avoid a full modeset. ++ * ++ * However, before we can use a CRTC we must make sure that no other device, ++ * that we setup previously, is already using this CRTC. Remember, we can only ++ * drive one connector per CRTC! So we simply iterate through the "modeset_list" ++ * of previously setup devices and check that this CRTC wasn't used before. ++ * Otherwise, we continue with the next CRTC/Encoder combination. ++ */ ++ ++static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn, ++ struct modeset_dev *dev) ++{ ++ drmModeEncoder *enc; ++ unsigned int i, j; ++ int32_t crtc; ++ struct modeset_dev *iter; ++ ++ /* first try the currently conected encoder+crtc */ ++ if (conn->encoder_id) ++ enc = drmModeGetEncoder(fd, conn->encoder_id); ++ else ++ enc = NULL; ++ ++ if (enc) { ++ if (enc->crtc_id) { ++ crtc = enc->crtc_id; ++ for (iter = modeset_list; iter; iter = iter->next) { ++ if (iter->crtc == crtc) { ++ crtc = -1; ++ break; ++ } ++ } ++ ++ if (crtc >= 0) { ++ drmModeFreeEncoder(enc); ++ dev->crtc = crtc; ++ return 0; ++ } ++ } ++ ++ drmModeFreeEncoder(enc); ++ } ++ ++ /* If the connector is not currently bound to an encoder or if the ++ * encoder+crtc is already used by another connector (actually unlikely ++ * but lets be safe), iterate all other available encoders to find a ++ * matching CRTC. */ ++ for (i = 0; i < conn->count_encoders; ++i) { ++ enc = drmModeGetEncoder(fd, conn->encoders[i]); ++ if (!enc) { ++ fprintf(stderr, "cannot retrieve encoder %u:%u (%d): %m\n", ++ i, conn->encoders[i], errno); ++ continue; ++ } ++ ++ /* iterate all global CRTCs */ ++ for (j = 0; j < res->count_crtcs; ++j) { ++ /* check whether this CRTC works with the encoder */ ++ if (!(enc->possible_crtcs & (1 << j))) ++ continue; ++ ++ /* check that no other device already uses this CRTC */ ++ crtc = res->crtcs[j]; ++ for (iter = modeset_list; iter; iter = iter->next) { ++ if (iter->crtc == crtc) { ++ crtc = -1; ++ break; ++ } ++ } ++ ++ /* we have found a CRTC, so save it and return */ ++ if (crtc >= 0) { ++ drmModeFreeEncoder(enc); ++ dev->crtc = crtc; ++ return 0; ++ } ++ } ++ ++ drmModeFreeEncoder(enc); ++ } ++ ++ fprintf(stderr, "cannot find suitable CRTC for connector %u\n", ++ conn->connector_id); ++ return -ENOENT; ++} ++ ++/* ++ * modeset_create_fb(fd, dev): After we have found a crtc+connector+mode ++ * combination, we need to actually create a suitable framebuffer that we can ++ * use with it. There are actually two ways to do that: ++ * * We can create a so called "dumb buffer". This is a buffer that we can ++ * memory-map via mmap() and every driver supports this. We can use it for ++ * unaccelerated software rendering on the CPU. ++ * * We can use libgbm to create buffers available for hardware-acceleration. ++ * libgbm is an abstraction layer that creates these buffers for each ++ * available DRM driver. As there is no generic API for this, each driver ++ * provides its own way to create these buffers. ++ * We can then use such buffers to create OpenGL contexts with the mesa3D ++ * library. ++ * We use the first solution here as it is much simpler and doesn't require any ++ * external libraries. However, if you want to use hardware-acceleration via ++ * OpenGL, it is actually pretty easy to create such buffers with libgbm and ++ * libEGL. But this is beyond the scope of this document. ++ * ++ * So what we do is requesting a new dumb-buffer from the driver. We specify the ++ * same size as the current mode that we selected for the connector. ++ * Then we request the driver to prepare this buffer for memory mapping. After ++ * that we perform the actual mmap() call. So we can now access the framebuffer ++ * memory directly via the dev->map memory map. ++ */ ++ ++static int modeset_create_fb(int fd, struct modeset_dev *dev) ++{ ++ struct drm_mode_create_dumb creq; ++ struct drm_mode_destroy_dumb dreq; ++ struct drm_mode_map_dumb mreq; ++ int ret; ++ ++ /* create dumb buffer */ ++ memset(&creq, 0, sizeof(creq)); ++ creq.width = dev->width; ++ creq.height = dev->height; ++ creq.bpp = 32; ++ ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq); ++ if (ret < 0) { ++ fprintf(stderr, "cannot create dumb buffer (%d): %m\n", ++ errno); ++ return -errno; ++ } ++ dev->stride = creq.pitch; ++ dev->size = creq.size; ++ dev->handle = creq.handle; ++ ++ /* create framebuffer object for the dumb-buffer */ ++ ret = drmModeAddFB(fd, dev->width, dev->height, 24, 32, dev->stride, ++ dev->handle, &dev->fb); ++ if (ret) { ++ fprintf(stderr, "cannot create framebuffer (%d): %m\n", ++ errno); ++ ret = -errno; ++ goto err_destroy; ++ } ++ ++ /* prepare buffer for memory mapping */ ++ memset(&mreq, 0, sizeof(mreq)); ++ mreq.handle = dev->handle; ++ ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); ++ if (ret) { ++ fprintf(stderr, "cannot map dumb buffer (%d): %m\n", ++ errno); ++ ret = -errno; ++ goto err_fb; ++ } ++ ++ /* perform actual memory mapping */ ++ dev->map = mmap(0, dev->size, PROT_READ | PROT_WRITE, MAP_SHARED, ++ fd, mreq.offset); ++ if (dev->map == MAP_FAILED) { ++ fprintf(stderr, "cannot mmap dumb buffer (%d): %m\n", ++ errno); ++ ret = -errno; ++ goto err_fb; ++ } ++ ++ /* clear the framebuffer to 0 */ ++ memset(dev->map, 0, dev->size); ++ ++ return 0; ++ ++err_fb: ++ drmModeRmFB(fd, dev->fb); ++err_destroy: ++ memset(&dreq, 0, sizeof(dreq)); ++ dreq.handle = dev->handle; ++ drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); ++ return ret; ++} ++ ++/* ++ * Finally! We have a connector with a suitable CRTC. We know which mode we want ++ * to use and we have a framebuffer of the correct size that we can write to. ++ * There is nothing special left to do. We only have to program the CRTC to ++ * connect each new framebuffer to each selected connector for each combination ++ * that we saved in the global modeset_list. ++ * This is done with a call to drmModeSetCrtc(). ++ * ++ * So we are ready for our main() function. First we check whether the user ++ * specified a DRM device on the command line, otherwise we use the default ++ * /dev/dri/card0. Then we open the device via modeset_open(). modeset_prepare() ++ * prepares all connectors and we can loop over "modeset_list" and call ++ * drmModeSetCrtc() on every CRTC/connector combination. ++ * ++ * But printing empty black pages is boring so we have another helper function ++ * modeset_draw() that draws some colors into the framebuffer for 5 seconds and ++ * then returns. And then we have all the cleanup functions which correctly free ++ * all devices again after we used them. All these functions are described below ++ * the main() function. ++ * ++ * As a side note: drmModeSetCrtc() actually takes a list of connectors that we ++ * want to control with this CRTC. We pass only one connector, though. As ++ * explained earlier, if we used multiple connectors, then all connectors would ++ * have the same controlling framebuffer so the output would be cloned. This is ++ * most often not what you want so we avoid explaining this feature here. ++ * Furthermore, all connectors will have to run with the same mode, which is ++ * also often not guaranteed. So instead, we only use one connector per CRTC. ++ * ++ * Before calling drmModeSetCrtc() we also save the current CRTC configuration. ++ * This is used in modeset_cleanup() to restore the CRTC to the same mode as was ++ * before we changed it. ++ * If we don't do this, the screen will stay blank after we exit until another ++ * application performs modesetting itself. ++ */ ++ ++int main(int argc, char **argv) ++{ ++ int ret, fd; ++ const char *card; ++ struct modeset_dev *iter; ++ ++ /* check which DRM device to open */ ++ if (argc > 1) ++ card = argv[1]; ++ else ++ card = "/dev/dri/card0"; ++ ++ fprintf(stderr, "using card '%s'\n", card); ++ ++ /* open the DRM device */ ++ ret = modeset_open(&fd, card); ++ if (ret) ++ goto out_return; ++ ++ /* prepare all connectors and CRTCs */ ++ ret = modeset_prepare(fd); ++ if (ret) ++ goto out_close; ++ ++ /* perform actual modesetting on each found connector+CRTC */ ++ for (iter = modeset_list; iter; iter = iter->next) { ++ iter->saved_crtc = drmModeGetCrtc(fd, iter->crtc); ++ ret = drmModeSetCrtc(fd, iter->crtc, iter->fb, 0, 0, ++ &iter->conn, 1, &iter->mode); ++ if (ret) ++ fprintf(stderr, "cannot set CRTC for connector %u (%d): %m\n", ++ iter->conn, errno); ++ } ++ ++ /* draw some colors for 5seconds */ ++ modeset_draw(); ++ ++ /* cleanup everything */ ++ modeset_cleanup(fd); ++ ++ ret = 0; ++ ++out_close: ++ close(fd); ++out_return: ++ if (ret) { ++ errno = -ret; ++ fprintf(stderr, "modeset failed with error %d: %m\n", errno); ++ } else { ++ fprintf(stderr, "exiting\n"); ++ } ++ return ret; ++} ++ ++/* ++ * A short helper function to compute a changing color value. No need to ++ * understand it. ++ */ ++ ++static uint8_t next_color(bool *up, uint8_t cur, unsigned int mod) ++{ ++ uint8_t next; ++ ++ next = cur + (*up ? 1 : -1) * (rand() % mod); ++ if ((*up && next < cur) || (!*up && next > cur)) { ++ *up = !*up; ++ next = cur; ++ } ++ ++ return next; ++} ++ ++/* ++ * modeset_draw(): This draws a solid color into all configured framebuffers. ++ * Every 100ms the color changes to a slightly different color so we get some ++ * kind of smoothly changing color-gradient. ++ * ++ * The color calculation can be ignored as it is pretty boring. So the ++ * interesting stuff is iterating over "modeset_list" and then through all lines ++ * and width. We then set each pixel individually to the current color. ++ * ++ * We do this 50 times as we sleep 100ms after each redraw round. This makes ++ * 50*100ms = 5000ms = 5s so it takes about 5seconds to finish this loop. ++ * ++ * Please note that we draw directly into the framebuffer. This means that you ++ * will see flickering as the monitor might refresh while we redraw the screen. ++ * To avoid this you would need to use two framebuffers and a call to ++ * drmModeSetCrtc() to switch between both buffers. ++ * You can also use drmModePageFlip() to do a vsync'ed pageflip. But this is ++ * beyond the scope of this document. ++ */ ++ ++static void modeset_draw(void) ++{ ++ uint8_t r, g, b; ++ bool r_up, g_up, b_up; ++ unsigned int i, j, k, off; ++ struct modeset_dev *iter; ++ ++ srand(time(NULL)); ++ r = rand() % 0xff; ++ g = rand() % 0xff; ++ b = rand() % 0xff; ++ r_up = g_up = b_up = true; ++ ++ for (i = 0; i < 50; ++i) { ++ r = next_color(&r_up, r, 20); ++ g = next_color(&g_up, g, 10); ++ b = next_color(&b_up, b, 5); ++ ++ for (iter = modeset_list; iter; iter = iter->next) { ++ for (j = 0; j < iter->height; ++j) { ++ for (k = 0; k < iter->width; ++k) { ++ off = iter->stride * j + k * 4; ++ *(uint32_t*)&iter->map[off] = ++ (r << 16) | (g << 8) | b; ++ } ++ } ++ } ++ ++ usleep(100000); ++ } ++} ++ ++/* ++ * modeset_cleanup(fd): This cleans up all the devices we created during ++ * modeset_prepare(). It resets the CRTCs to their saved states and deallocates ++ * all memory. ++ * It should be pretty obvious how all of this works. ++ */ ++ ++static void modeset_cleanup(int fd) ++{ ++ struct modeset_dev *iter; ++ struct drm_mode_destroy_dumb dreq; ++ ++ while (modeset_list) { ++ /* remove from global list */ ++ iter = modeset_list; ++ modeset_list = iter->next; ++ ++ /* restore saved CRTC configuration */ ++ drmModeSetCrtc(fd, ++ iter->saved_crtc->crtc_id, ++ iter->saved_crtc->buffer_id, ++ iter->saved_crtc->x, ++ iter->saved_crtc->y, ++ &iter->conn, ++ 1, ++ &iter->saved_crtc->mode); ++ drmModeFreeCrtc(iter->saved_crtc); ++ ++ /* unmap buffer */ ++ munmap(iter->map, iter->size); ++ ++ /* delete framebuffer */ ++ drmModeRmFB(fd, iter->fb); ++ ++ /* delete dumb buffer */ ++ memset(&dreq, 0, sizeof(dreq)); ++ dreq.handle = iter->handle; ++ drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); ++ ++ /* free allocated memory */ ++ free(iter); ++ } ++} ++ ++/* ++ * I hope this was a short but easy overview of the DRM modesetting API. The DRM ++ * API offers much more capabilities including: ++ * - double-buffering or tripple-buffering (or whatever you want) ++ * - vsync'ed page-flips ++ * - hardware-accelerated rendering (for example via OpenGL) ++ * - output cloning ++ * - graphics-clients plus authentication ++ * - DRM planes/overlays/sprites ++ * - ... ++ * If you are interested in these topics, I can currently only redirect you to ++ * existing implementations, including: ++ * - plymouth (which uses dumb-buffers like this example; very easy to understand) ++ * - kmscon (which uses libuterm to do this) ++ * - wayland (very sophisticated DRM renderer; hard to understand fully as it ++ * uses more complicated techniques like DRM planes) ++ * - xserver (very hard to understand as it is split across many files/projects) ++ * ++ * But understanding how modesetting (as described in this document) works, is ++ * essential to understand all further DRM topics. ++ * ++ * Any feedback is welcome. Feel free to use this code freely for your own ++ * documentation or projects. ++ * ++ * - Hosted on http://github.com/dvdhrm/docs ++ * - Written by David Rheinsberg ++ */ +-- +2.25.1 + diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0012-Implement-drm-backend.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0012-Implement-drm-backend.patch new file mode 100644 index 00000000..1d1e281d --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/files/0012-Implement-drm-backend.patch @@ -0,0 +1,507 @@ +From edc84300b5e5d8b15a87fbb4aee0c83e1a80e9e6 Mon Sep 17 00:00:00 2001 +From: Vasyl Vavrychuk +Date: Mon, 25 Apr 2022 10:59:51 +0300 +Subject: [PATCH 12/17] Implement drm backend + +Limitation is that splash screen is drawn only on the first connector. + +drm-backend backport from: +https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/ + +Signed-off-by: Vasyl Vavrychuk +--- + Makefile.am | 12 +++- + configure.ac | 9 +++ + psplash-drm.c | 179 +++++++++++++++++--------------------------------- + psplash-drm.h | 17 +++++ + psplash.c | 52 +++++++++++---- + 5 files changed, 135 insertions(+), 134 deletions(-) + create mode 100644 psplash-drm.h + +diff --git a/Makefile.am b/Makefile.am +index 375b926..c3d4f03 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -8,12 +8,20 @@ psplash_SOURCES = psplash.c psplash.h psplash-fb.c psplash-fb.h \ + psplash-poky-img.h psplash-bar-img.h $(FONT_NAME)-font.h \ + psplash-draw.c psplash-draw.h + BUILT_SOURCES = psplash-poky-img.h psplash-bar-img.h ++psplash_CPPFLAGS = ++psplash_LDFLAGS = + + psplash_write_SOURCES = psplash-write.c psplash.h + ++if ENABLE_DRM ++psplash_SOURCES += psplash-drm.c psplash-drm.h ++psplash_CPPFLAGS += $(LIBDRM_CFLAGS) -DENABLE_DRM ++psplash_LDFLAGS += $(LIBDRM_LIBS) ++endif ++ + if HAVE_SYSTEMD +-psplash_CPPFLAGS = $(SYSTEMD_CFLAGS) -DHAVE_SYSTEMD +-psplash_LDFLAGS= $(SYSTEMD_LIBS) ++psplash_CPPFLAGS += $(SYSTEMD_CFLAGS) -DHAVE_SYSTEMD ++psplash_LDFLAGS += $(SYSTEMD_LIBS) + bin_PROGRAMS += psplash-systemd + psplash_systemd_CPPFLAGS = $(SYSTEMD_CFLAGS) + psplash_systemd_LDFLAGS= $(SYSTEMD_LIBS) +diff --git a/configure.ac b/configure.ac +index 2a7da91..2e5c4f5 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -12,6 +12,15 @@ if test "x$GCC" = "xyes"; then + GCC_FLAGS="-g -Wall -Wextra" + fi + ++AC_ARG_ENABLE(drm, ++ AS_HELP_STRING([--enable-drm], [enable drm backend (default is 'no')])) ++ ++AS_IF([test "x$enable_drm" = "xyes"], [ ++ PKG_CHECK_MODULES(LIBDRM, libdrm) ++]) ++ ++AM_CONDITIONAL([ENABLE_DRM], [test "x$enable_drm" = "xyes"]) ++ + AC_ARG_WITH([systemd], AS_HELP_STRING([--with-systemd], [Build with systemd + support])) + +diff --git a/psplash-drm.c b/psplash-drm.c +index c9a9f5c..30850ed 100644 +--- a/psplash-drm.c ++++ b/psplash-drm.c +@@ -26,10 +26,8 @@ + * provided by some external library. + */ + +-#define _GNU_SOURCE + #include + #include +-#include + #include + #include + #include +@@ -39,6 +37,7 @@ + #include + #include + #include ++#include "psplash-drm.h" + + struct modeset_dev; + static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn, +@@ -48,8 +47,6 @@ static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn, + struct modeset_dev *dev); + static int modeset_open(int *out, const char *node); + static int modeset_prepare(int fd); +-static void modeset_draw(void); +-static void modeset_cleanup(int fd); + + /* + * When the linux kernel detects a graphics-card on your machine, it loads the +@@ -153,7 +150,7 @@ struct modeset_dev { + uint32_t stride; + uint32_t size; + uint32_t handle; +- uint8_t *map; ++ void *map; + + drmModeModeInfo mode; + uint32_t fb; +@@ -187,7 +184,7 @@ static int modeset_prepare(int fd) + { + drmModeRes *res; + drmModeConnector *conn; +- unsigned int i; ++ int i; + struct modeset_dev *dev; + int ret; + +@@ -338,11 +335,10 @@ static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn, + struct modeset_dev *dev) + { + drmModeEncoder *enc; +- unsigned int i, j; +- int32_t crtc; ++ int i, j, crtc; + struct modeset_dev *iter; + +- /* first try the currently conected encoder+crtc */ ++ /* first try the currently connected encoder+crtc */ + if (conn->encoder_id) + enc = drmModeGetEncoder(fd, conn->encoder_id); + else +@@ -352,7 +348,7 @@ static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn, + if (enc->crtc_id) { + crtc = enc->crtc_id; + for (iter = modeset_list; iter; iter = iter->next) { +- if (iter->crtc == crtc) { ++ if (iter->crtc == (uint32_t)crtc) { + crtc = -1; + break; + } +@@ -389,7 +385,7 @@ static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn, + /* check that no other device already uses this CRTC */ + crtc = res->crtcs[j]; + for (iter = modeset_list; iter; iter = iter->next) { +- if (iter->crtc == crtc) { ++ if (iter->crtc == (uint32_t)crtc) { + crtc = -1; + break; + } +@@ -503,6 +499,12 @@ err_destroy: + return ret; + } + ++static void psplash_drm_flip(PSplashCanvas *canvas, int sync) ++{ ++ (void)canvas; ++ (void)sync; ++} ++ + /* + * Finally! We have a connector with a suitable CRTC. We know which mode we want + * to use and we have a framebuffer of the correct size that we can write to. +@@ -532,155 +534,89 @@ err_destroy: + * also often not guaranteed. So instead, we only use one connector per CRTC. + * + * Before calling drmModeSetCrtc() we also save the current CRTC configuration. +- * This is used in modeset_cleanup() to restore the CRTC to the same mode as was +- * before we changed it. ++ * This is used in psplash_drm_destroy() to restore the CRTC to the same mode as ++ * was before we changed it. + * If we don't do this, the screen will stay blank after we exit until another + * application performs modesetting itself. + */ + +-int main(int argc, char **argv) ++PSplashDRM* psplash_drm_new(int angle, int dev_id) + { +- int ret, fd; +- const char *card; ++ PSplashDRM *drm = NULL; ++ int ret; ++ char card[] = "/dev/dri/card0"; + struct modeset_dev *iter; + +- /* check which DRM device to open */ +- if (argc > 1) +- card = argv[1]; +- else +- card = "/dev/dri/card0"; ++ if ((drm = malloc(sizeof(*drm))) == NULL) { ++ perror("malloc"); ++ goto error; ++ } ++ drm->canvas.priv = drm; ++ drm->canvas.flip = psplash_drm_flip; ++ ++ if (dev_id > 0 && dev_id < 10) { ++ // Conversion from integer to ascii. ++ card[13] = dev_id + 48; ++ } + + fprintf(stderr, "using card '%s'\n", card); + + /* open the DRM device */ +- ret = modeset_open(&fd, card); ++ ret = modeset_open(&drm->fd, card); + if (ret) +- goto out_return; ++ goto error; + + /* prepare all connectors and CRTCs */ +- ret = modeset_prepare(fd); ++ ret = modeset_prepare(drm->fd); + if (ret) +- goto out_close; ++ goto error; + + /* perform actual modesetting on each found connector+CRTC */ + for (iter = modeset_list; iter; iter = iter->next) { +- iter->saved_crtc = drmModeGetCrtc(fd, iter->crtc); +- ret = drmModeSetCrtc(fd, iter->crtc, iter->fb, 0, 0, ++ iter->saved_crtc = drmModeGetCrtc(drm->fd, iter->crtc); ++ ret = drmModeSetCrtc(drm->fd, iter->crtc, iter->fb, 0, 0, + &iter->conn, 1, &iter->mode); + if (ret) + fprintf(stderr, "cannot set CRTC for connector %u (%d): %m\n", + iter->conn, errno); + } + +- /* draw some colors for 5seconds */ +- modeset_draw(); +- +- /* cleanup everything */ +- modeset_cleanup(fd); +- +- ret = 0; +- +-out_close: +- close(fd); +-out_return: +- if (ret) { +- errno = -ret; +- fprintf(stderr, "modeset failed with error %d: %m\n", errno); +- } else { +- fprintf(stderr, "exiting\n"); +- } +- return ret; ++ drm->canvas.data = modeset_list->map; ++ drm->canvas.width = modeset_list->width; ++ drm->canvas.height = modeset_list->height; ++ drm->canvas.bpp = 32; ++ drm->canvas.stride = modeset_list->stride; ++ drm->canvas.angle = angle; ++ drm->canvas.rgbmode = RGB888; ++ ++ return drm; ++error: ++ psplash_drm_destroy(drm); ++ return NULL; + } + + /* +- * A short helper function to compute a changing color value. No need to +- * understand it. +- */ +- +-static uint8_t next_color(bool *up, uint8_t cur, unsigned int mod) +-{ +- uint8_t next; +- +- next = cur + (*up ? 1 : -1) * (rand() % mod); +- if ((*up && next < cur) || (!*up && next > cur)) { +- *up = !*up; +- next = cur; +- } +- +- return next; +-} +- +-/* +- * modeset_draw(): This draws a solid color into all configured framebuffers. +- * Every 100ms the color changes to a slightly different color so we get some +- * kind of smoothly changing color-gradient. +- * +- * The color calculation can be ignored as it is pretty boring. So the +- * interesting stuff is iterating over "modeset_list" and then through all lines +- * and width. We then set each pixel individually to the current color. +- * +- * We do this 50 times as we sleep 100ms after each redraw round. This makes +- * 50*100ms = 5000ms = 5s so it takes about 5seconds to finish this loop. +- * +- * Please note that we draw directly into the framebuffer. This means that you +- * will see flickering as the monitor might refresh while we redraw the screen. +- * To avoid this you would need to use two framebuffers and a call to +- * drmModeSetCrtc() to switch between both buffers. +- * You can also use drmModePageFlip() to do a vsync'ed pageflip. But this is +- * beyond the scope of this document. +- */ +- +-static void modeset_draw(void) +-{ +- uint8_t r, g, b; +- bool r_up, g_up, b_up; +- unsigned int i, j, k, off; +- struct modeset_dev *iter; +- +- srand(time(NULL)); +- r = rand() % 0xff; +- g = rand() % 0xff; +- b = rand() % 0xff; +- r_up = g_up = b_up = true; +- +- for (i = 0; i < 50; ++i) { +- r = next_color(&r_up, r, 20); +- g = next_color(&g_up, g, 10); +- b = next_color(&b_up, b, 5); +- +- for (iter = modeset_list; iter; iter = iter->next) { +- for (j = 0; j < iter->height; ++j) { +- for (k = 0; k < iter->width; ++k) { +- off = iter->stride * j + k * 4; +- *(uint32_t*)&iter->map[off] = +- (r << 16) | (g << 8) | b; +- } +- } +- } +- +- usleep(100000); +- } +-} +- +-/* +- * modeset_cleanup(fd): This cleans up all the devices we created during ++ * psplash_drm_destroy(drm): This cleans up all the devices we created during + * modeset_prepare(). It resets the CRTCs to their saved states and deallocates + * all memory. + * It should be pretty obvious how all of this works. + */ + +-static void modeset_cleanup(int fd) ++void psplash_drm_destroy(PSplashDRM *drm) + { + struct modeset_dev *iter; + struct drm_mode_destroy_dumb dreq; + ++ if (!drm) ++ return; ++ + while (modeset_list) { + /* remove from global list */ + iter = modeset_list; + modeset_list = iter->next; + + /* restore saved CRTC configuration */ +- drmModeSetCrtc(fd, ++ drmModeSetCrtc(drm->fd, + iter->saved_crtc->crtc_id, + iter->saved_crtc->buffer_id, + iter->saved_crtc->x, +@@ -694,16 +630,19 @@ static void modeset_cleanup(int fd) + munmap(iter->map, iter->size); + + /* delete framebuffer */ +- drmModeRmFB(fd, iter->fb); ++ drmModeRmFB(drm->fd, iter->fb); + + /* delete dumb buffer */ + memset(&dreq, 0, sizeof(dreq)); + dreq.handle = iter->handle; +- drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); ++ drmIoctl(drm->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); + + /* free allocated memory */ + free(iter); + } ++ ++ close(drm->fd); ++ free(drm); + } + + /* +diff --git a/psplash-drm.h b/psplash-drm.h +new file mode 100644 +index 0000000..e987fd6 +--- /dev/null ++++ b/psplash-drm.h +@@ -0,0 +1,17 @@ ++#ifndef _HAVE_PSPLASH_DRM_H ++#define _HAVE_PSPLASH_DRM_H ++ ++#include "psplash-draw.h" ++ ++typedef struct PSplashDRM ++{ ++ PSplashCanvas canvas; ++ int fd; ++} ++PSplashDRM; ++ ++void psplash_drm_destroy(PSplashDRM *drm); ++ ++PSplashDRM* psplash_drm_new(int angle, int dev_id); ++ ++#endif +diff --git a/psplash.c b/psplash.c +index 036dfb1..ebf8d7a 100644 +--- a/psplash.c ++++ b/psplash.c +@@ -12,6 +12,9 @@ + + #include "psplash.h" + #include "psplash-fb.h" ++#ifdef ENABLE_DRM ++#include "psplash-drm.h" ++#endif + #include "psplash-config.h" + #include "psplash-colors.h" + #include "psplash-poky-img.h" +@@ -224,8 +227,11 @@ int + main (int argc, char** argv) + { + char *rundir; +- int pipe_fd, i = 0, angle = 0, fbdev_id = 0, ret = 0; +- PSplashFB *fb; ++ int pipe_fd, i = 0, angle = 0, dev_id = 0, use_drm = 0, ret = 0; ++ PSplashFB *fb = NULL; ++#ifdef ENABLE_DRM ++ PSplashDRM *drm = NULL; ++#endif + PSplashCanvas *canvas; + bool disable_console_switch = FALSE; + +@@ -247,16 +253,24 @@ main (int argc, char** argv) + continue; + } + +- if (!strcmp(argv[i],"-f") || !strcmp(argv[i],"--fbdev")) ++ if (!strcmp(argv[i], "-f") || !strcmp(argv[i], "--fbdev") || ++ !strcmp(argv[i], "-d") || !strcmp(argv[i], "--dev")) + { + if (++i >= argc) goto fail; +- fbdev_id = atoi(argv[i]); ++ dev_id = atoi(argv[i]); + continue; + } + ++#ifdef ENABLE_DRM ++ if (!strcmp(argv[i], "--drm")) { ++ use_drm = 1; ++ continue; ++ } ++#endif ++ + fail: + fprintf(stderr, +- "Usage: %s [-n|--no-console-switch][-a|--angle <0|90|180|270>][-f|--fbdev <0..9>]\n", ++ "Usage: %s [-n|--no-console-switch][-a|--angle <0|90|180|270>][-f|--fbdev|-d|--dev <0..9>][--drm]\n", + argv[0]); + exit(-1); + } +@@ -291,12 +305,21 @@ main (int argc, char** argv) + if (!disable_console_switch) + psplash_console_switch (); + +- if ((fb = psplash_fb_new(angle,fbdev_id)) == NULL) +- { +- ret = -1; +- goto fb_fail; ++ if (use_drm) { ++#ifdef ENABLE_DRM ++ if ((drm = psplash_drm_new(angle, dev_id)) == NULL) { ++ ret = -1; ++ goto error; ++ } ++ canvas = &drm->canvas; ++#endif ++ } else { ++ if ((fb = psplash_fb_new(angle, dev_id)) == NULL) { ++ ret = -1; ++ goto error; + } +- canvas = &fb->canvas; ++ canvas = &fb->canvas; ++ } + + #ifdef HAVE_SYSTEMD + sd_notify(0, "READY=1"); +@@ -349,9 +372,14 @@ main (int argc, char** argv) + + psplash_main(canvas, pipe_fd, 0); + +- psplash_fb_destroy (fb); ++ if (fb) ++ psplash_fb_destroy(fb); ++#ifdef ENABLE_DRM ++ if (drm) ++ psplash_drm_destroy(drm); ++#endif + +- fb_fail: ++ error: + unlink(PSPLASH_FIFO); + + if (!disable_console_switch) +-- +2.25.1 + diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0013-Reverse-modeset_list.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0013-Reverse-modeset_list.patch new file mode 100644 index 00000000..e1e171fc --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/files/0013-Reverse-modeset_list.patch @@ -0,0 +1,48 @@ +From 6a73289e30a8b60c65f49ac477e35fd3302bafe0 Mon Sep 17 00:00:00 2001 +From: Vasyl Vavrychuk +Date: Mon, 25 Apr 2022 10:59:52 +0300 +Subject: [PATCH 13/17] Reverse modeset_list + +Now, it has the same order as connectors in drmModeGetResources. As +result splash screen will be drawn on the first connector. + +drm-backend backport from: +https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/ + +Signed-off-by: Vasyl Vavrychuk +--- + psplash-drm.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/psplash-drm.c b/psplash-drm.c +index 30850ed..2468cf1 100644 +--- a/psplash-drm.c ++++ b/psplash-drm.c +@@ -185,7 +185,7 @@ static int modeset_prepare(int fd) + drmModeRes *res; + drmModeConnector *conn; + int i; +- struct modeset_dev *dev; ++ struct modeset_dev *dev, *last_dev = NULL; + int ret; + + /* retrieve resources */ +@@ -226,8 +226,13 @@ static int modeset_prepare(int fd) + + /* free connector data and link device into global list */ + drmModeFreeConnector(conn); +- dev->next = modeset_list; +- modeset_list = dev; ++ if (last_dev == NULL) { ++ modeset_list = dev; ++ last_dev = dev; ++ } else { ++ last_dev->next = dev; ++ last_dev = dev; ++ } + } + + /* free resources again */ +-- +2.25.1 + diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0014-psplash-drm.c-Allocate-resources-only-for-the-first-.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0014-psplash-drm.c-Allocate-resources-only-for-the-first-.patch new file mode 100644 index 00000000..28b1014b --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/files/0014-psplash-drm.c-Allocate-resources-only-for-the-first-.patch @@ -0,0 +1,46 @@ +From 7423f166c8899b84448f68739d5293f19f8dfd06 Mon Sep 17 00:00:00 2001 +From: Vasyl Vavrychuk +Date: Mon, 25 Apr 2022 10:59:53 +0300 +Subject: [PATCH 14/17] psplash-drm.c: Allocate resources only for the first + connector + +Since splash screen is shown only on the first scanout, there is no need +to allocate resources for next connectors. + +drm-backend backport from: +https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/ + +Signed-off-by: Vasyl Vavrychuk +--- + psplash-drm.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/psplash-drm.c b/psplash-drm.c +index 2468cf1..5e56286 100644 +--- a/psplash-drm.c ++++ b/psplash-drm.c +@@ -39,6 +39,8 @@ + #include + #include "psplash-drm.h" + ++#define MIN(a,b) ((a) < (b) ? (a) : (b)) ++ + struct modeset_dev; + static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn, + struct modeset_dev *dev); +@@ -196,8 +198,10 @@ static int modeset_prepare(int fd) + return -errno; + } + +- /* iterate all connectors */ +- for (i = 0; i < res->count_connectors; ++i) { ++ /* ~iterate all connectors~ - Use first connector if present. It is ++ optimization related workaround since psplash supports drawing splash ++ screen on one scanout anyway. */ ++ for (i = 0; i < MIN(res->count_connectors, 1); ++i) { + /* get information for each connector */ + conn = drmModeGetConnector(fd, res->connectors[i]); + if (!conn) { +-- +2.25.1 + diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0015-psplash-drm.c-Implement-double-buffering.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0015-psplash-drm.c-Implement-double-buffering.patch new file mode 100644 index 00000000..cd65c990 --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/files/0015-psplash-drm.c-Implement-double-buffering.patch @@ -0,0 +1,350 @@ +From 266b4808094ae636a64e545f5e59fb612827e0ee Mon Sep 17 00:00:00 2001 +From: Vasyl Vavrychuk +Date: Mon, 25 Apr 2022 10:59:54 +0300 +Subject: [PATCH 15/17] psplash-drm.c: Implement double buffering + +Based on +https://github.com/dvdhrm/docs/blob/master/drm-howto/modeset-double-buffered.c + +drm-backend backport from: +https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/ + +Signed-off-by: Vasyl Vavrychuk +--- + psplash-drm.c | 176 +++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 140 insertions(+), 36 deletions(-) + +diff --git a/psplash-drm.c b/psplash-drm.c +index 5e56286..fcb7507 100644 +--- a/psplash-drm.c ++++ b/psplash-drm.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -41,10 +42,12 @@ + + #define MIN(a,b) ((a) < (b) ? (a) : (b)) + ++struct modeset_buf; + struct modeset_dev; + static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn, + struct modeset_dev *dev); +-static int modeset_create_fb(int fd, struct modeset_dev *dev); ++static int modeset_create_fb(int fd, struct modeset_buf *buf); ++static void modeset_destroy_fb(int fd, struct modeset_buf *buf); + static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn, + struct modeset_dev *dev); + static int modeset_open(int *out, const char *node); +@@ -144,18 +147,45 @@ static int modeset_open(int *out, const char *node) + * } + */ + +-struct modeset_dev { +- struct modeset_dev *next; ++/* ++ * Previously, we used the modeset_dev objects to hold buffer informations, too. ++ * Technically, we could have split them but avoided this to make the ++ * example simpler. ++ * However, in this example we need 2 buffers. One back buffer and one front ++ * buffer. So we introduce a new structure modeset_buf which contains everything ++ * related to a single buffer. Each device now gets an array of two of these ++ * buffers. ++ * Each buffer consists of width, height, stride, size, handle, map and fb-id. ++ * They have the same meaning as before. ++ * ++ * Each device also gets a new integer field: front_buf. This field contains the ++ * index of the buffer that is currently used as front buffer / scanout buffer. ++ * In our example it can be 0 or 1. We flip it by using XOR: ++ * dev->front_buf ^= dev->front_buf ++ * ++ * Everything else stays the same. ++ */ + ++struct modeset_buf { + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t size; + uint32_t handle; + void *map; ++ uint32_t fb; ++}; ++ ++struct modeset_dev { ++ struct modeset_dev *next; ++ ++ uint32_t width; ++ uint32_t height; ++ ++ unsigned int front_buf; ++ struct modeset_buf bufs[2]; + + drmModeModeInfo mode; +- uint32_t fb; + uint32_t conn; + uint32_t crtc; + drmModeCrtc *saved_crtc; +@@ -292,10 +322,15 @@ static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn, + return -EFAULT; + } + +- /* copy the mode information into our device structure */ ++ /* copy the mode information into our device structure and into both ++ * buffers */ + memcpy(&dev->mode, &conn->modes[0], sizeof(dev->mode)); + dev->width = conn->modes[0].hdisplay; + dev->height = conn->modes[0].vdisplay; ++ dev->bufs[0].width = dev->width; ++ dev->bufs[0].height = dev->height; ++ dev->bufs[1].width = dev->width; ++ dev->bufs[1].height = dev->height; + fprintf(stderr, "mode for connector %u is %ux%u\n", + conn->connector_id, dev->width, dev->height); + +@@ -307,14 +342,30 @@ static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn, + return ret; + } + +- /* create a framebuffer for this CRTC */ +- ret = modeset_create_fb(fd, dev); ++ /* create framebuffer #1 for this CRTC */ ++ ret = modeset_create_fb(fd, &dev->bufs[0]); + if (ret) { + fprintf(stderr, "cannot create framebuffer for connector %u\n", + conn->connector_id); + return ret; + } + ++ /* create framebuffer #2 for this CRTC */ ++ ret = modeset_create_fb(fd, &dev->bufs[1]); ++ if (ret) { ++ fprintf(stderr, "cannot create framebuffer for connector %u\n", ++ conn->connector_id); ++ modeset_destroy_fb(fd, &dev->bufs[0]); ++ return ret; ++ } ++ ++ if (dev->bufs[0].size != dev->bufs[1].size) { ++ fprintf(stderr, "front buffer size %" PRIu32 " does not match " ++ "back buffer size %" PRIu32 "\n", ++ dev->bufs[0].size, dev->bufs[1].size); ++ return -1; ++ } ++ + return 0; + } + +@@ -441,7 +492,7 @@ static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn, + * memory directly via the dev->map memory map. + */ + +-static int modeset_create_fb(int fd, struct modeset_dev *dev) ++static int modeset_create_fb(int fd, struct modeset_buf *buf) + { + struct drm_mode_create_dumb creq; + struct drm_mode_destroy_dumb dreq; +@@ -450,8 +501,8 @@ static int modeset_create_fb(int fd, struct modeset_dev *dev) + + /* create dumb buffer */ + memset(&creq, 0, sizeof(creq)); +- creq.width = dev->width; +- creq.height = dev->height; ++ creq.width = buf->width; ++ creq.height = buf->height; + creq.bpp = 32; + ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq); + if (ret < 0) { +@@ -459,13 +510,13 @@ static int modeset_create_fb(int fd, struct modeset_dev *dev) + errno); + return -errno; + } +- dev->stride = creq.pitch; +- dev->size = creq.size; +- dev->handle = creq.handle; ++ buf->stride = creq.pitch; ++ buf->size = creq.size; ++ buf->handle = creq.handle; + + /* create framebuffer object for the dumb-buffer */ +- ret = drmModeAddFB(fd, dev->width, dev->height, 24, 32, dev->stride, +- dev->handle, &dev->fb); ++ ret = drmModeAddFB(fd, buf->width, buf->height, 24, 32, buf->stride, ++ buf->handle, &buf->fb); + if (ret) { + fprintf(stderr, "cannot create framebuffer (%d): %m\n", + errno); +@@ -475,7 +526,7 @@ static int modeset_create_fb(int fd, struct modeset_dev *dev) + + /* prepare buffer for memory mapping */ + memset(&mreq, 0, sizeof(mreq)); +- mreq.handle = dev->handle; ++ mreq.handle = buf->handle; + ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); + if (ret) { + fprintf(stderr, "cannot map dumb buffer (%d): %m\n", +@@ -485,9 +536,9 @@ static int modeset_create_fb(int fd, struct modeset_dev *dev) + } + + /* perform actual memory mapping */ +- dev->map = mmap(0, dev->size, PROT_READ | PROT_WRITE, MAP_SHARED, ++ buf->map = mmap(0, buf->size, PROT_READ | PROT_WRITE, MAP_SHARED, + fd, mreq.offset); +- if (dev->map == MAP_FAILED) { ++ if (buf->map == MAP_FAILED) { + fprintf(stderr, "cannot mmap dumb buffer (%d): %m\n", + errno); + ret = -errno; +@@ -495,23 +546,73 @@ static int modeset_create_fb(int fd, struct modeset_dev *dev) + } + + /* clear the framebuffer to 0 */ +- memset(dev->map, 0, dev->size); ++ memset(buf->map, 0, buf->size); + + return 0; + + err_fb: +- drmModeRmFB(fd, dev->fb); ++ drmModeRmFB(fd, buf->fb); + err_destroy: + memset(&dreq, 0, sizeof(dreq)); +- dreq.handle = dev->handle; ++ dreq.handle = buf->handle; + drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); + return ret; + } + ++/* ++ * modeset_destroy_fb() is a new function. It does exactly the reverse of ++ * modeset_create_fb() and destroys a single framebuffer. The modeset.c example ++ * used to do this directly in modeset_cleanup(). ++ * We simply unmap the buffer, remove the drm-FB and destroy the memory buffer. ++ */ ++ ++static void modeset_destroy_fb(int fd, struct modeset_buf *buf) ++{ ++ struct drm_mode_destroy_dumb dreq; ++ ++ /* unmap buffer */ ++ munmap(buf->map, buf->size); ++ ++ /* delete framebuffer */ ++ drmModeRmFB(fd, buf->fb); ++ ++ /* delete dumb buffer */ ++ memset(&dreq, 0, sizeof(dreq)); ++ dreq.handle = buf->handle; ++ drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); ++} ++ + static void psplash_drm_flip(PSplashCanvas *canvas, int sync) + { +- (void)canvas; ++ PSplashDRM *drm = canvas->priv; ++ struct modeset_buf *buf; ++ int ret; ++ + (void)sync; ++ ++ /* pick a back buffer */ ++ buf = &modeset_list->bufs[modeset_list->front_buf ^ 1]; ++ ++ /* set back buffer as a front buffer */ ++ ret = drmModeSetCrtc(drm->fd, modeset_list->crtc, buf->fb, 0, 0, ++ &modeset_list->conn, 1, &modeset_list->mode); ++ if (ret) { ++ fprintf(stderr, "cannot flip CRTC for connector %u (%d): %m\n", ++ modeset_list->conn, errno); ++ return; ++ } ++ ++ /* update front buffer index */ ++ modeset_list->front_buf ^= 1; ++ ++ /* update back buffer pointer */ ++ drm->canvas.data = modeset_list->bufs[modeset_list->front_buf ^ 1].map; ++ ++ /* Sync new front to new back when requested */ ++ if (sync) ++ memcpy(modeset_list->bufs[modeset_list->front_buf ^ 1].map, ++ modeset_list->bufs[modeset_list->front_buf].map, ++ modeset_list->bufs[0].size); + } + + /* +@@ -555,6 +656,7 @@ PSplashDRM* psplash_drm_new(int angle, int dev_id) + int ret; + char card[] = "/dev/dri/card0"; + struct modeset_dev *iter; ++ struct modeset_buf *buf; + + if ((drm = malloc(sizeof(*drm))) == NULL) { + perror("malloc"); +@@ -583,18 +685,28 @@ PSplashDRM* psplash_drm_new(int angle, int dev_id) + /* perform actual modesetting on each found connector+CRTC */ + for (iter = modeset_list; iter; iter = iter->next) { + iter->saved_crtc = drmModeGetCrtc(drm->fd, iter->crtc); +- ret = drmModeSetCrtc(drm->fd, iter->crtc, iter->fb, 0, 0, ++ buf = &iter->bufs[iter->front_buf]; ++ ret = drmModeSetCrtc(drm->fd, iter->crtc, buf->fb, 0, 0, + &iter->conn, 1, &iter->mode); + if (ret) + fprintf(stderr, "cannot set CRTC for connector %u (%d): %m\n", + iter->conn, errno); + } + +- drm->canvas.data = modeset_list->map; ++ drm->canvas.data = modeset_list->bufs[modeset_list->front_buf ^ 1].map; + drm->canvas.width = modeset_list->width; + drm->canvas.height = modeset_list->height; + drm->canvas.bpp = 32; +- drm->canvas.stride = modeset_list->stride; ++ ++ if (modeset_list->bufs[0].stride != modeset_list->bufs[1].stride) { ++ fprintf(stderr, "front buffer stride %" PRIu32 " does not match" ++ " back buffer stride %" PRIu32 "\n", ++ modeset_list->bufs[0].stride, ++ modeset_list->bufs[1].stride); ++ goto error; ++ } ++ drm->canvas.stride = modeset_list->bufs[0].stride; ++ + drm->canvas.angle = angle; + drm->canvas.rgbmode = RGB888; + +@@ -614,7 +726,6 @@ error: + void psplash_drm_destroy(PSplashDRM *drm) + { + struct modeset_dev *iter; +- struct drm_mode_destroy_dumb dreq; + + if (!drm) + return; +@@ -635,16 +746,9 @@ void psplash_drm_destroy(PSplashDRM *drm) + &iter->saved_crtc->mode); + drmModeFreeCrtc(iter->saved_crtc); + +- /* unmap buffer */ +- munmap(iter->map, iter->size); +- +- /* delete framebuffer */ +- drmModeRmFB(drm->fd, iter->fb); +- +- /* delete dumb buffer */ +- memset(&dreq, 0, sizeof(dreq)); +- dreq.handle = iter->handle; +- drmIoctl(drm->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); ++ /* destroy framebuffers */ ++ modeset_destroy_fb(drm->fd, &iter->bufs[1]); ++ modeset_destroy_fb(drm->fd, &iter->bufs[0]); + + /* free allocated memory */ + free(iter); +-- +2.25.1 + diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0016-Imprement-drm-lease-support.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0016-Imprement-drm-lease-support.patch new file mode 100644 index 00000000..6a4bf387 --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/files/0016-Imprement-drm-lease-support.patch @@ -0,0 +1,189 @@ +From 0fcca6600c7d74ec13986d3e9e795f4a7c8afe59 Mon Sep 17 00:00:00 2001 +From: Hiroyuki Ishii +Date: Tue, 27 Dec 2022 16:43:46 +0900 +Subject: [PATCH 16/17] Imprement drm-lease support + +Basic support to utilize drm-lease device via drm-lease-manager. + +Known issue: +- --angle option does not work correctly with drm-lease enabled + +Signed-off-by: Hiroyuki Ishii +--- + Makefile.am | 5 +++++ + configure.ac | 9 +++++++++ + psplash-drm-lease.h | 10 ++++++++++ + psplash-drm.c | 44 +++++++++++++++++++++++++++++++++++++++----- + psplash.c | 12 ++++++++++++ + 5 files changed, 75 insertions(+), 5 deletions(-) + create mode 100644 psplash-drm-lease.h + +diff --git a/Makefile.am b/Makefile.am +index c3d4f03..3657889 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -19,6 +19,11 @@ psplash_CPPFLAGS += $(LIBDRM_CFLAGS) -DENABLE_DRM + psplash_LDFLAGS += $(LIBDRM_LIBS) + endif + ++if ENABLE_DRM_LEASE ++psplash_CPPFLAGS += $(LIBDRM_LEASE_CFLAGS) -DENABLE_DRM_LEASE ++psplash_LDFLAGS += $(LIBDRM_LEASE_LIBS) ++endif ++ + if HAVE_SYSTEMD + psplash_CPPFLAGS += $(SYSTEMD_CFLAGS) -DHAVE_SYSTEMD + psplash_LDFLAGS += $(SYSTEMD_LIBS) +diff --git a/configure.ac b/configure.ac +index 2e5c4f5..1a752e3 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -21,6 +21,15 @@ AS_IF([test "x$enable_drm" = "xyes"], [ + + AM_CONDITIONAL([ENABLE_DRM], [test "x$enable_drm" = "xyes"]) + ++AC_ARG_ENABLE(drm-lease, ++ AS_HELP_STRING([--enable-drm-lease], [enable drm-lease (default is 'no')])) ++ ++AS_IF([test "x$enable_drm_lease" = "xyes"], [ ++ PKG_CHECK_MODULES(LIBDRM_LEASE, libdlmclient) ++]) ++ ++AM_CONDITIONAL([ENABLE_DRM_LEASE], [test "x$enable_drm_lease" = "xyes"]) ++ + AC_ARG_WITH([systemd], AS_HELP_STRING([--with-systemd], [Build with systemd + support])) + +diff --git a/psplash-drm-lease.h b/psplash-drm-lease.h +new file mode 100644 +index 0000000..46289c3 +--- /dev/null ++++ b/psplash-drm-lease.h +@@ -0,0 +1,10 @@ ++#ifndef _HAVE_PSPLASH_DRM_LEASE_H ++#define _HAVE_PSPLASH_DRM_LEASE_H ++#ifdef ENABLE_DRM_LEASE ++ ++#include ++ ++void drm_set_lease_name(char *); ++ ++#endif // ENABLE_DRM_LEASE ++#endif // _HAVE_PSPLASH_DRM_LEASE_H +diff --git a/psplash-drm.c b/psplash-drm.c +index fcb7507..a5aff90 100644 +--- a/psplash-drm.c ++++ b/psplash-drm.c +@@ -39,6 +39,9 @@ + #include + #include + #include "psplash-drm.h" ++#ifdef ENABLE_DRM_LEASE ++#include "psplash-drm-lease.h" ++#endif + + #define MIN(a,b) ((a) < (b) ? (a) : (b)) + +@@ -53,6 +56,10 @@ static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn, + static int modeset_open(int *out, const char *node); + static int modeset_prepare(int fd); + ++#ifdef ENABLE_DRM_LEASE ++char *drm_lease_name; ++#endif ++ + /* + * When the linux kernel detects a graphics-card on your machine, it loads the + * correct device driver (located in kernel-tree at ./drivers/gpu/drm/) and +@@ -662,6 +669,7 @@ PSplashDRM* psplash_drm_new(int angle, int dev_id) + perror("malloc"); + goto error; + } ++ drm->fd = 0; + drm->canvas.priv = drm; + drm->canvas.flip = psplash_drm_flip; + +@@ -670,12 +678,30 @@ PSplashDRM* psplash_drm_new(int angle, int dev_id) + card[13] = dev_id + 48; + } + +- fprintf(stderr, "using card '%s'\n", card); ++#ifdef ENABLE_DRM_LEASE ++ if (drm_lease_name) { ++ fprintf(stderr, "using drm lease '%s'\n", drm_lease_name); ++ struct dlm_lease *lease = dlm_get_lease(drm_lease_name); ++ if (lease) { ++ drm->fd = dlm_lease_fd(lease); ++ if (!drm->fd) ++ dlm_release_lease(lease); ++ } ++ if (!drm->fd) { ++ fprintf(stderr, "Could not get DRM lease %s\n", drm_lease_name); ++ goto error; ++ } ++ } ++#endif + +- /* open the DRM device */ +- ret = modeset_open(&drm->fd, card); +- if (ret) +- goto error; ++ if (!drm->fd) { ++ fprintf(stderr, "using card '%s'\n", card); ++ ++ /* open the DRM device */ ++ ret = modeset_open(&drm->fd, card); ++ if (ret) ++ goto error; ++ } + + /* prepare all connectors and CRTCs */ + ret = modeset_prepare(drm->fd); +@@ -758,6 +784,14 @@ void psplash_drm_destroy(PSplashDRM *drm) + free(drm); + } + ++#ifdef ENABLE_DRM_LEASE ++void drm_set_lease_name (char *name) { ++ if (!name) ++ return; ++ drm_lease_name = strdup(name); ++} ++#endif ++ + /* + * I hope this was a short but easy overview of the DRM modesetting API. The DRM + * API offers much more capabilities including: +diff --git a/psplash.c b/psplash.c +index ebf8d7a..4aa650d 100644 +--- a/psplash.c ++++ b/psplash.c +@@ -15,6 +15,9 @@ + #ifdef ENABLE_DRM + #include "psplash-drm.h" + #endif ++#ifdef ENABLE_DRM_LEASE ++#include "psplash-drm-lease.h" ++#endif + #include "psplash-config.h" + #include "psplash-colors.h" + #include "psplash-poky-img.h" +@@ -267,6 +270,15 @@ main (int argc, char** argv) + continue; + } + #endif ++#ifdef ENABLE_DRM_LEASE ++ if (!strcmp(argv[i],"--drm-lease")) ++ { ++ if (++i >= argc) goto fail; ++ drm_set_lease_name(argv[i]); ++ use_drm = 1; ++ continue; ++ } ++#endif + + fail: + fprintf(stderr, +-- +2.25.1 + diff --git a/meta-agl-drm-lease/recipes-core/psplash/files/0017-drm-lease-Fix-incorrect-drawing-with-portrait-orient.patch b/meta-agl-drm-lease/recipes-core/psplash/files/0017-drm-lease-Fix-incorrect-drawing-with-portrait-orient.patch new file mode 100644 index 00000000..d68bc49d --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/files/0017-drm-lease-Fix-incorrect-drawing-with-portrait-orient.patch @@ -0,0 +1,42 @@ +From a4f7a5f0dd287895461cd007b23094459b6b88cb Mon Sep 17 00:00:00 2001 +From: Hiroyuki Ishii +Date: Wed, 28 Dec 2022 15:17:24 +0900 +Subject: [PATCH 17/17] drm-lease: Fix incorrect drawing with portrait + orientation + +Signed-off-by: Hiroyuki Ishii +--- + psplash-drm.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/psplash-drm.c b/psplash-drm.c +index a5aff90..c20df13 100644 +--- a/psplash-drm.c ++++ b/psplash-drm.c +@@ -736,6 +736,23 @@ PSplashDRM* psplash_drm_new(int angle, int dev_id) + drm->canvas.angle = angle; + drm->canvas.rgbmode = RGB888; + ++ /* ++ * There seems some difference about handling portrait angle between ++ * pure drm vs drm-lease. We'd use a method as same with psplash-fb ++ * for drm-lease devices. ++ */ ++ if (drm_lease_name) { ++ switch (angle) { ++ case 270: ++ case 90: ++ drm->canvas.width = modeset_list->height; ++ drm->canvas.height = modeset_list->width; ++ break; ++ default: ++ break; ++ } ++ } ++ + return drm; + error: + psplash_drm_destroy(drm); +-- +2.25.1 + diff --git a/meta-agl-drm-lease/recipes-core/psplash/psplash_git.bbappend b/meta-agl-drm-lease/recipes-core/psplash/psplash_git.bbappend new file mode 100644 index 00000000..56650669 --- /dev/null +++ b/meta-agl-drm-lease/recipes-core/psplash/psplash_git.bbappend @@ -0,0 +1,43 @@ +FILESEXTRAPATHS:prepend := "${THISDIR}/files:" + +# drm-backend backport from: +# https://patchwork.yoctoproject.org/project/yocto/cover/20220425075954.10427-1-vasyl.vavrychuk@opensynergy.com/ +SRC_URI += " \ + file://0001-Fix-duplicated-definition-of-bool.patch \ + file://0002-Trim-trailing-spaces.patch \ + file://0003-Fix-unused-result-warnings.patch \ + file://0004-Remove-unused-save_termios.patch \ + file://0005-Remove-psplash-fb.h-from-psplash.h.patch \ + file://0006-Extract-plot-pixel-from-psplash-fb.patch \ + file://0007-Extract-draw-rect-image-from-psplash-fb.patch \ + file://0008-Extract-draw-font-from-psplash-fb.patch \ + file://0009-psplash.c-Make-psplash_draw_-msg-progress-independen.patch \ + file://0010-Rework-flip-as-function-pointer.patch \ + file://0011-Import-drm-howto-modeset.c-as-psplash-drm.c.patch \ + file://0012-Implement-drm-backend.patch \ + file://0013-Reverse-modeset_list.patch \ + file://0014-psplash-drm.c-Allocate-resources-only-for-the-first-.patch \ + file://0015-psplash-drm.c-Implement-double-buffering.patch \ + " + +# drm-lease support from: +# https://github.com/agl-ic-eg/meta-agl-demo/tree/main/recipes-core/psplash +SRC_URI += " \ + file://0016-Imprement-drm-lease-support.patch \ + file://0017-drm-lease-Fix-incorrect-drawing-with-portrait-orient.patch \ + " + +# Licesnse checksum was changed by above patches +LIC_FILES_CHKSUM = "file://psplash.h;beginline=1;endline=8;md5=db1ed16abf4be6de3d79201093ac4f07" + +PACKAGECONFIG[drm] = "--enable-drm,,libdrm" +PSPLASH_ARGS += "${@bb.utils.contains('PACKAGECONFIG', 'drm', '--drm', '', d)}" + +PACKAGECONFIG[drm-lease] = "--enable-drm-lease,,drm-lease-manager" +PSPLASH_DRM_LEASE_ARGS ??= "--drm-lease lease0" +PSPLASH_ARGS += "${@bb.utils.contains('PACKAGECONFIG', 'drm-lease', '${PSPLASH_DRM_LEASE_ARGS}', '', d)}" +RDEPENDS:${PN} += "${@bb.utils.contains('PACKAGECONFIG', 'drm-lease', 'drm-lease-manager', '', d)}" + +do_install:append () { + sed -i -e "s!^\(ExecStart=/usr/bin/psplash.*\)!\1 ${PSPLASH_ARGS}!" ${D}${systemd_system_unitdir}/psplash-start.service +} -- cgit 1.2.3-korg