Available in experimental. In QEMU benchmark scrolling 1000 lines
decreased from 72s to 32s.

-- 
Regards
Vladimir 'φ-coder/phcoder' Serbinenko

=== added file 'ChangeLog.scrollopt'
--- ChangeLog.scrollopt	1970-01-01 00:00:00 +0000
+++ ChangeLog.scrollopt	2009-11-30 09:26:26 +0000
@@ -0,0 +1,4 @@
+2009-11-30  Vladimir Serbinenko  <phco...@gmail.com>
+
+	* video/fb/video_fb.c (grub_video_fb_scroll): Optimise by avoiding
+	unnecessary calls.

=== modified file 'video/fb/video_fb.c'
--- video/fb/video_fb.c	2009-08-28 13:54:20 +0000
+++ video/fb/video_fb.c	2009-11-30 09:52:10 +0000
@@ -974,32 +974,83 @@
     {
       /* 3. Move data in render target.  */
       struct grub_video_fbblit_info target;
-      grub_uint8_t *src;
-      grub_uint8_t *dst;
-      int j;
+      int i, j;
+      int linedelta, linelen;
 
       target.mode_info = &render_target->mode_info;
       target.data = render_target->data;
 
-      /* Check vertical direction of the move.  */
-      if (dy <= 0)
-	/* 3a. Move data upwards.  */
-	for (j = 0; j < height; j++)
-	  {
-	    dst = grub_video_fb_get_video_ptr (&target, dst_x, dst_y + j);
-	    src = grub_video_fb_get_video_ptr (&target, src_x, src_y + j);
-	    grub_memmove (dst, src,
-			  width * target.mode_info->bytes_per_pixel);
-	  }
+      linedelta = target.mode_info->pitch
+	- width * target.mode_info->bytes_per_pixel;
+      linelen = width * target.mode_info->bytes_per_pixel;
+#define DO_SCROLL                                                    \
+      /* Check vertical direction of the move.  */                   \
+      if (dy < 0 || (dy == 0 && dx < 0))                             \
+	{                                                            \
+	  dst = (void *) grub_video_fb_get_video_ptr (&target,       \
+						      dst_x, dst_y); \
+	  src = (void *) grub_video_fb_get_video_ptr (&target,	     \
+						      src_x, src_y); \
+	  /* 3a. Move data upwards.  */                              \
+	  for (j = 0; j < height; j++)                               \
+	    {                                                        \
+	      for (i = 0; i < linelen; i++)                          \
+		*(dst++) = *(src++);	                             \
+	      dst += linedelta;                                      \
+	      src += linedelta;                                      \
+	    }							     \
+	}                                                            \
+      else                                                           \
+	{                                                            \
+	  /* 3b. Move data downwards.  */                            \
+	  dst = (void *) grub_video_fb_get_video_ptr (&target,	     \
+					     dst_x + width - 1,      \
+					     dst_y + height - 1);    \
+	  src = (void *) grub_video_fb_get_video_ptr (&target,	     \
+					     src_x + width - 1,      \
+					     src_y + height - 1);    \
+	  for (j = 0; j < height; j++)                               \
+	    {                                                        \
+	      for (i = 0; i < linelen; i++)                          \
+		*(dst--) = *(src--);                                 \
+	      dst -= linedelta;                                      \
+	      src -= linedelta;                                      \
+	    }                                                        \
+	}
+
+      /* If everything is aligned on 32-bit use 32-bit copy.  */
+      if ((grub_addr_t) grub_video_fb_get_video_ptr (&target, src_x, src_y)
+	  % sizeof (grub_uint32_t) == 0
+	  && (grub_addr_t) grub_video_fb_get_video_ptr (&target, dst_x, dst_y) 
+	  % sizeof (grub_uint32_t) == 0
+	  && linelen % sizeof (grub_uint32_t) == 0
+	  && linedelta % sizeof (grub_uint32_t) == 0)
+	{
+	  grub_uint32_t *src, *dst;
+	  linelen /= sizeof (grub_uint32_t);
+	  linedelta /= sizeof (grub_uint32_t);
+	  DO_SCROLL
+	}
+      /* If everything is aligned on 16-bit use 16-bit copy.  */
+      else if ((grub_addr_t) grub_video_fb_get_video_ptr (&target, src_x, src_y)
+	       % sizeof (grub_uint16_t) == 0
+	       && (grub_addr_t) grub_video_fb_get_video_ptr (&target,
+							     dst_x, dst_y) 
+	       % sizeof (grub_uint16_t) == 0
+	       && linelen % sizeof (grub_uint16_t) == 0
+	       && linedelta % sizeof (grub_uint16_t) == 0)
+	{
+	  grub_uint16_t *src, *dst;
+	  linelen /= sizeof (grub_uint16_t);
+	  linedelta /= sizeof (grub_uint16_t);
+	  DO_SCROLL
+	}
+      /* If not aligned at all use 8-bit copy.  */
       else
-	/* 3b. Move data downwards.  */
-	for (j = (height - 1); j >= 0; j--)
-	  {
-	    dst = grub_video_fb_get_video_ptr (&target, dst_x, dst_y + j);
-	    src = grub_video_fb_get_video_ptr (&target, src_x, src_y + j);
-	    grub_memmove (dst, src,
-			  width * target.mode_info->bytes_per_pixel);
-	  }
+	{
+	  grub_uint8_t *src, *dst;
+	  DO_SCROLL
+	}	
     }
 
   /* 4. Fill empty space with specified color.  In this implementation

Attachment: signature.asc
Description: OpenPGP digital signature

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

Reply via email to