diff --git a/ChangeLog.scrollopt b/ChangeLog.scrollopt new file mode 100644 index 000000000..c677a2372 --- /dev/null +++ b/ChangeLog.scrollopt @@ -0,0 +1,4 @@ +2009-11-30 Vladimir Serbinenko + + * video/fb/video_fb.c (grub_video_fb_scroll): Optimise by avoiding + unnecessary calls. diff --git a/video/fb/video_fb.c b/video/fb/video_fb.c index 5f2917da6..15c30c23b 100644 --- a/video/fb/video_fb.c +++ b/video/fb/video_fb.c @@ -974,32 +974,83 @@ grub_video_fb_scroll (grub_video_color_t color, int dx, int dy) { /* 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