grub-devel.gnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 0/3] framebuffer rotation
@ 2024-06-18  4:14 kbader94
  2024-06-18  4:14 ` [PATCH v1 1/3] dirty 2d kbader94
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: kbader94 @ 2024-06-18  4:14 UTC (permalink / raw
  To: grub-devel; +Cc: kbader94

This patch series implements a framebuffer rotation configuration option which allows the user to specify a rotation translation to be applied to the video output from grub, such that user can programatically rotate the display. This enables grub to be used in nonstandard display mounting schemes such as portrait mode.

    Patch 1: dirty-2d - track and update 2d regions in the framebuffer. This simplifies the implementation of the framebuffer rotation.
    Patch 2: frambuffer rotation - numerous changes in the video_fb subsystem to enable specifying render_target rotation.
    Patch 3: enables setting the framebuffer rotation by setting GRUB_FB_ROTATION in /etc/default/grub. NOTE. rotation is passed on to linux unless GRUB_GFXPAYLOAD_LINUX = text

Status: Works as intended, however some optimizations(particularly in the blitting functions) have been left for future implementation.

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v1 1/3] dirty 2d
  2024-06-18  4:14 [PATCH v1 0/3] framebuffer rotation kbader94
@ 2024-06-18  4:14 ` kbader94
  2024-06-18  4:14 ` [PATCH v1 2/3] framebuffer rotation kbader94
  2024-06-18  4:14 ` [PATCH v1 3/3] fb rotation - Add config option to grub-mkconfig to enable setting GRUB_FB_ROTATION in grub's config file. Setting GRUB_FB_ROTATION to 90, 180, 270, 'left', 'right', or 'inverted' will set the rotation for both grub AND linux. For linux, the changes are passed on to linux kernel entries if GRUB_GFXPAYLOAD_LINUX = 'keep' kbader94
  2 siblings, 0 replies; 4+ messages in thread
