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.bade...@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

Reply via email to