]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Avoid slow read-back from VRAM.
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 15 Jun 2012 21:57:20 +0000 (23:57 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 15 Jun 2012 21:57:20 +0000 (23:57 +0200)
* include/grub/video_fb.h (grub_video_fb_doublebuf_update_screen_t):
Move from here ...
* grub-core/video/fb/video_fb.c
(grub_video_fb_doublebuf_update_screen_t): ... here. Remove arguments.
* grub-core/video/fb/video_fb.c (framebuf_t): New type.
(front_target): Remove front_target. Add pages.
(grub_video_fb_init): Skip setting front_pages.
(grub_video_fb_fini): Likewise.
(doublebuf_blit_update_screen): Use pages.
(grub_video_fb_doublebuf_blit_init): Likewise.
(doublebuf_pageflipping_init): Allocate offscreen buffer.
(doublebuf_pageflipping_update_screen): Use offscreen buffer.
(grub_video_fb_setup): Prefer doublebuffing.

ChangeLog
grub-core/video/fb/video_fb.c
grub-core/video/ieee1275.c
include/grub/video_fb.h

index 96696791a2598d46c64a44fde7d55d132d03cc79..9167a3754f016d6ac4a94812b42c891f710c791c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2012-06-15  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Avoid slow read-back from VRAM.
+
+       * include/grub/video_fb.h (grub_video_fb_doublebuf_update_screen_t):
+       Move from here ...
+       * grub-core/video/fb/video_fb.c
+       (grub_video_fb_doublebuf_update_screen_t): ... here. Remove arguments.
+       * grub-core/video/fb/video_fb.c (framebuf_t): New type.
+       (front_target): Remove front_target. Add pages.
+       (grub_video_fb_init): Skip setting front_pages.
+       (grub_video_fb_fini): Likewise.
+       (doublebuf_blit_update_screen): Use pages.
+       (grub_video_fb_doublebuf_blit_init): Likewise.
+       (doublebuf_pageflipping_init): Allocate offscreen buffer.
+       (doublebuf_pageflipping_update_screen): Use offscreen buffer.
+       (grub_video_fb_setup): Prefer doublebuffing.
+
 2012-06-15  Vladimir Serbinenko  <phcoder@gmail.com>
 
        * grub-core/normal/main.c (GRUB_MOD_INIT): Ignore errors when loading
index 2ab403db2b8cf7533f7a24b59a447aea8fdd4dff..9d79f77b5c36a86276fe9054385ff4053121bf59 100644 (file)
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
+typedef grub_err_t (*grub_video_fb_doublebuf_update_screen_t) (void);
+typedef volatile void *framebuf_t;
+
 static struct
 {
   struct grub_video_fbrender_target *render_target;
-  struct grub_video_fbrender_target *front_target;
   struct grub_video_fbrender_target *back_target;
   struct grub_video_palette_data *palette;
+  framebuf_t pages[2];
   unsigned int palette_size;
   /* For page flipping strategy.  */
   int displayed_page;           /* The page # that is the front buffer.  */
@@ -72,7 +75,6 @@ grub_video_fb_init (void)
 {
   grub_free (framebuffer.palette);
   framebuffer.render_target = 0;
-  framebuffer.front_target = 0;
   framebuffer.back_target = 0;
   framebuffer.palette = 0;
   framebuffer.palette_size = 0;
@@ -88,7 +90,6 @@ grub_video_fb_fini (void)
   grub_free (framebuffer.offscreen_buffer);
   grub_free (framebuffer.palette);
   framebuffer.render_target = 0;
-  framebuffer.front_target = 0;
   framebuffer.back_target = 0;
   framebuffer.palette = 0;
   framebuffer.palette_size = 0;
@@ -1283,64 +1284,57 @@ grub_video_fb_get_active_render_target (struct grub_video_fbrender_target **targ
 }
 
 static grub_err_t
-doublebuf_blit_update_screen (struct grub_video_fbrender_target *front,
-                             struct grub_video_fbrender_target *back)
+doublebuf_blit_update_screen (void)
 {
-  grub_memcpy (front->data, back->data,
-              front->mode_info.pitch * front->mode_info.height);
+  grub_memcpy ((void *) framebuffer.pages[0], framebuffer.back_target->data,
+              framebuffer.back_target->mode_info.pitch
+              * framebuffer.back_target->mode_info.height);
   return GRUB_ERR_NONE;
 }
 
 static grub_err_t
-grub_video_fb_doublebuf_blit_init (struct grub_video_fbrender_target **front,
-                                  struct grub_video_fbrender_target **back,
+grub_video_fb_doublebuf_blit_init (struct grub_video_fbrender_target **back,
                                   struct grub_video_mode_info mode_info,
-                                  void *framebuf)
+                                  volatile void *framebuf)
 {
   grub_err_t err;
-  int page_size = mode_info.pitch * mode_info.height;
-
-  err = grub_video_fb_create_render_target_from_pointer (front, &mode_info,
-                                                        framebuf);
-  if (err)
-    return err;
+  grub_size_t page_size = mode_info.pitch * mode_info.height;
 
   framebuffer.offscreen_buffer = grub_malloc (page_size);
   if (! framebuffer.offscreen_buffer)
-    {
-      grub_video_fb_delete_render_target (*front);
-      *front = 0;
-      return grub_errno;
-    }
+    return grub_errno;
 
-  err = grub_video_fb_create_render_target_from_pointer (back, &mode_info,
+  err = grub_video_fb_create_render_target_from_pointer (&framebuffer.back_target,
+                                                        &mode_info,
                                                         framebuffer.offscreen_buffer);
 
   if (err)
     {
-      grub_video_fb_delete_render_target (*front);
       grub_free (framebuffer.offscreen_buffer);
       framebuffer.offscreen_buffer = 0;
-      *front = 0;
       return grub_errno;
     }
   (*back)->is_allocated = 1;
 
   framebuffer.update_screen = doublebuf_blit_update_screen;
+  framebuffer.pages[0] = framebuf;
+  framebuffer.displayed_page = 0;
+  framebuffer.render_page = 0;
 
   return GRUB_ERR_NONE;
 }
 
 static grub_err_t
-doublebuf_pageflipping_update_screen (struct grub_video_fbrender_target *front
-                                     __attribute__ ((unused)),
-                                     struct grub_video_fbrender_target *back
-                                     __attribute__ ((unused)))
+doublebuf_pageflipping_update_screen (void)
 {
   int new_displayed_page;
-  struct grub_video_fbrender_target *target;
   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);
+
   /* Swap the page numbers in the framebuffer struct.  */
   new_displayed_page = framebuffer.render_page;
   framebuffer.render_page = framebuffer.displayed_page;
@@ -1355,26 +1349,7 @@ doublebuf_pageflipping_update_screen (struct grub_video_fbrender_target *front
       return err;
     }
 
-  target = framebuffer.back_target;
-  framebuffer.back_target = framebuffer.front_target;
-  framebuffer.front_target = target;
-
-  if (framebuffer.front_target->mode_info.mode_type
-      & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP)
-    grub_memcpy (framebuffer.back_target->data, framebuffer.front_target->data,
-                framebuffer.back_target->mode_info.pitch
-                * framebuffer.back_target->mode_info.height);
-
-  err = grub_video_fb_get_active_render_target (&target);
-  if (err)
-    return err;
-
-  if (framebuffer.render_target == framebuffer.back_target)
-    framebuffer.render_target = framebuffer.front_target;
-  else if (framebuffer.render_target == framebuffer.front_target)
-    framebuffer.render_target = framebuffer.back_target;
-
-  return err;
+  return GRUB_ERR_NONE;
 }
 
 static grub_err_t
@@ -1384,32 +1359,37 @@ doublebuf_pageflipping_init (struct grub_video_mode_info *mode_info,
                             volatile void *page1_ptr)
 {
   grub_err_t err;
+  grub_size_t page_size = mode_info->pitch * mode_info->height;
 
-  framebuffer.displayed_page = 0;
-  framebuffer.render_page = 1;
-
-  framebuffer.update_screen = doublebuf_pageflipping_update_screen;
-
-  err = grub_video_fb_create_render_target_from_pointer (&framebuffer.front_target,
-                                                        mode_info,
-                                                        (void *) page0_ptr);
-  if (err)
-    return err;
+  framebuffer.offscreen_buffer = grub_malloc (page_size);
+  if (! framebuffer.offscreen_buffer)
+    {
+      return grub_errno;
+    }
 
   err = grub_video_fb_create_render_target_from_pointer (&framebuffer.back_target,
                                                         mode_info,
-                                                        (void *) page1_ptr);
+                                                        framebuffer.offscreen_buffer);
+
   if (err)
     {
-      grub_video_fb_delete_render_target (framebuffer.front_target);
-      return err;
+      grub_free (framebuffer.offscreen_buffer);
+      framebuffer.offscreen_buffer = 0;
+      return grub_errno;
     }
+  framebuffer.back_target->is_allocated = 1;
+
+  framebuffer.displayed_page = 0;
+  framebuffer.render_page = 1;
+
+  framebuffer.update_screen = doublebuf_pageflipping_update_screen;
+  framebuffer.pages[0] = page0_ptr;
+  framebuffer.pages[1] = page1_ptr;
 
   /* Set the framebuffer memory data pointer and display the right page.  */
   err = set_page_in (framebuffer.displayed_page);
   if (err)
     {
-      grub_video_fb_delete_render_target (framebuffer.front_target);
       grub_video_fb_delete_render_target (framebuffer.back_target);
       return err;
     }
@@ -1427,20 +1407,14 @@ grub_video_fb_setup (unsigned int mode_type, unsigned int mode_mask,
                     volatile void *page1_ptr)
 {
   grub_err_t err;
-  int updating_swap_needed;
-
-  updating_swap_needed
-    = grub_video_check_mode_flag (mode_type, mode_mask,
-                                 GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP, 0);
 
   /* Do double buffering only if it's either requested or efficient.  */
   if (set_page_in && grub_video_check_mode_flag (mode_type, mode_mask,
                                                 GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED,
-                                                !updating_swap_needed))
+                                                1))
     {
       mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
-      if (updating_swap_needed)
-       mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP;
+      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP;
 
       err = doublebuf_pageflipping_init (mode_info, page0_ptr,
                                         set_page_in,
@@ -1459,7 +1433,7 @@ grub_video_fb_setup (unsigned int mode_type, unsigned int mode_mask,
 
   if (grub_video_check_mode_flag (mode_type, mode_mask,
                                  GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED,
-                                 0))
+                                 1))
     {
       /* It was much nicer with the cast directly at function call but
         some older gcc versions don't accept it properly.*/
@@ -1467,8 +1441,7 @@ grub_video_fb_setup (unsigned int mode_type, unsigned int mode_mask,
       mode_info->mode_type |= (GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
                               | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
 
-      err = grub_video_fb_doublebuf_blit_init (&framebuffer.front_target,
-                                              &framebuffer.back_target,
+      err = grub_video_fb_doublebuf_blit_init (&framebuffer.back_target,
                                               *mode_info,
                                               tmp);
 
@@ -1485,15 +1458,18 @@ grub_video_fb_setup (unsigned int mode_type, unsigned int mode_mask,
     }
 
   /* Fall back to no double buffering.  */
-  err = grub_video_fb_create_render_target_from_pointer (&framebuffer.front_target,
+  err = grub_video_fb_create_render_target_from_pointer (&framebuffer.back_target,
                                                         mode_info,
                                                         (void *) page0_ptr);
 
   if (err)
     return err;
 
-  framebuffer.back_target = framebuffer.front_target;
   framebuffer.update_screen = 0;
+  framebuffer.pages[0] = page0_ptr;
+  framebuffer.displayed_page = 0;
+  framebuffer.render_page = 0;
+  framebuffer.set_page = 0;
 
   mode_info->mode_type &= ~GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
 
@@ -1510,8 +1486,7 @@ grub_video_fb_swap_buffers (void)
   if (!framebuffer.update_screen)
     return GRUB_ERR_NONE;
 
-  err = framebuffer.update_screen (framebuffer.front_target,
-                                  framebuffer.back_target);
+  err = framebuffer.update_screen ();
   if (err)
     return err;
 
@@ -1522,23 +1497,17 @@ grub_err_t
 grub_video_fb_get_info_and_fini (struct grub_video_mode_info *mode_info,
                                 void **framebuf)
 {
-  grub_memcpy (mode_info, &(framebuffer.front_target->mode_info),
+  grub_memcpy (mode_info, &(framebuffer.back_target->mode_info),
               sizeof (*mode_info));
 
   /* We are about to load a kernel.  Switch back to page zero, since some
      kernel drivers expect that.  */
-  if ((mode_info->mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED)
-      && framebuffer.set_page && framebuffer.displayed_page != 0)
+  if (framebuffer.set_page && framebuffer.displayed_page != 0)
     {
-      /* Ensure both pages are exactly in sync.  */
-      grub_memcpy (framebuffer.back_target->data,
-                  framebuffer.front_target->data,
-                  framebuffer.back_target->mode_info.pitch
-                  * framebuffer.back_target->mode_info.height);
-      grub_video_swap_buffers ();
+      framebuffer.update_screen ();
     }
 
-  *framebuf = framebuffer.front_target->data;
+  *framebuf = (void *) framebuffer.pages[framebuffer.displayed_page];
 
   grub_video_fb_fini ();
 
index 913ea8376640f904441d6d36d2477f20315f087d..84f9b89ac1d4e58b1f125a717aff2332459827a3 100644 (file)
@@ -40,7 +40,6 @@ static int have_setcolors = 0;
 static struct
 {
   struct grub_video_mode_info mode_info;
-  struct grub_video_render_target *render_target;
   grub_uint8_t *ptr;
 } framebuffer;
 
@@ -186,23 +185,12 @@ grub_video_ieee1275_setup (unsigned int width, unsigned int height,
   grub_dprintf ("video", "IEEE1275: initialising FB @ %p %dx%dx%d\n",
                framebuffer.ptr, framebuffer.mode_info.width,
                framebuffer.mode_info.height, framebuffer.mode_info.bpp);
-  
-  err = grub_video_fb_create_render_target_from_pointer 
-    (&framebuffer.render_target, &framebuffer.mode_info, framebuffer.ptr);
 
+  err = grub_video_fb_setup (mode_type, mode_mask,
+                            &framebuffer.mode_info,
+                            framebuffer.ptr, NULL, NULL);
   if (err)
-    {
-      grub_dprintf ("video", "IEEE1275: Couldn't create FB target\n");
-      return err;
-    }
-  
-  err = grub_video_fb_set_active_render_target (framebuffer.render_target);
-  
-  if (err)
-    {
-      grub_dprintf ("video", "IEEE1275: Couldn't set FB target\n");
-      return err;
-    }
+    return err;
 
   grub_video_ieee1275_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS,
                                   grub_video_fbstd_colors);
@@ -210,22 +198,6 @@ grub_video_ieee1275_setup (unsigned int width, unsigned int height,
   return err;
 }
 
-static grub_err_t
-grub_video_ieee1275_swap_buffers (void)
-{
-  /* TODO: Implement buffer swapping.  */
-  return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_video_ieee1275_set_active_render_target (struct grub_video_render_target *target)
-{
-  if (target == GRUB_VIDEO_RENDER_TARGET_DISPLAY)
-    target = framebuffer.render_target;
-
-  return grub_video_fb_set_active_render_target (target);
-}
-
 static grub_err_t
 grub_video_ieee1275_get_info_and_fini (struct grub_video_mode_info *mode_info,
                                  void **framebuf)
@@ -287,10 +259,10 @@ static struct grub_video_adapter grub_video_ieee1275_adapter =
     .blit_bitmap = grub_video_fb_blit_bitmap,
     .blit_render_target = grub_video_fb_blit_render_target,
     .scroll = grub_video_fb_scroll,
-    .swap_buffers = grub_video_ieee1275_swap_buffers,
+    .swap_buffers = grub_video_fb_swap_buffers,
     .create_render_target = grub_video_fb_create_render_target,
     .delete_render_target = grub_video_fb_delete_render_target,
-    .set_active_render_target = grub_video_ieee1275_set_active_render_target,
+    .set_active_render_target = grub_video_fb_set_active_render_target,
     .get_active_render_target = grub_video_fb_get_active_render_target,
 
     .next = 0
index 6816f6f601ce674990c7a6138fa9cb564b23aaf1..d696398fe0d28ff20dae8de632024513459b8407 100644 (file)
@@ -115,10 +115,6 @@ grub_video_fb_get_active_render_target (struct grub_video_fbrender_target **targ
 grub_err_t
 grub_video_fb_set_active_render_target (struct grub_video_fbrender_target *target);
 
-typedef grub_err_t
-(*grub_video_fb_doublebuf_update_screen_t) (struct grub_video_fbrender_target *front,
-                                         struct grub_video_fbrender_target *back);
-
 typedef grub_err_t (*grub_video_fb_set_page_t) (int page);
 
 grub_err_t