From: kbader94 @ 2024-06-18  4:14 UTC (permalink / raw
  To: grub-devel; +Cc: kbader94

Modify the dirty function so it tracks and updates 2d regions. The current dirty() implementation only tracks the y coordinate changes, and then updates all the pixels in between the changed(dirty) y coordinates, such that the entire screen's width is updated even if just a single 16x16 pixel character was updated(dirtied). This patch modifies render_targets to use grub_video_rects to track dirty regions instead of the previous dirty struct. dirty callees are then modified appropriately using 2d coordinates. Finally the doublebuf_*_update_screen functions are modified to update 2d regions by making multiple grub_memcpy calls to the framebuffer, one for each row of pixels being updated(instead of a single call for the contiguous block of framebuffer data as was previously done).

 Changes to be committed:
	modified:   grub-core/video/fb/video_fb.c

Signed-off-by: kbader94 <kyle.bader94@gmail.com>
---
 grub-core/video/fb/video_fb.c | 199 +++++++++++++++++++++-------------
 1 file changed, 122 insertions(+), 77 deletions(-)

diff --git a/grub-core/video/fb/video_fb.c b/grub-core/video/fb/video_fb.c
index fa4ebde26..d17c47b11 100644
--- a/grub-core/video/fb/video_fb.c
+++ b/grub-core/video/fb/video_fb.c
@@ -31,13 +31,6 @@ GRUB_MOD_LICENSE ("GPLv3+");
 
 typedef grub_err_t (*grub_video_fb_doublebuf_update_screen_t) (void);
 typedef volatile void *framebuf_t;
-
-struct dirty
-{
-  int first_line;
-  int last_line;
-};
-
 static struct
 {
   struct grub_video_fbrender_target *render_target;
@@ -47,8 +40,8 @@ static struct
 
   unsigned int palette_size;
 
-  struct dirty current_dirty;
-  struct dirty previous_dirty;
+  struct grub_video_rect current_dirty;
+  struct grub_video_rect previous_dirty;
 
   /* For page flipping strategy.  */
   int displayed_page;           /* The page # that is the front buffer.  */
@@ -831,14 +824,36 @@ grub_video_fb_unmap_color_int (struct grub_video_fbblit_info * source,
 }
 
 static void
-dirty (int y, int height)
+dirty (int x, int y, int width, int height)
 {
+  
+  grub_video_rect_t *current_dirty = &framebuffer.current_dirty;
+  grub_video_rect_t dirty_rect = {
+    .x = x,
+    .y = y,
+    .width = width,
+    .height = height
+  };
+
   if (framebuffer.render_target != framebuffer.back_target)
     return;
-  if (framebuffer.current_dirty.first_line > y)
-    framebuffer.current_dirty.first_line = y;
-  if (framebuffer.current_dirty.last_line < y + height)
-    framebuffer.current_dirty.last_line = y + height;
+
+  /* extend dirty_rect bounds if dirty x min is less than current x */
+  if (dirty_rect.x < current_dirty->x) 
+    current_dirty->x = dirty_rect.x;
+
+  /* extend dirty_rect bounds if dirty x max is greater than current width */
+  if (dirty_rect.x + dirty_rect.width > current_dirty->x + current_dirty->width)
+    current_dirty->width = (dirty_rect.x + dirty_rect.width) - current_dirty->x;
+
+  /* extend dirty_rect bounds if dirty y min is less than current y */
+  if (dirty_rect.y < current_dirty->y)
+    current_dirty->y = dirty_rect.y;
+
+  /* extend dirty_rect bounds if dirty y max is greater than current height */
+  if (dirty_rect.y + dirty_rect.height > current_dirty->y + current_dirty->height)
+    current_dirty->height = (dirty_rect.y + dirty_rect.height) - current_dirty->y;
+
 }
 
 grub_err_t
@@ -896,7 +911,7 @@ grub_video_fb_fill_rect (grub_video_color_t color, int x, int y,
   x += area_x;
   y += area_y;
 
-  dirty (y, height);
+  dirty (x, y, width, height);
 
   /* Use fbblit_info to encapsulate rendering.  */
   target.mode_info = &framebuffer.render_target->mode_info;
@@ -1008,8 +1023,7 @@ grub_video_fb_blit_source (struct grub_video_fbblit_info *source,
   target.mode_info = &framebuffer.render_target->mode_info;
   target.data = framebuffer.render_target->data;
 
-  /* Do actual blitting.  */
-  dirty (y, height);
+  dirty (x, y, width, height);
   grub_video_fb_dispatch_blit (&target, source, oper, x, y, width, height,
                                offset_x, offset_y);
 
@@ -1061,7 +1075,9 @@ grub_video_fb_scroll (grub_video_color_t color, int dx, int dy)
   width = framebuffer.render_target->viewport.width - grub_abs (dx);
   height = framebuffer.render_target->viewport.height - grub_abs (dy);
 
-  dirty (framebuffer.render_target->viewport.y,
+  dirty (framebuffer.render_target->viewport.x,
+	 framebuffer.render_target->viewport.y,
+   framebuffer.render_target->viewport.width,
 	 framebuffer.render_target->viewport.height);
 
   if (dx < 0)
@@ -1416,28 +1432,33 @@ grub_video_fb_get_active_render_target (struct grub_video_fbrender_target **targ
 static grub_err_t
 doublebuf_blit_update_screen (void)
 {
-  if (framebuffer.current_dirty.first_line
-      <= framebuffer.current_dirty.last_line)
-    {
-      grub_size_t copy_size;
-
-      if (grub_sub (framebuffer.current_dirty.last_line,
-		    framebuffer.current_dirty.first_line, &copy_size) ||
-	  grub_mul (framebuffer.back_target->mode_info.pitch, copy_size, &copy_size))
-	{
-	  /* Shouldn't happen, but if it does we've a bug. */
-	  return GRUB_ERR_BUG;
-	}
-
-      grub_memcpy ((char *) framebuffer.pages[0] + framebuffer.current_dirty.first_line *
-		   framebuffer.back_target->mode_info.pitch,
-		   (char *) framebuffer.back_target->data + framebuffer.current_dirty.first_line *
-		   framebuffer.back_target->mode_info.pitch,
-		   copy_size);
+  if (framebuffer.current_dirty.height > 0 || framebuffer.current_dirty.width > 0) {
+    /* dirty row size in bytes */
+    grub_size_t row_size = framebuffer.current_dirty.width 
+                           * framebuffer.back_target->mode_info.bytes_per_pixel;
+
+    /* address of dirty_rect origin on render target */
+    char *src_base = (char *)framebuffer.back_target->data + framebuffer.current_dirty.y
+                      * framebuffer.back_target->mode_info.pitch + framebuffer.current_dirty.x
+                      * framebuffer.back_target->mode_info.bytes_per_pixel;
+
+    /* address of dirty_rect origin on display target */
+    char *dst_base = (char *)framebuffer.pages[0] + framebuffer.current_dirty.y
+                      * framebuffer.back_target->mode_info.pitch + framebuffer.current_dirty.x
+                      * framebuffer.back_target->mode_info.bytes_per_pixel;
+
+    /* blit each row from render_target to display */
+    grub_size_t pitch = framebuffer.back_target->mode_info.pitch;
+    for (unsigned int y = 0; y < framebuffer.current_dirty.height; y++) {
+      grub_memcpy(dst_base + y * pitch, src_base + y * pitch, row_size);
     }
-  framebuffer.current_dirty.first_line
-    = framebuffer.back_target->mode_info.height;
-  framebuffer.current_dirty.last_line = 0;
+  }
+
+  /* reset current_dirty rect */
+  framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+  framebuffer.current_dirty.height = 0;
+  framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+  framebuffer.current_dirty.width = 0;
 
   return GRUB_ERR_NONE;
 }
@@ -1470,8 +1491,10 @@ grub_video_fb_doublebuf_blit_init (struct grub_video_fbrender_target **back,
   framebuffer.pages[0] = framebuf;
   framebuffer.displayed_page = 0;
   framebuffer.render_page = 0;
-  framebuffer.current_dirty.first_line = mode_info.height;
-  framebuffer.current_dirty.last_line = 0;
+  framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+  framebuffer.current_dirty.height = 0;
+  framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+  framebuffer.current_dirty.width = 0;
 
   return GRUB_ERR_NONE;
 }
@@ -1481,37 +1504,52 @@ doublebuf_pageflipping_update_screen (void)
 {
   int new_displayed_page;
   grub_err_t err;
-  int first_line, last_line;
-
-  first_line = framebuffer.current_dirty.first_line;
-  last_line = framebuffer.current_dirty.last_line;
-  if (first_line > framebuffer.previous_dirty.first_line)
-    first_line = framebuffer.previous_dirty.first_line;
-  if (last_line < framebuffer.previous_dirty.last_line)
-    last_line = framebuffer.previous_dirty.last_line;
 
-  if (first_line <= last_line)
-    {
-      grub_size_t copy_size;
-
-      if (grub_sub (last_line, first_line, &copy_size) ||
-	  grub_mul (framebuffer.back_target->mode_info.pitch, copy_size, &copy_size))
-	{
-	  /* Shouldn't happen, but if it does we've a bug. */
-	  return GRUB_ERR_BUG;
-	}
-
-      grub_memcpy ((char *) framebuffer.pages[framebuffer.render_page] + first_line *
-		   framebuffer.back_target->mode_info.pitch,
-		   (char *) framebuffer.back_target->data + first_line *
-		   framebuffer.back_target->mode_info.pitch,
-		   copy_size);
+  /* compare current and previous dirty_rects, and use greatest extents */
+  unsigned int min_x = framebuffer.current_dirty.x;
+  unsigned int min_y = framebuffer.current_dirty.y;
+  unsigned int max_x = framebuffer.current_dirty.x + framebuffer.current_dirty.width;
+  unsigned int max_y = framebuffer.current_dirty.y + framebuffer.current_dirty.height;  
+  if (framebuffer.previous_dirty.x < min_x)
+    min_x = framebuffer.previous_dirty.x;
+  if (framebuffer.previous_dirty.y < min_y)
+    min_y = framebuffer.previous_dirty.y;
+  if (framebuffer.previous_dirty.x + framebuffer.previous_dirty.width > max_x)
+    max_x = framebuffer.previous_dirty.x + framebuffer.previous_dirty.width;
+  if (framebuffer.previous_dirty.y + framebuffer.previous_dirty.height > max_y)
+    max_y = framebuffer.previous_dirty.y + framebuffer.previous_dirty.height;
+  int dirty_width = max_x - min_x;
+  int dirty_height = max_y - min_y;
+
+  /* check if there is anything to do */
+  if (dirty_width > 0 && dirty_height > 0) {
+    /* byte size of dirty row */
+    grub_size_t row_size = dirty_width 
+                          * framebuffer.back_target->mode_info.bytes_per_pixel;
+
+    /* render target base address */
+    char *src_base = (char *)framebuffer.back_target->data + min_y
+                      * framebuffer.back_target->mode_info.pitch + min_x 
+                      * framebuffer.back_target->mode_info.bytes_per_pixel;
+
+    /* display target base address */
+    char *dst_base = (char *)framebuffer.pages[framebuffer.render_page] + min_y 
+                      * framebuffer.back_target->mode_info.pitch + min_x
+                      * framebuffer.back_target->mode_info.bytes_per_pixel;
+
+    /* blit each row from render_target to display */
+    grub_size_t pitch = framebuffer.back_target->mode_info.pitch;
+    for (int y = 0; y < dirty_height; y++) {
+      grub_memcpy(dst_base + y * pitch, src_base + y * pitch, row_size);
     }
+  }
 
+  /* reset current_dirty rect */
   framebuffer.previous_dirty = framebuffer.current_dirty;
-  framebuffer.current_dirty.first_line
-    = framebuffer.back_target->mode_info.height;
-  framebuffer.current_dirty.last_line = 0;
+  framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+  framebuffer.current_dirty.height = 0;
+  framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+  framebuffer.current_dirty.width = 0;
 
   /* Swap the page numbers in the framebuffer struct.  */
   new_displayed_page = framebuffer.render_page;
@@ -1570,12 +1608,17 @@ doublebuf_pageflipping_init (struct grub_video_mode_info *mode_info,
   framebuffer.pages[0] = page0_ptr;
   framebuffer.pages[1] = page1_ptr;
 
-  framebuffer.current_dirty.first_line
-    = framebuffer.back_target->mode_info.height;
-  framebuffer.current_dirty.last_line = 0;
-  framebuffer.previous_dirty.first_line
-    = framebuffer.back_target->mode_info.height;
-  framebuffer.previous_dirty.last_line = 0;
+  /* reset current_dirty rect */
+  framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+  framebuffer.current_dirty.height = 0;
+  framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+  framebuffer.current_dirty.width = 0;
+
+   /* reset previous_dirty rect */
+  framebuffer.previous_dirty.y = framebuffer.back_target->mode_info.height;
+  framebuffer.previous_dirty.height = 0;
+  framebuffer.previous_dirty.x = framebuffer.back_target->mode_info.width;
+  framebuffer.previous_dirty.width = 0;
 
   /* Set the framebuffer memory data pointer and display the right page.  */
   err = set_page_in (framebuffer.displayed_page);
@@ -1661,9 +1704,11 @@ grub_video_fb_setup (unsigned int mode_type, unsigned int mode_mask,
   framebuffer.displayed_page = 0;
   framebuffer.render_page = 0;
   framebuffer.set_page = 0;
-  framebuffer.current_dirty.first_line
-    = framebuffer.back_target->mode_info.height;
-  framebuffer.current_dirty.last_line = 0;
+ /* reset transformed_add_rect */
+  framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+  framebuffer.current_dirty.height = 0;
+  framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+  framebuffer.current_dirty.width = 0;
 
   mode_info->mode_type &= ~GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
 
-- 
2.34.1


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v1 2/3] framebuffer rotation
  2024-06-18  4:14 [PATCH v1 0/3] framebuffer rotation kbader94
  2024-06-18  4:14 ` [PATCH v1 1/3] dirty 2d kbader94
@ 2024-06-18  4:14 ` kbader94
  2024-06-18  4:14 ` [PATCH v1 3/3] fb rotation - Add config option to grub-mkconfig to enable setting GRUB_FB_ROTATION in grub's config file. Setting GRUB_FB_ROTATION to 90, 180, 270, 'left', 'right', or 'inverted' will set the rotation for both grub AND linux. For linux, the changes are passed on to linux kernel entries if GRUB_GFXPAYLOAD_LINUX = 'keep' kbader94
  2 siblings, 0 replies; 4+ messages in thread
From: kbader94 @ 2024-06-18  4:14 UTC (permalink / raw
  To: grub-devel; +Cc: kbader94

   Add optional framebuffer rotation, which allows the user to specify the display output rotation

   MODIFIED:

fbutil.h include/grub - Add function declarations. see below.

video.h include/grub

   struct grub_video_mode_info - Add int original_width, int original_height,
   enum grub_video_rotation rotation.

fbblit.c grub-core/video/fb

   Modify grub_video_fb_dispatch_blit() to rotate blit coordinates.
   TODO: currently only the generic(slow) blitting operation is used when rotation is specified. This should be implementd for every blitting mode and operation.

fbfill.c grub-core/video/fb

   Modify grub_video_fb_fill_dispatch() to rotate fill coordinates.

fbutil.c grub-core/video/fb

   Add functions trans_x and trans_y to translate coordinates depending on mode_info.rotation
   Add function grub_video_transform_rectangle to transform video_rect depending on mode_info

video_fb.c grub-core/video/fb

   Modify functions:

      dirty() to rotate dirty video_rect

      grub_video_fb_scroll() to rotate scroll

      grub_video_fb_create_render_target - use no rotation via mode_info by default. Render
      target's(such as text_layers) get rotated on the final blit to the actual framebuffer,    thus we want a mode_info with NO rotation set to prevent "double rotation's".

      grub_video_fb_create_render_target_from_pointer - Check for rotation grub_env_var and set mode_info rotation, viewport, area, width, and height for render_target depending on the rotation specified.

      Other functions - update to use original_width or original_height where appropriate.


Signed-off-by: kbader94 <kyle.bader94@gmail.com>
---
 grub-core/video/fb/fbblit.c   |  71 ++++++++++++++++++++--
 grub-core/video/fb/fbfill.c   |  28 ++++++---
 grub-core/video/fb/fbutil.c   |  61 +++++++++++++++++++
 grub-core/video/fb/video_fb.c | 107 +++++++++++++++++++++++-----------
 include/grub/fbutil.h         |   9 +++
 include/grub/video.h          |  20 ++++++-
 6 files changed, 247 insertions(+), 49 deletions(-)

diff --git a/grub-core/video/fb/fbblit.c b/grub-core/video/fb/fbblit.c
index 1010ef393..5dda0ffdb 100644
--- a/grub-core/video/fb/fbblit.c
+++ b/grub-core/video/fb/fbblit.c
@@ -62,7 +62,8 @@ grub_video_fbblit_replace (struct grub_video_fbblit_info *dst,
 	  dst_color = grub_video_fb_map_rgba (src_red, src_green,
 					      src_blue, src_alpha);
 
-	  set_pixel (dst, x + i, y + j, dst_color);
+	  set_pixel (dst, x + trans_x(i, j, dst->mode_info), 
+               y + trans_y(i,j, dst->mode_info), dst_color);
 	}
     }
 }
@@ -1195,11 +1196,11 @@ grub_video_fbblit_blend (struct grub_video_fbblit_info *dst,
             {
               dst_color = grub_video_fb_map_rgba (src_red, src_green,
 						  src_blue, src_alpha);
-              set_pixel (dst, x + i, y + j, dst_color);
+              set_pixel (dst, x + trans_x(i, j, dst->mode_info), y + trans_y(i,j, dst->mode_info), dst_color);
               continue;
             }
 
-          dst_color = get_pixel (dst, x + i, y + j);
+          dst_color = get_pixel (dst, x + trans_x(i, j, dst->mode_info), y + trans_y(i,j, dst->mode_info));
 
           grub_video_fb_unmap_color_int (dst, dst_color, &dst_red,
 					 &dst_green, &dst_blue, &dst_alpha);
@@ -1212,7 +1213,7 @@ grub_video_fbblit_blend (struct grub_video_fbblit_info *dst,
           dst_color = grub_video_fb_map_rgba (dst_red, dst_green, dst_blue,
 					      dst_alpha);
 
-          set_pixel (dst, x + i, y + j, dst_color);
+          set_pixel (dst, x + trans_x(i, j, dst->mode_info), y + trans_y(i,j, dst->mode_info), dst_color);
         }
     }
 }
@@ -1936,6 +1937,68 @@ grub_video_fb_dispatch_blit (struct grub_video_fbblit_info *target,
 			     unsigned int width, unsigned int height,
 			     int offset_x, int offset_y)
 {
+  if (target->mode_info->rotation == GRUB_VIDEO_ROTATE_90)
+    {
+      int nx = y;
+      int ny = target->mode_info->width - x - 1;
+      if (oper == GRUB_VIDEO_BLIT_REPLACE)
+	{
+	  /* No optimized replace operator found, use default (slow) blitter.  */
+	  grub_video_fbblit_replace (target, source, nx, ny, width, height,
+					offset_x, offset_y);
+	  return;
+	}
+      else
+	{
+	  /* No optimized replace operator found, use default (slow) blitter.  */
+	  grub_video_fbblit_blend (target, source, nx, ny, width, height,
+				      offset_x, offset_y);
+	  return;
+	}
+    }
+
+  if (target->mode_info->rotation == GRUB_VIDEO_ROTATE_180)
+    {
+      int nx = target->mode_info->width - x - 1;
+      int ny = target->mode_info->height - y - 1;
+      if (oper == GRUB_VIDEO_BLIT_REPLACE)
+	{
+	  /* No optimized replace operator found, use default (slow) blitter.  */
+	  grub_video_fbblit_replace (target, source, nx, ny, width, height,
+					 offset_x, offset_y);
+	  return;
+	}
+      else
+	{
+	  /* No optimized replace operator found, use default (slow) blitter.  */
+	  grub_video_fbblit_blend (target, source, nx, ny, width, height,
+				       offset_x, offset_y);
+	  return;
+	}
+
+      
+    }
+
+  if (target->mode_info->rotation == GRUB_VIDEO_ROTATE_270)
+    {
+      int nx = target->mode_info->height - y - 1;
+      int ny = x;
+      if (oper == GRUB_VIDEO_BLIT_REPLACE)
+	{
+	  /* No optimized replace operator found, use default (slow) blitter.  */
+	  grub_video_fbblit_replace (target, source, nx, ny, width, height,
+					 offset_x, offset_y);
+	  return;
+	}
+      else
+	{
+	  /* No optimized replace operator found, use default (slow) blitter.  */
+	  grub_video_fbblit_blend (target, source, nx, ny, width, height,
+				       offset_x, offset_y);
+	  return;
+	}
+    }
+
   if (oper == GRUB_VIDEO_BLIT_REPLACE)
     {
       /* Try to figure out more optimized version for replace operator.  */
diff --git a/grub-core/video/fb/fbfill.c b/grub-core/video/fb/fbfill.c
index 49fa16b92..cab4d8acc 100644
--- a/grub-core/video/fb/fbfill.c
+++ b/grub-core/video/fb/fbfill.c
@@ -185,28 +185,38 @@ grub_video_fb_fill_dispatch (struct grub_video_fbblit_info *target,
 			     grub_video_color_t color, int x, int y,
 			     unsigned int width, unsigned int height)
 {
+  grub_video_rect_t orig = {
+    .x = x,
+    .y = y,
+    .width = width,
+    .height = height
+  };
+  grub_video_rect_t tran = grub_video_transform_rectangle (orig, target->mode_info);
+  
   /* Try to figure out more optimized version.  Note that color is already
      mapped to target format so we can make assumptions based on that.  */
   switch (target->mode_info->bytes_per_pixel)
     {
     case 4:
-      grub_video_fbfill_direct32 (target, color, x, y,
-				  width, height);
+      grub_video_fbfill_direct32 (target, color, tran.x, tran.y,
+				  tran.width, tran.height);
       return;
     case 3:
-      grub_video_fbfill_direct24 (target, color, x, y,
-				  width, height);
+      grub_video_fbfill_direct24 (target, color, tran.x, tran.y,
+				  tran.width, tran.height);
+      return;
       return;
     case 2:
-      grub_video_fbfill_direct16 (target, color, x, y,
-                                        width, height);
+      grub_video_fbfill_direct16 (target, color, tran.x, tran.y,
+				  tran.width, tran.height);
       return;
     case 1:
-      grub_video_fbfill_direct8 (target, color, x, y,
-				       width, height);
+      grub_video_fbfill_direct8 (target, color, tran.x, tran.y,
+				  tran.width, tran.height);
       return;
     }
 
   /* No optimized version found, use default (slow) filler.  */
-  grub_video_fbfill (target, color, x, y, width, height);
+  grub_video_fbfill  (target, color, tran.x, tran.y,
+				  tran.width, tran.height);
 }
diff --git a/grub-core/video/fb/fbutil.c b/grub-core/video/fb/fbutil.c
index 25ef39f47..368356fd7 100644
--- a/grub-core/video/fb/fbutil.c
+++ b/grub-core/video/fb/fbutil.c
@@ -149,3 +149,64 @@ set_pixel (struct grub_video_fbblit_info *source,
       break;
     }
 }
+
+int 
+trans_x(int x,int y, struct grub_video_mode_info *mode_info)
+{
+    switch (mode_info->rotation) {
+        case GRUB_VIDEO_ROTATE_90:
+            return y;
+        case GRUB_VIDEO_ROTATE_180:
+            return -x;
+        case GRUB_VIDEO_ROTATE_270:
+            return -y;
+        case GRUB_VIDEO_ROTATE_NONE:
+        default:
+            return x;
+    }
+}
+
+int 
+trans_y(int x, int y, struct grub_video_mode_info *mode_info)
+{
+    switch (mode_info->rotation) {
+        case GRUB_VIDEO_ROTATE_90:
+            return -x;
+        case GRUB_VIDEO_ROTATE_180:
+            return -y;
+        case GRUB_VIDEO_ROTATE_270:
+            return x;
+        case GRUB_VIDEO_ROTATE_NONE:
+        default:
+            return y;
+    }
+}
+
+grub_video_rect_t grub_video_transform_rectangle (grub_video_rect_t r, const struct grub_video_mode_info *mode_info)
+{
+  grub_video_rect_t n;
+  switch (mode_info->rotation)
+    {
+    case GRUB_VIDEO_ROTATE_NONE:
+      return r;
+    case GRUB_VIDEO_ROTATE_90:
+      n.width = r.height;
+      n.height = r.width;
+      n.x = r.y;
+      n.y = mode_info->width - r.x - r.width;
+      return n;
+    case GRUB_VIDEO_ROTATE_180:
+      n.width = r.width;
+      n.height = r.height;
+      n.x = mode_info->width - r.x - r.width;
+      n.y = mode_info->height - r.y - r.height;
+      return n;
+    case GRUB_VIDEO_ROTATE_270:
+      n.width = r.height;
+      n.height = r.width;
+      n.x = mode_info->height - r.y - r.height;
+      n.y = r.x;
+      return n;
+    }
+  return r;
+}
\ No newline at end of file
diff --git a/grub-core/video/fb/video_fb.c b/grub-core/video/fb/video_fb.c
index d17c47b11..377a9179d 100644
--- a/grub-core/video/fb/video_fb.c
+++ b/grub-core/video/fb/video_fb.c
@@ -26,6 +26,7 @@
 #include <grub/bitmap.h>
 #include <grub/dl.h>
 #include <grub/safemath.h>
+#include <grub/env.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -826,15 +827,17 @@ grub_video_fb_unmap_color_int (struct grub_video_fbblit_info * source,
 static void
 dirty (int x, int y, int width, int height)
 {
-  
+
   grub_video_rect_t *current_dirty = &framebuffer.current_dirty;
-  grub_video_rect_t dirty_rect = {
+  grub_video_rect_t additive_rect = {
     .x = x,
     .y = y,
     .width = width,
     .height = height
   };
 
+  grub_video_rect_t dirty_rect = grub_video_transform_rectangle (additive_rect, &framebuffer.render_target->mode_info);
+
   if (framebuffer.render_target != framebuffer.back_target)
     return;
 
@@ -1063,6 +1066,8 @@ grub_video_fb_scroll (grub_video_color_t color, int dx, int dy)
 {
   int width;
   int height;
+  int tx; /* transformed scroll coords */
+  int ty; /* transformed scroll coords */
   int src_x;
   int src_y;
   int dst_x;
@@ -1072,39 +1077,41 @@ grub_video_fb_scroll (grub_video_color_t color, int dx, int dy)
   if ((dx == 0) && (dy == 0))
     return GRUB_ERR_NONE;
 
-  width = framebuffer.render_target->viewport.width - grub_abs (dx);
-  height = framebuffer.render_target->viewport.height - grub_abs (dy);
+  tx = trans_x(dx,dy, &framebuffer.render_target->mode_info);
+  ty = trans_y(dx,dy, &framebuffer.render_target->mode_info);
+  width = framebuffer.render_target->mode_info.original_width - grub_abs (tx);
+  height = framebuffer.render_target->mode_info.original_height - grub_abs (ty);
 
   dirty (framebuffer.render_target->viewport.x,
 	 framebuffer.render_target->viewport.y,
-   framebuffer.render_target->viewport.width,
+	 framebuffer.render_target->viewport.width,
 	 framebuffer.render_target->viewport.height);
 
-  if (dx < 0)
+  if (tx < 0)
     {
-      src_x = framebuffer.render_target->viewport.x - dx;
+      src_x = framebuffer.render_target->viewport.x - tx;
       dst_x = framebuffer.render_target->viewport.x;
     }
   else
     {
       src_x = framebuffer.render_target->viewport.x;
-      dst_x = framebuffer.render_target->viewport.x + dx;
+      dst_x = framebuffer.render_target->viewport.x + tx;
     }
 
-  if (dy < 0)
+  if (ty < 0)
     {
-      src_y = framebuffer.render_target->viewport.y - dy;
+      src_y = framebuffer.render_target->viewport.y - ty;
       dst_y = framebuffer.render_target->viewport.y;
     }
   else
     {
       src_y = framebuffer.render_target->viewport.y;
-      dst_y = framebuffer.render_target->viewport.y + dy;
+      dst_y = framebuffer.render_target->viewport.y + ty;
     }
 
   /* 2. Check if there is need to copy data.  */
-  if ((grub_abs (dx) < framebuffer.render_target->viewport.width)
-       && (grub_abs (dy) < framebuffer.render_target->viewport.height))
+  if ((grub_abs (tx) < framebuffer.render_target->viewport.width)
+       && (grub_abs (ty) < framebuffer.render_target->viewport.height))
     {
       /* 3. Move data in render target.  */
       struct grub_video_fbblit_info target;
@@ -1119,7 +1126,7 @@ grub_video_fb_scroll (grub_video_color_t color, int dx, int dy)
       linelen = width * target.mode_info->bytes_per_pixel;
 #define DO_SCROLL                                                    \
       /* Check vertical direction of the move.  */                   \
-      if (dy < 0 || (dy == 0 && dx < 0))                             \
+      if (ty < 0 || (ty == 0 && tx < 0))                             \
 	{                                                            \
 	  dst = (void *) grub_video_fb_get_video_ptr (&target,       \
 						      dst_x, dst_y); \
@@ -1245,6 +1252,9 @@ grub_video_fb_create_render_target (struct grub_video_fbrender_target **result,
   /* TODO: Implement other types too.
      Currently only 32bit render targets are supported.  */
 
+/* only used by text_layers, so do not rotate */
+  target->mode_info.rotation = GRUB_VIDEO_ROTATE_NONE;
+
   /* Mark render target as allocated.  */
   target->is_allocated = 1;
 
@@ -1270,6 +1280,8 @@ grub_video_fb_create_render_target (struct grub_video_fbrender_target **result,
   /* Setup render target format.  */
   target->mode_info.width = width;
   target->mode_info.height = height;
+  target->mode_info.original_width = width;
+  target->mode_info.original_height = height;
   switch (mode_type)
     {
     case GRUB_VIDEO_MODE_TYPE_INDEX_COLOR
@@ -1332,6 +1344,7 @@ grub_video_fb_create_render_target_from_pointer (struct grub_video_fbrender_targ
 {
   struct grub_video_fbrender_target *target;
   unsigned y;
+  const char *rot_env;
 
 #ifndef GRUB_HAVE_UNALIGNED_ACCESS
   if (!(mode_info->bytes_per_pixel & (mode_info->bytes_per_pixel - 1))
@@ -1352,30 +1365,53 @@ grub_video_fb_create_render_target_from_pointer (struct grub_video_fbrender_targ
   target->data = ptr;
 
   grub_memcpy (&(target->mode_info), mode_info, sizeof (target->mode_info));
+  rot_env = grub_env_get("rotation");
+
+  if (!rot_env) {
+        target->mode_info.rotation = GRUB_VIDEO_ROTATE_NONE;
+    } else if (grub_strcmp(rot_env, "90") == 0) {
+        target->mode_info.rotation = GRUB_VIDEO_ROTATE_90;
+    } else if (grub_strcmp(rot_env, "180") == 0) {
+        target->mode_info.rotation = GRUB_VIDEO_ROTATE_180;
+    } else if (grub_strcmp(rot_env, "270") == 0) {
+        target->mode_info.rotation = GRUB_VIDEO_ROTATE_270;
+    } else {
+        target->mode_info.rotation = GRUB_VIDEO_ROTATE_NONE;
+    }
+
+  target->mode_info.original_width = mode_info->width;
+  target->mode_info.original_height = mode_info->height;
+
+  if (target->mode_info.rotation == GRUB_VIDEO_ROTATE_90
+      || target->mode_info.rotation == GRUB_VIDEO_ROTATE_270)
+    {
+      target->mode_info.width = target->mode_info.original_height;
+      target->mode_info.height = target->mode_info.original_width;
+    }
 
   /* Reset viewport, region and area to match new mode.  */
   target->viewport.x = 0;
   target->viewport.y = 0;
-  target->viewport.width = mode_info->width;
-  target->viewport.height = mode_info->height;
+  target->viewport.width = target->mode_info.width;
+  target->viewport.height = target->mode_info.height;
 
   target->region.x = 0;
   target->region.y = 0;
-  target->region.width = mode_info->width;
-  target->region.height = mode_info->height;
+  target->region.width = target->mode_info.width;
+  target->region.height = target->mode_info.height;
 
   target->area_enabled = 0;
   target->area.x = 0;
   target->area.y = 0;
-  target->area.width = mode_info->width;
-  target->area.height = mode_info->height;
+  target->area.width = target->mode_info.width;
+  target->area.height = target->mode_info.height;
   target->area_offset_x = 0;
   target->area_offset_y = 0;
 
   /* Clear render target with black and maximum transparency.  */
-  for (y = 0; y < mode_info->height; y++)
+  for (y = 0; y < target->mode_info.original_height; y++)
     grub_memset (target->data + mode_info->pitch * y, 0,
-		 mode_info->bytes_per_pixel * mode_info->width);
+		 mode_info->bytes_per_pixel * target->mode_info.original_width);
 
   /* Save result to caller.  */
   *result = target;
@@ -1455,9 +1491,9 @@ doublebuf_blit_update_screen (void)
   }
 
   /* reset current_dirty rect */
-  framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+  framebuffer.current_dirty.y = framebuffer.back_target->mode_info.original_height;
   framebuffer.current_dirty.height = 0;
-  framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+  framebuffer.current_dirty.x = framebuffer.back_target->mode_info.original_width;
   framebuffer.current_dirty.width = 0;
 
   return GRUB_ERR_NONE;
@@ -1491,9 +1527,9 @@ grub_video_fb_doublebuf_blit_init (struct grub_video_fbrender_target **back,
   framebuffer.pages[0] = framebuf;
   framebuffer.displayed_page = 0;
   framebuffer.render_page = 0;
-  framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+  framebuffer.current_dirty.y = framebuffer.back_target->mode_info.original_height;
   framebuffer.current_dirty.height = 0;
-  framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+  framebuffer.current_dirty.x = framebuffer.back_target->mode_info.original_width;
   framebuffer.current_dirty.width = 0;
 
   return GRUB_ERR_NONE;
@@ -1546,9 +1582,9 @@ doublebuf_pageflipping_update_screen (void)
 
   /* reset current_dirty rect */
   framebuffer.previous_dirty = framebuffer.current_dirty;
-  framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+  framebuffer.current_dirty.y = framebuffer.back_target->mode_info.original_height;
   framebuffer.current_dirty.height = 0;
-  framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+  framebuffer.current_dirty.x = framebuffer.back_target->mode_info.original_width;
   framebuffer.current_dirty.width = 0;
 
   /* Swap the page numbers in the framebuffer struct.  */
@@ -1609,15 +1645,15 @@ doublebuf_pageflipping_init (struct grub_video_mode_info *mode_info,
   framebuffer.pages[1] = page1_ptr;
 
   /* reset current_dirty rect */
-  framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+  framebuffer.current_dirty.y = framebuffer.back_target->mode_info.original_height;
   framebuffer.current_dirty.height = 0;
-  framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+  framebuffer.current_dirty.x = framebuffer.back_target->mode_info.original_width;
   framebuffer.current_dirty.width = 0;
 
    /* reset previous_dirty rect */
-  framebuffer.previous_dirty.y = framebuffer.back_target->mode_info.height;
+  framebuffer.previous_dirty.y = framebuffer.back_target->mode_info.original_height;
   framebuffer.previous_dirty.height = 0;
-  framebuffer.previous_dirty.x = framebuffer.back_target->mode_info.width;
+  framebuffer.previous_dirty.x = framebuffer.back_target->mode_info.original_width;
   framebuffer.previous_dirty.width = 0;
 
   /* Set the framebuffer memory data pointer and display the right page.  */
@@ -1705,9 +1741,9 @@ grub_video_fb_setup (unsigned int mode_type, unsigned int mode_mask,
   framebuffer.render_page = 0;
   framebuffer.set_page = 0;
  /* reset transformed_add_rect */
-  framebuffer.current_dirty.y = framebuffer.back_target->mode_info.height;
+  framebuffer.current_dirty.y = framebuffer.back_target->mode_info.original_height;
   framebuffer.current_dirty.height = 0;
-  framebuffer.current_dirty.x = framebuffer.back_target->mode_info.width;
+  framebuffer.current_dirty.x = framebuffer.back_target->mode_info.original_width;
   framebuffer.current_dirty.width = 0;
 
   mode_info->mode_type &= ~GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
@@ -1739,6 +1775,9 @@ grub_video_fb_get_info_and_fini (struct grub_video_mode_info *mode_info,
   grub_memcpy (mode_info, &(framebuffer.back_target->mode_info),
 	       sizeof (*mode_info));
 
+  mode_info->width = framebuffer.back_target->mode_info.original_width;
+  mode_info->height = framebuffer.back_target->mode_info.original_height;
+
   /* We are about to load a kernel.  Switch back to page zero, since some
      kernel drivers expect that.  */
   if (framebuffer.set_page && framebuffer.displayed_page != 0)
diff --git a/include/grub/fbutil.h b/include/grub/fbutil.h
index 78a1ab3b4..ad625bff9 100644
--- a/include/grub/fbutil.h
+++ b/include/grub/fbutil.h
@@ -61,4 +61,13 @@ grub_video_color_t get_pixel (struct grub_video_fbblit_info *source,
 void set_pixel (struct grub_video_fbblit_info *source,
                 unsigned int x, unsigned int y, grub_video_color_t color);
 
+int 
+trans_x(int x,int y, struct grub_video_mode_info *mode_info);
+
+int 
+trans_y(int x, int y, struct grub_video_mode_info *mode_info);
+
+grub_video_rect_t grub_video_transform_rectangle (grub_video_rect_t r, 
+                                                  const struct grub_video_mode_info *mode_info);
+
 #endif /* ! GRUB_VBEUTIL_MACHINE_HEADER */
diff --git a/include/grub/video.h b/include/grub/video.h
index 9dac0f379..f05e70b26 100644
--- a/include/grub/video.h
+++ b/include/grub/video.h
@@ -75,6 +75,14 @@ typedef enum grub_video_mode_type
     GRUB_VIDEO_MODE_TYPE_INFO_MASK        = 0x00FF0000,
   } grub_video_mode_type_t;
 
+enum grub_video_rotation
+  {
+    GRUB_VIDEO_ROTATE_NONE,
+    GRUB_VIDEO_ROTATE_90,
+    GRUB_VIDEO_ROTATE_180,
+    GRUB_VIDEO_ROTATE_270
+  };
+
 /* The basic render target representing the whole display.  This always
    renders to the back buffer when double-buffering is in use.  */
 #define GRUB_VIDEO_RENDER_TARGET_DISPLAY \
@@ -122,12 +130,20 @@ enum grub_video_blit_operators
 
 struct grub_video_mode_info
 {
-  /* Width of the screen.  */
+  /* Width of the screen, before the rotation.  */
+  unsigned int original_width;
+
+  /* Height of the screen, before the rotation.  */
+  unsigned int original_height;
+
+  /* Width of the screen, after the rotation.  */
   unsigned int width;
 
-  /* Height of the screen.  */
+  /* Height of the screen, after the rotation.  */
   unsigned int height;
 
+  enum grub_video_rotation rotation;
+
   /* Mode type bitmask.  Contains information like is it Index color or
      RGB mode.  */
   grub_video_mode_type_t mode_type;
-- 
2.34.1


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v1 3/3] fb rotation - Add config option to grub-mkconfig to enable setting GRUB_FB_ROTATION in grub's config file. Setting GRUB_FB_ROTATION to 90, 180, 270, 'left', 'right', or 'inverted' will set the rotation for both grub AND linux. For linux, the changes are passed on to linux kernel entries if GRUB_GFXPAYLOAD_LINUX = 'keep'.
  2024-06-18  4:14 [PATCH v1 0/3] framebuffer rotation kbader94
  2024-06-18  4:14 ` [PATCH v1 1/3] dirty 2d kbader94
  2024-06-18  4:14 ` [PATCH v1 2/3] framebuffer rotation kbader94
@ 2024-06-18  4:14 ` kbader94
  2 siblings, 0 replies; 4+ messages in thread
From: kbader94 @ 2024-06-18  4:14 UTC (permalink / raw
  To: grub-devel; +Cc: kbader94

Changes to be committed:
	modified:   util/grub-mkconfig.in
	modified:   util/grub.d/00_header.in
	modified:   util/grub.d/10_linux.in

Signed-off-by: kbader94 <kyle.bader94@gmail.com>
---
 util/grub-mkconfig.in    |  1 +
 util/grub.d/00_header.in | 16 ++++++++++++++++
 util/grub.d/10_linux.in  | 32 ++++++++++++++++++++++++++++++++
 3 files changed, 49 insertions(+)

diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
index 32c480dae..b915fcf00 100644
--- a/util/grub-mkconfig.in
+++ b/util/grub-mkconfig.in
@@ -247,6 +247,7 @@ export GRUB_DEFAULT \
   GRUB_DISABLE_RECOVERY \
   GRUB_VIDEO_BACKEND \
   GRUB_GFXMODE \
+  GRUB_FB_ROTATION \
   GRUB_BACKGROUND \
   GRUB_THEME \
   GRUB_GFXPAYLOAD_LINUX \
diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
index f86b69bad..990fce9ed 100644
--- a/util/grub.d/00_header.in
+++ b/util/grub.d/00_header.in
@@ -47,6 +47,22 @@ if [ -s \$prefix/grubenv ]; then
   load_env
 fi
 EOF
+
+# Set fb rotation for grub
+if [ "x$GRUB_FB_ROTATION" != x ]; then
+    case "${GRUB_FB_ROTATION}" in
+        inverted | 180)
+    echo set rotation=180
+            ;;
+        left | 90)
+    echo set rotation=90
+            ;;
+        right | 270)
+    echo set rotation=270
+            ;;
+    esac
+fi
+
 if [ "x$GRUB_BUTTON_CMOS_ADDRESS" != "x" ]; then
     cat <<EOF
 if cmostest $GRUB_BUTTON_CMOS_ADDRESS ; then
diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
index cc393be7e..671373837 100644
--- a/util/grub.d/10_linux.in
+++ b/util/grub.d/10_linux.in
@@ -120,10 +120,42 @@ linux_entry ()
 	  && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" "${config}" 2> /dev/null; then
 	  echo "	set gfxpayload=keep" | sed "s/^/$submenu_indentation/"
       fi
+
+    # Set fb rotation by default
+    case "${GRUB_FB_ROTATION}" in
+    inverted | 180)
+      args="$args fbcon=rotate:2"
+      ;;
+    left | 90)
+      args="$args fbcon=rotate:3"
+      ;;
+    right | 270)
+      args="$args fbcon=rotate:1"
+      ;;
+    esac
+
   else
       if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then
 	  echo "	load_video" | sed "s/^/$submenu_indentation/"
       fi
+
+    if [ "x$GRUB_GFXPAYLOAD_LINUX" = "xkeep" ]; then
+
+      # Set fb rotation if gfxpayload == keep
+      case "${GRUB_FB_ROTATION}" in
+      inverted | 180)
+        args="$args fbcon=rotate:2"
+        ;;
+      left | 90)
+        args="$args fbcon=rotate:3"
+        ;;
+      right | 270)
+        args="$args fbcon=rotate:1"
+        ;;
+      esac
+
+    fi
+
       echo "	set gfxpayload=$GRUB_GFXPAYLOAD_LINUX" | sed "s/^/$submenu_indentation/"
   fi
 
-- 
2.34.1


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2024-06-18  4:15 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-06-18  4:14 [PATCH v1 0/3] framebuffer rotation kbader94
2024-06-18  4:14 ` [PATCH v1 1/3] dirty 2d kbader94
2024-06-18  4:14 ` [PATCH v1 2/3] framebuffer rotation kbader94
2024-06-18  4:14 ` [PATCH v1 3/3] fb rotation - Add config option to grub-mkconfig to enable setting GRUB_FB_ROTATION in grub's config file. Setting GRUB_FB_ROTATION to 90, 180, 270, 'left', 'right', or 'inverted' will set the rotation for both grub AND linux. For linux, the changes are passed on to linux kernel entries if GRUB_GFXPAYLOAD_LINUX = 'keep' kbader94

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).