diff --git a/ChangeLog b/ChangeLog index 6ee1052b1..35ad54e0c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2012-06-19 Vladimir Serbinenko + + 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 * grub-core/net/drivers/ieee1275/ofnet.c (search_net_devices): Decrease diff --git a/grub-core/video/fb/video_fb.c b/grub-core/video/fb/video_fb.c index 9d79f77b5..cfe441f42 100644 --- a/grub-core/video/fb/video_fb.c +++ b/grub-core/video/fb/video_fb.c @@ -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; + int first_line, last_line; - grub_memcpy ((void *) framebuffer.pages[framebuffer.render_page], - framebuffer.back_target->data, - framebuffer.back_target->mode_info.pitch - * framebuffer.back_target->mode_info.height); + 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;