Enable drm-lease support at psplash 92/28692/2
authorNaoto Yamaguchi <naoto.yamaguchi@aisin.co.jp>
Sun, 23 Apr 2023 11:25:45 +0000 (20:25 +0900)
committerNaoto Yamaguchi <naoto.yamaguchi@aisin.co.jp>
Mon, 8 May 2023 23:13:10 +0000 (08:13 +0900)
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 <naoto.yamaguchi@aisin.co.jp>
18 files changed:
meta-agl-drm-lease/recipes-core/psplash/files/0001-Fix-duplicated-definition-of-bool.patch [new file with mode: 0644]
meta-agl-drm-lease/recipes-core/psplash/files/0002-Trim-trailing-spaces.patch [new file with mode: 0644]
meta-agl-drm-lease/recipes-core/psplash/files/0003-Fix-unused-result-warnings.patch [new file with mode: 0644]
meta-agl-drm-lease/recipes-core/psplash/files/0004-Remove-unused-save_termios.patch [new file with mode: 0644]
meta-agl-drm-lease/recipes-core/psplash/files/0005-Remove-psplash-fb.h-from-psplash.h.patch [new file with mode: 0644]
meta-agl-drm-lease/recipes-core/psplash/files/0006-Extract-plot-pixel-from-psplash-fb.patch [new file with mode: 0644]
meta-agl-drm-lease/recipes-core/psplash/files/0007-Extract-draw-rect-image-from-psplash-fb.patch [new file with mode: 0644]
meta-agl-drm-lease/recipes-core/psplash/files/0008-Extract-draw-font-from-psplash-fb.patch [new file with mode: 0644]
meta-agl-drm-lease/recipes-core/psplash/files/0009-psplash.c-Make-psplash_draw_-msg-progress-independen.patch [new file with mode: 0644]
meta-agl-drm-lease/recipes-core/psplash/files/0010-Rework-flip-as-function-pointer.patch [new file with mode: 0644]
meta-agl-drm-lease/recipes-core/psplash/files/0011-Import-drm-howto-modeset.c-as-psplash-drm.c.patch [new file with mode: 0644]
meta-agl-drm-lease/recipes-core/psplash/files/0012-Implement-drm-backend.patch [new file with mode: 0644]
meta-agl-drm-lease/recipes-core/psplash/files/0013-Reverse-modeset_list.patch [new file with mode: 0644]
meta-agl-drm-lease/recipes-core/psplash/files/0014-psplash-drm.c-Allocate-resources-only-for-the-first-.patch [new file with mode: 0644]
meta-agl-drm-lease/recipes-core/psplash/files/0015-psplash-drm.c-Implement-double-buffering.patch [new file with mode: 0644]
meta-agl-drm-lease/recipes-core/psplash/files/0016-Imprement-drm-lease-support.patch [new file with mode: 0644]
meta-agl-drm-lease/recipes-core/psplash/files/0017-drm-lease-Fix-incorrect-drawing-with-portrait-orient.patch [new file with mode: 0644]
meta-agl-drm-lease/recipes-core/psplash/psplash_git.bbappend [new file with mode: 0644]

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 (file)
index 0000000..ae533b7
--- /dev/null
@@ -0,0 +1,35 @@
+From 816b7168c6380ec5a72416d3e0c52e22d891e2d9 Mon Sep 17 00:00:00 2001
+From: Hiroyuki Ishii <ishii.hiroyuki002@jp.panasonic.com>
+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 <ishii.hiroyuki002@jp.panasonic.com>
+---
+ 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 <sys/types.h>
+ #include <termios.h>
+ #include <unistd.h>
++#include <stdbool.h>
+ 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 (file)
index 0000000..2980809
--- /dev/null
@@ -0,0 +1,535 @@
+From 5f82ef966776c9520af8ca59d12260d7e908e464 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+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 <vasyl.vavrychuk@opensynergy.com>
+---
+ 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 <mallum@o-hand.com>
+  *
+@@ -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 <mallum@o-hand.com>
+  *
+@@ -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 <mallum@o-hand.com>
+  *
+@@ -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 <mallum@o-hand.com>
+  *
+@@ -19,7 +19,7 @@
+ #include <errno.h>
+ #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 <mallum@o-hand.com>
+  *
+- *  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 <mallum@o-hand.com>
+  *
+-- 
+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 (file)
index 0000000..948609d
--- /dev/null
@@ -0,0 +1,150 @@
+From edb01af9b4789b9c3b908329f6be5819e2cfe954 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+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 <vasyl.vavrychuk@opensynergy.com>
+---
+ 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 (file)
index 0000000..7c105ea
--- /dev/null
@@ -0,0 +1,41 @@
+From 733b6d8ae3ed8d5d2972c717bb9a94f65ff6f194 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+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 <vasyl.vavrychuk@opensynergy.com>
+---
+ 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 <sys/stat.h>
+ #include <sys/time.h>
+ #include <sys/types.h>
+-#include <termios.h>
+ #include <unistd.h>
+ #include <stdbool.h>
+-- 
+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 (file)
index 0000000..602d703
--- /dev/null
@@ -0,0 +1,81 @@
+From 2f1fe1b5233d69cf354ffb5ab182810ef74c7e3d Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+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 <vasyl.vavrychuk@opensynergy.com>
+---
+ 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 <endian.h>
+-#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 <linux/fb.h>
++#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 <errno.h>
+ #include <fcntl.h>
+ #include <limits.h>
+-#include <linux/fb.h>
+ #include <linux/kd.h>
+ #include <linux/vt.h>
+ #include <signal.h>
+@@ -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 (file)
index 0000000..5627d5e
--- /dev/null
@@ -0,0 +1,624 @@
+From f0504ac0abd16b5e98456fb3ea2777e6b64418ec Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+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 <vasyl.vavrychuk@opensynergy.com>
+---
+ 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 <mallum@o-hand.com>
++ *
++ *  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 <mallum@o-hand.com>
++ *
++ *  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 <linux/fb.h>
+-#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 (file)
index 0000000..2e897d4
--- /dev/null
@@ -0,0 +1,299 @@
+From d0f899114600ee25eb2d7d2c089deb549c371bd2 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+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 <vasyl.vavrychuk@opensynergy.com>
+---
+ 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 (file)
index 0000000..a62e939
--- /dev/null
@@ -0,0 +1,350 @@
+From 532e889486ed4c6b254893e89c63cc4395cc83da Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+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 <vasyl.vavrychuk@opensynergy.com>
+---
+ 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 (file)
index 0000000..9cd2692
--- /dev/null
@@ -0,0 +1,191 @@
+From 1046e65f7cca2b592fbb7e8f0d1392fb742a67b1 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+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 <vasyl.vavrychuk@opensynergy.com>
+---
+ 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 (file)
index 0000000..2d897a3
--- /dev/null
@@ -0,0 +1,141 @@
+From e1004cd1a1252a17219f5ebd13749c91e8ddc09b Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+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 <vasyl.vavrychuk@opensynergy.com>
+---
+ 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 (file)
index 0000000..767dbf4
--- /dev/null
@@ -0,0 +1,764 @@
+From d5a9fb5cd8505c16d4d75c695af1e64597d36c86 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+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 <vasyl.vavrychuk@opensynergy.com>
+---
+ 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 <david.rheinsberg@gmail.com>
++ * 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 <errno.h>
++#include <fcntl.h>
++#include <stdbool.h>
++#include <stdint.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/mman.h>
++#include <time.h>
++#include <unistd.h>
++#include <xf86drm.h>
++#include <xf86drmMode.h>
++
++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/<xy>) 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 <david.rheinsberg@gmail.com>
++ */
+-- 
+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 (file)
index 0000000..1d1e281
--- /dev/null
@@ -0,0 +1,507 @@
+From edc84300b5e5d8b15a87fbb4aee0c83e1a80e9e6 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+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 <vasyl.vavrychuk@opensynergy.com>
+---
+ 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 <errno.h>
+ #include <fcntl.h>
+-#include <stdbool.h>
+ #include <stdint.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+@@ -39,6 +37,7 @@
+ #include <unistd.h>
+ #include <xf86drm.h>
+ #include <xf86drmMode.h>
++#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 (file)
index 0000000..e1e171f
--- /dev/null
@@ -0,0 +1,48 @@
+From 6a73289e30a8b60c65f49ac477e35fd3302bafe0 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+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 <vasyl.vavrychuk@opensynergy.com>
+---
+ 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 (file)
index 0000000..28b1014
--- /dev/null
@@ -0,0 +1,46 @@
+From 7423f166c8899b84448f68739d5293f19f8dfd06 Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+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 <vasyl.vavrychuk@opensynergy.com>
+---
+ 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 <xf86drmMode.h>
+ #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 (file)
index 0000000..cd65c99
--- /dev/null
@@ -0,0 +1,350 @@
+From 266b4808094ae636a64e545f5e59fb612827e0ee Mon Sep 17 00:00:00 2001
+From: Vasyl Vavrychuk <vasyl.vavrychuk@opensynergy.com>
+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 <vasyl.vavrychuk@opensynergy.com>
+---
+ 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 <errno.h>
+ #include <fcntl.h>
+ #include <stdint.h>
++#include <inttypes.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -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 (file)
index 0000000..6a4bf38
--- /dev/null
@@ -0,0 +1,189 @@
+From 0fcca6600c7d74ec13986d3e9e795f4a7c8afe59 Mon Sep 17 00:00:00 2001
+From: Hiroyuki Ishii <ishii.hiroyuki002@jp.panasonic.com>
+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 <ishii.hiroyuki002@jp.panasonic.com>
+---
+ 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 <dlmclient.h>
++
++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 <xf86drm.h>
+ #include <xf86drmMode.h>
+ #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/<xy>) 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 (file)
index 0000000..d68bc49
--- /dev/null
@@ -0,0 +1,42 @@
+From a4f7a5f0dd287895461cd007b23094459b6b88cb Mon Sep 17 00:00:00 2001
+From: Hiroyuki Ishii <ishii.hiroyuki002@jp.panasonic.com>
+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 <ishii.hiroyuki002@jp.panasonic.com>
+---
+ 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 (file)
index 0000000..5665066
--- /dev/null
@@ -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
+}