]> git.proxmox.com Git - grub2.git/commitdiff
Move most framebuffer handling to video_fb.c
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sun, 16 May 2010 12:40:03 +0000 (14:40 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sun, 16 May 2010 12:40:03 +0000 (14:40 +0200)
include/grub/video_fb.h
video/fb/video_fb.c
video/i386/pc/vbe.c

index 3046a597b107362da1d7ad782fbd705145b5f17b..2c1907fdf3581829e3b72b7becbd052a9f28c02a 100644 (file)
@@ -119,11 +119,18 @@ 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
+grub_video_fb_setup (unsigned int mode_type, unsigned int mode_mask,
+                    struct grub_video_mode_info *mode_info,
+                    volatile void *page0_ptr,
+                    grub_video_fb_set_page_t set_page_in,
+                    volatile void *page1_ptr);
+grub_err_t
+grub_video_fb_swap_buffers (void);
 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_update_screen_t *update_screen,
-                                  struct grub_video_mode_info mode_info,
-                                  void *framebuf);
+grub_video_fb_get_info_and_fini (struct grub_video_mode_info *mode_info,
+                                void **framebuf);
 
 #endif /* ! GRUB_VIDEO_FB_HEADER */
index 9c5577bb9cfa53854613f6860012296fe405e0d9..6ec61868df64bc20812673c209dbd788c0aae0d0 100644 (file)
 #include <grub/bitmap.h>
 
 static struct grub_video_fbrender_target *render_target;
+static struct grub_video_fbrender_target *front_target;
+static struct grub_video_fbrender_target *back_target;
 struct grub_video_palette_data *palette;
 static unsigned int palette_size;
+/* For page flipping strategy.  */
+static int displayed_page;           /* The page # that is the front buffer.  */
+static int render_page;              /* The page # that is the back buffer.  */
+static grub_video_fb_set_page_t set_page;
+static char *offscreen_buffer;
+static grub_video_fb_doublebuf_update_screen_t update_screen;
 
 /* Specify "standard" VGA palette, some video cards may
    need this and this will also be used when using RGB modes.  */
@@ -58,8 +66,11 @@ grub_video_fb_init (void)
 {
   grub_free (palette);
   render_target = 0;
+  front_target = 0;
+  back_target = 0;
   palette = 0;
   palette_size = 0;
+  set_page = 0;
   return GRUB_ERR_NONE;
 }
 
@@ -68,10 +79,15 @@ grub_video_fb_fini (void)
 {
   /* TODO: destroy render targets.  */
 
+  grub_free (offscreen_buffer);
   grub_free (palette);
   render_target = 0;
+  front_target = 0;
+  back_target = 0;
   palette = 0;
   palette_size = 0;
+  set_page = 0;
+  offscreen_buffer = 0;
   return GRUB_ERR_NONE;
 }
 
