]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Avoid unnecessary memcpy of whole video buffer.
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 19 Jun 2012 17:34:51 +0000 (19:34 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 19 Jun 2012 17:34:51 +0000 (19:34 +0200)
* grub-core/video/fb/video_fb.c (dirty): New struct.
(framebuffer): Add members current_dirty and previous_dirty.
(dirty): New function.
(grub_video_fb_fill_rect): Update dirty.
(common_blitter): Likewise.
(grub_video_fb_scroll): Likewise.
(doublebuf_blit_update_screen): Copy only dirty part.
(doublebuf_pageflipping_update_screen): Likewise.
(grub_video_fb_doublebuf_blit_init): Init dirty.
(doublebuf_pageflipping_init): Likewise.
(grub_video_fb_setup): Likewise.

ChangeLog
grub-core/video/fb/video_fb.c

index 6ee1052b152d9f8ab857ae8a93550ddc9481db43..35ad54e0c61df849cc4ea502e88bf94257f70099 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2012-06-19  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Avoid unnecessary memcpy of whole video buffer.
+
+       * grub-core/video/fb/video_fb.c (dirty): New struct.
+       (framebuffer): Add members current_dirty and previous_dirty.
+       (dirty): New function.
+       (grub_video_fb_fill_rect): Update dirty.
+       (common_blitter): Likewise.
+       (grub_video_fb_scroll): Likewise.
+       (doublebuf_blit_update_screen): Copy only dirty part.
+       (doublebuf_pageflipping_update_screen): Likewise.
+       (grub_video_fb_doublebuf_blit_init): Init dirty.
+       (doublebuf_pageflipping_init): Likewise.
+       (grub_video_fb_setup): Likewise.
+
 2012-06-19  Vladimir Serbinenko  <phcoder@gmail.com>
 
        * grub-core/net/drivers/ieee1275/ofnet.c (search_net_devices): Decrease
index 9d79f77b5c36a86276fe9054385ff4053121bf59..cfe441f427824769fa57ed56579f29bfb15e5c61 100644 (file)
@@ -31,13 +31,24 @@ 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;
   struct grub_video_fbrender_target *back_target;
   struct grub_video_palette_data *palette;
   framebuf_t pages[2];
+
   unsigned int palette_size;
+
+  struct dirty current_dirty;
+  struct dirty previous_dirty;
+
   /* For page flipping strategy.  */
   int displayed_page;           /* The page # that is the front buffer.  */
   int render_page;              /* The page # that is the back buffer.  */
@@ -424,6 +435,17 @@ grub_video_fb_unmap_color_int (struct grub_video_fbblit_info * source,
     }
 }
 
+static void
+dirty (int y, int 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;
+}
+
 grub_err_t
 grub_video_fb_fill_rect (grub_video_color_t color, int x, int y,
                         unsigned int width, unsigned int height)
@@ -457,6 +479,8 @@ grub_video_fb_fill_rect (grub_video_color_t color, int x, int y,
   x += framebuffer.render_target->viewport.x;
   y += framebuffer.render_target->viewport.y;
 
+  dirty (y, height);
+
   /* Use fbblit_info to encapsulate rendering.  */
   target.mode_info = &framebuffer.render_target->mode_info;
   target.data = framebuffer.render_target->data;
@@ -515,6 +539,8 @@ common_blitter (struct grub_video_fbblit_info *target,
                 unsigned int width, unsigned int height,
                 int offset_x, int offset_y)
 {
+  dirty (y, height);
+
   if (oper == GRUB_VIDEO_BLIT_REPLACE)
     {
       /* Try to figure out more optimized version for replace operator.  */
@@ -977,6 +1003,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,
+        framebuffer.render_target->viewport.height);
+
   if (dx < 0)
     {
       src_x = framebuffer.render_target->viewport.x - dx;
@@ -1286,9 +1315,21 @@ grub_video_fb_get_active_render_target (struct grub_video_fbrender_target **targ
 static grub_err_t
 doublebuf_blit_update_screen (void)
 {
-  grub_memcpy ((void *) framebuffer.pages[0], framebuffer.back_target->data,
-              framebuffer.back_target->mode_info.pitch
-              * framebuffer.back_target->mode_info.height);
+  if (framebuffer.current_dirty.first_line
+      <= framebuffer.current_dirty.last_line)
+    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,
+                framebuffer.back_target->mode_info.pitch
+                * (framebuffer.current_dirty.last_line
+                   - framebuffer.current_dirty.first_line));
+  framebuffer.current_dirty.first_line
+    = framebuffer.back_target->mode_info.height;
+  framebuffer.current_dirty.last_line = 0;
+
   return GRUB_ERR_NONE;
 }
 
@@ -1300,7 +1341,7 @@ grub_video_fb_doublebuf_blit_init (struct grub_video_fbrender_target **back,
   grub_err_t err;
   grub_size_t page_size = mode_info.pitch * mode_info.height;
 
-  framebuffer.offscreen_buffer = grub_malloc (page_size);
+  framebuffer.offscreen_buffer = grub_zalloc (page_size);
   if (! framebuffer.offscreen_buffer)
     return grub_errno;
 
@@ -1320,6 +1361,8 @@ 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;
 
   return GRUB_ERR_NONE;
 }
@@ -1329,11 +1372,26 @@ doublebuf_pageflipping_update_screen (void)
 {
   int new_displayed_page;
   grub_err_t err;
-
-  grub_memcpy ((void *) framebuffer.pages[framebuffer.render_page],
-              framebuffer.back_target->data,
-              framebuffer.back_target->mode_info.pitch
-              * framebuffer.back_target->mode_info.height);
+  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_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,
+                framebuffer.back_target->mode_info.pitch
+                * (last_line - first_line));
+  framebuffer.previous_dirty = framebuffer.current_dirty;
+  framebuffer.current_dirty.first_line
+    = framebuffer.back_target->mode_info.height;
+  framebuffer.current_dirty.last_line = 0;
 
   /* Swap the page numbers in the framebuffer struct.  */
   new_displayed_page = framebuffer.render_page;
@@ -1386,6 +1444,13 @@ 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;
+
   /* Set the framebuffer memory data pointer and display the right page.  */
   err = set_page_in (framebuffer.displayed_page);
   if (err)
@@ -1470,6 +1535,9 @@ 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;
 
   mode_info->mode_type &= ~GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;