@@ -1221,6 +1237,10 @@ grub_video_fb_delete_render_target (struct grub_video_fbrender_target *target)
 grub_err_t
 grub_video_fb_set_active_render_target (struct grub_video_fbrender_target *target)
 {
+  if (target == (struct grub_video_fbrender_target *)
+      GRUB_VIDEO_RENDER_TARGET_DISPLAY)
+      target = back_target;
+
   if (! target->data)
     return grub_error (GRUB_ERR_BAD_ARGUMENT,
                        "invalid render target given");
@@ -1235,6 +1255,9 @@ grub_video_fb_get_active_render_target (struct grub_video_fbrender_target **targ
 {
   *target = render_target;
 
+  if (*target == back_target)
+    *target = (struct grub_video_fbrender_target *) GRUB_VIDEO_RENDER_TARGET_DISPLAY;
+
   return GRUB_ERR_NONE;
 }
 
@@ -1247,16 +1270,14 @@ doublebuf_blit_update_screen (struct grub_video_fbrender_target *front,
   return GRUB_ERR_NONE;
 }
 
-grub_err_t
+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_update_screen_t *update_screen,
                                   struct grub_video_mode_info mode_info,
                                   void *framebuf)
 {
   grub_err_t err;
   int page_size = mode_info.pitch * mode_info.height;
-  void *offscreen_buffer;
 
   err = grub_video_fb_create_render_target_from_pointer (front, &mode_info,
                                                         framebuf);
@@ -1283,7 +1304,200 @@ grub_video_fb_doublebuf_blit_init (struct grub_video_fbrender_target **front,
     }
   (*back)->is_allocated = 1;
 
-  *update_screen = doublebuf_blit_update_screen;
+  update_screen = doublebuf_blit_update_screen;
+
+  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)))
+{
+  int new_displayed_page;
+  struct grub_video_fbrender_target *target;
+  grub_err_t err;
+
+  /* Swap the page numbers in the framebuffer struct.  */
+  new_displayed_page = render_page;
+  render_page = displayed_page;
+  displayed_page = new_displayed_page;
+
+  err = set_page (displayed_page);
+  if (err)
+    {
+      /* Restore previous state.  */
+      render_page = displayed_page;
+      displayed_page = new_displayed_page;
+      return err;
+    }
+
+  target = back_target;
+  back_target = front_target;
+  front_target = target;
+
+  if (front_target->mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP)
+    grub_memcpy (back_target->data, front_target->data,
+                back_target->mode_info.pitch * back_target->mode_info.height);
+
+  err = grub_video_fb_get_active_render_target (&target);
+  if (err)
+    return err;
+
+  if (render_target == back_target)
+    render_target = front_target;
+  else if (target == front_target)
+    render_target = back_target;
+
+  return err;
+}
+
+static grub_err_t
+doublebuf_pageflipping_init (struct grub_video_mode_info *mode_info,
+                            volatile void *page0_ptr,
+                            grub_video_fb_set_page_t set_page_in,
+                            volatile void *page1_ptr)
+{
+  grub_err_t err;
+
+  displayed_page = 0;
+  render_page = 1;
+
+  update_screen = doublebuf_pageflipping_update_screen;
+
+  err = grub_video_fb_create_render_target_from_pointer (&front_target,
+                                                        mode_info,
+                                                        (void *) page0_ptr);
+  if (err)
+    return err;
+
+  err = grub_video_fb_create_render_target_from_pointer (&back_target,
+                                                        mode_info,
+                                                        (void *) page1_ptr);
+  if (err)
+    {
+      grub_video_fb_delete_render_target (front_target);
+      return err;
+    }
+
+  /* Set the framebuffer memory data pointer and display the right page.  */
+  err = set_page_in (displayed_page);
+  if (err)
+    {
+      grub_video_fb_delete_render_target (front_target);
+      grub_video_fb_delete_render_target (back_target);
+      return err;
+    }
+  set_page = set_page_in;
+
+  return GRUB_ERR_NONE;
+}
+
+/* Select the best double buffering mode available.  */
+grub_err_t
+grub_video_fb_setup (unsigned int mode_type, unsigned int mode_mask,
+                    struct grub_video_mode_info *mode_info,
+                    volatile void *page0_ptr,
+                    grub_video_fb_set_page_t set_page_in,
+                    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))
+    {
+      mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
+      if (updating_swap_needed)
+       mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP;
+
+      err = doublebuf_pageflipping_init (mode_info, page0_ptr,
+                                        set_page_in,
+                                        page1_ptr);
+      if (!err)
+       {
+         render_target = back_target;
+         return GRUB_ERR_NONE;
+       }
+      
+      mode_info->mode_type &= ~(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
+                               | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
+
+      grub_errno = GRUB_ERR_NONE;
+    }
+
+  if (grub_video_check_mode_flag (mode_type, mode_mask,
+                                 GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED,
+                                 0))
+    {
+      mode_info->mode_type |= (GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
+                              | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
+
+      err = grub_video_fb_doublebuf_blit_init (&front_target,
+                                              &back_target,
+                                              *mode_info,
+                                              (void *) page0_ptr);
+
+      if (!err)
+       {
+         render_target = back_target;
+         return GRUB_ERR_NONE;
+       }
+
+      mode_info->mode_type &= ~(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
+                               | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
+
+      grub_errno = GRUB_ERR_NONE;
+    }
+
+  /* Fall back to no double buffering.  */
+  err = grub_video_fb_create_render_target_from_pointer (&front_target,
+                                                        mode_info,
+                                                        (void *) page0_ptr);
+
+  if (err)
+    return err;
+
+  back_target = front_target;
+  update_screen = 0;
+
+  mode_info->mode_type &= ~GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
+
+  render_target = back_target;
+
+  return GRUB_ERR_NONE;
+}
+
+
+grub_err_t
+grub_video_fb_swap_buffers (void)
+{
+  grub_err_t err;
+  if (!update_screen)
+    return GRUB_ERR_NONE;
+
+  err = update_screen (front_target, back_target);
+  if (err)
+    return err;
+
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_video_fb_get_info_and_fini (struct grub_video_mode_info *mode_info,
+                                void **framebuf)
+{
+  grub_memcpy (mode_info, &(front_target->mode_info), sizeof (*mode_info));
+  *framebuf = front_target->data;
+
+  grub_video_fb_fini ();
 
   return GRUB_ERR_NONE;
 }
index 72b8f183184cbaea233cd8267595e60ee5fd2a6a..05c6db736f0b3463912ab4c8f60b5a590c5bc746 100644 (file)
@@ -40,25 +40,12 @@ static grub_uint32_t last_set_mode = 3;
 static struct
 {
   struct grub_video_mode_info mode_info;
-  struct grub_video_render_target *front_target;
-  struct grub_video_render_target *back_target;
 
   unsigned int bytes_per_scan_line;
   unsigned int bytes_per_pixel;
   grub_uint32_t active_vbe_mode;
   grub_uint8_t *ptr;
   int index_color_mode;
-
-  char *offscreen_buffer;
-
-  grub_size_t page_size;        /* The size of a page in bytes.  */
-
-  /* For page flipping strategy.  */
-  int displayed_page;           /* The page # that is the front buffer.  */
-  int render_page;              /* The page # that is the back buffer.  */
-
-  /* Virtual functions.  */
-  grub_video_fb_doublebuf_update_screen_t update_screen;
 } framebuffer;
 
 static grub_uint32_t initial_vbe_mode;
@@ -377,7 +364,6 @@ grub_video_vbe_fini (void)
   vbe_mode_list = NULL;
 
   err = grub_video_fb_fini ();
-  grub_free (framebuffer.offscreen_buffer);
   return err;
 }
 
@@ -387,11 +373,11 @@ grub_video_vbe_fini (void)
   respectively.
 */
 static grub_err_t
-doublebuf_pageflipping_commit (void)
+doublebuf_pageflipping_set_page (int page)
 {
   /* Tell the video adapter to display the new front page.  */
   int display_start_line
-    = framebuffer.mode_info.height * framebuffer.displayed_page;
+    = framebuffer.mode_info.height * page;
 
   grub_vbe_status_t vbe_err =
     grub_vbe_bios_set_display_start (0, display_start_line);
@@ -402,164 +388,6 @@ doublebuf_pageflipping_commit (void)
   return 0;
 }
 
-static grub_err_t
-doublebuf_pageflipping_update_screen (struct grub_video_fbrender_target *front
-                                     __attribute__ ((unused)),
-                                     struct grub_video_fbrender_target *back
-                                     __attribute__ ((unused)))
-{
-  int new_displayed_page;
-  struct grub_video_fbrender_target *target;
-  grub_err_t err;
-
-  /* Swap the page numbers in the framebuffer struct.  */
-  new_displayed_page = framebuffer.render_page;
-  framebuffer.render_page = framebuffer.displayed_page;
-  framebuffer.displayed_page = new_displayed_page;
-
-  err = doublebuf_pageflipping_commit ();
-  if (err)
-    {
-      /* Restore previous state.  */
-      framebuffer.render_page = framebuffer.displayed_page;
-      framebuffer.displayed_page = new_displayed_page;
-      return err;
-    }
-
-  if (framebuffer.mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP)
-    grub_memcpy (framebuffer.ptr + framebuffer.render_page
-                * framebuffer.page_size, framebuffer.ptr
-                + framebuffer.displayed_page * framebuffer.page_size,
-                framebuffer.page_size);
-
-  target = framebuffer.back_target;
-  framebuffer.back_target = framebuffer.front_target;
-  framebuffer.front_target = target;
-
-  err = grub_video_fb_get_active_render_target (&target);
-  if (err)
-    return err;
-
-  if (target == framebuffer.back_target)
-    err = grub_video_fb_set_active_render_target (framebuffer.front_target);
-  else if (target == framebuffer.front_target)
-    err = grub_video_fb_set_active_render_target (framebuffer.back_target);
-
-  return err;
-}
-
-static grub_err_t
-doublebuf_pageflipping_init (void)
-{
-  /* Get video RAM size in bytes.  */
-  grub_size_t vram_size = controller_info.total_memory << 16;
-  grub_err_t err;
-
-  framebuffer.page_size =
-    framebuffer.mode_info.pitch * framebuffer.mode_info.height;
-
-  if (2 * framebuffer.page_size > vram_size)
-    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-                      "Not enough video memory for double buffering.");
-
-  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, &framebuffer.mode_info, framebuffer.ptr);
-  if (err)
-    return err;
-
-  err = grub_video_fb_create_render_target_from_pointer (&framebuffer.back_target, &framebuffer.mode_info, framebuffer.ptr + framebuffer.page_size);
-  if (err)
-    {
-      grub_video_fb_delete_render_target (framebuffer.front_target);
-      return err;
-    }
-
-  /* Set the framebuffer memory data pointer and display the right page.  */
-  err = doublebuf_pageflipping_commit ();
-  if (err)
-    {
-      grub_video_fb_delete_render_target (framebuffer.front_target);
-      grub_video_fb_delete_render_target (framebuffer.back_target);
-      return err;
-    }
-
-  return GRUB_ERR_NONE;
-}
-
-/* Select the best double buffering mode available.  */
-static grub_err_t
-double_buffering_init (unsigned int mode_type, unsigned int mode_mask)
-{
-  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 (grub_video_check_mode_flag (mode_type, mode_mask,
-                                 GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED,
-                                 !updating_swap_needed))
-    {
-      framebuffer.mode_info.mode_type |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
-      if (updating_swap_needed)
-       framebuffer.mode_info.mode_type |= GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP;
-      err = doublebuf_pageflipping_init ();
-      if (!err)
-       return GRUB_ERR_NONE;
-      
-      framebuffer.mode_info.mode_type
-       &= ~(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
-            | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
-
-      grub_errno = GRUB_ERR_NONE;
-    }
-
-  if (grub_video_check_mode_flag (mode_type, mode_mask,
-                                 GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED,
-                                 0))
-    {
-      framebuffer.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,
-                                              &framebuffer.update_screen,
-                                              framebuffer.mode_info,
-                                              framebuffer.ptr);
-
-      if (!err)
-       return GRUB_ERR_NONE;
-
-      framebuffer.mode_info.mode_type
-       &= ~(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
-            | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
-
-      grub_errno = GRUB_ERR_NONE;
-    }
-
-  /* Fall back to no double buffering.  */
-  err = grub_video_fb_create_render_target_from_pointer (&framebuffer.front_target, &framebuffer.mode_info, framebuffer.ptr);
-
-  if (err)
-    return err;
-
-  framebuffer.back_target = framebuffer.front_target;
-  framebuffer.update_screen = 0;
-
-  framebuffer.mode_info.mode_type &= ~GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
-
-  return GRUB_ERR_NONE;
-}
-
-
-
 static grub_err_t
 grub_video_vbe_setup (unsigned int width, unsigned int height,
                       unsigned int mode_type, unsigned int mode_mask)
@@ -684,15 +512,24 @@ grub_video_vbe_setup (unsigned int width, unsigned int height,
 
       framebuffer.mode_info.blit_format = grub_video_get_blit_format (&framebuffer.mode_info);
 
-      /* Set up double buffering and targets.  */
-      err = double_buffering_init (mode_type, mode_mask);
-      if (err)
-       return err;
-
-      err = grub_video_fb_set_active_render_target (framebuffer.back_target);
-
-      if (err)
-       return err;
+      {
+       /* Get video RAM size in bytes.  */
+       grub_size_t vram_size = controller_info.total_memory << 16;
+       grub_size_t page_size;        /* The size of a page in bytes.  */
+
+       page_size = framebuffer.mode_info.pitch * framebuffer.mode_info.height;
+
+       if (vram_size >= 2 * page_size)
+         err = grub_video_fb_setup (mode_type, mode_mask,
+                                    &framebuffer.mode_info,
+                                    framebuffer.ptr,
+                                    doublebuf_pageflipping_set_page,
+                                    framebuffer.ptr + page_size);
+       else
+         err = grub_video_fb_setup (mode_type, mode_mask,
+                                    &framebuffer.mode_info,
+                                    framebuffer.ptr, 0, 0);
+      }
 
       /* Copy default palette to initialize emulated palette.  */
       err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS,
@@ -723,59 +560,13 @@ grub_video_vbe_set_palette (unsigned int start, unsigned int count,
   return grub_video_fb_set_palette (start, count, palette_data);
 }
 
-static grub_err_t
-grub_video_vbe_swap_buffers (void)
-{
-  grub_err_t err;
-  if (!framebuffer.update_screen)
-    return GRUB_ERR_NONE;
-
-  err = framebuffer.update_screen (framebuffer.front_target,
-                                  framebuffer.back_target);
-  if (err)
-    return err;
-
-  return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_video_vbe_set_active_render_target (struct grub_video_render_target *target)
-{
-  if (target == GRUB_VIDEO_RENDER_TARGET_DISPLAY)
-      target = framebuffer.back_target;
-
-  return grub_video_fb_set_active_render_target (target);
-}
-
-static grub_err_t
-grub_video_vbe_get_active_render_target (struct grub_video_render_target **target)
-{
-  grub_err_t err;
-  err = grub_video_fb_get_active_render_target (target);
-  if (err)
-    return err;
-
-  if (*target == framebuffer.back_target)
-    *target = GRUB_VIDEO_RENDER_TARGET_DISPLAY;
-
-  return GRUB_ERR_NONE;
-}
-
 static grub_err_t
 grub_video_vbe_get_info_and_fini (struct grub_video_mode_info *mode_info,
                                  void **framebuf)
 {
-  grub_memcpy (mode_info, &(framebuffer.mode_info), sizeof (*mode_info));
-  *framebuf = (char *) framebuffer.ptr
-    + framebuffer.displayed_page * framebuffer.page_size;
-
   grub_free (vbe_mode_list);
   vbe_mode_list = NULL;
-
-  grub_video_fb_fini ();
-  grub_free (framebuffer.offscreen_buffer);
-
-  return GRUB_ERR_NONE;
+  return grub_video_fb_get_info_and_fini (mode_info, framebuf);
 }
 
 static struct grub_video_adapter grub_video_vbe_adapter =
@@ -800,11 +591,11 @@ static struct grub_video_adapter grub_video_vbe_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_vbe_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_vbe_set_active_render_target,
-    .get_active_render_target = grub_video_vbe_get_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
   };