Initial reimport of double buffering
This commit is contained in:
parent
df48e9e18d
commit
1f56d83788
10 changed files with 318 additions and 23 deletions
31
ChangeLog.video
Normal file
31
ChangeLog.video
Normal file
|
@ -0,0 +1,31 @@
|
|||
2009-08-24 Colin D Bennett <colin@gibibit.com>
|
||||
2009-08-24 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Double buffering support.
|
||||
|
||||
* commands/i386/pc/videotest.c (grub_cmd_videotest): Swap doublebuffers.
|
||||
* include/grub/video.h: Update comment.
|
||||
* include/grub/video_fb.h (grub_video_fb_doublebuf_update_screen_t):
|
||||
New type.
|
||||
(grub_video_fb_doublebuf_blit_init): New prototype.
|
||||
* term/gfxterm.c (scroll_up): Support double buffering.
|
||||
(grub_gfxterm_refresh): Likewise.
|
||||
* video/fb/video_fb.c (doublebuf_blit_update_screen): New function.
|
||||
(grub_video_fb_doublebuf_blit_init): Likewise.
|
||||
* video/i386/pc/vbe.c (framebuffer): Remove 'render_target'. Add
|
||||
'front_target', 'back_target', 'offscreen_buffer', 'page_size',
|
||||
'displayed_page', 'render_page' and 'update_screen'.
|
||||
(grub_video_vbe_fini): Free offscreen buffer.
|
||||
(doublebuf_pageflipping_commit): New function.
|
||||
(doublebuf_pageflipping_update_screen): Likewise.
|
||||
(doublebuf_pageflipping_init): Likewise.
|
||||
(double_buffering_init): Likewise.
|
||||
(grub_video_vbe_setup): Enable doublebuffering.
|
||||
(grub_video_vbe_swap_buffers): Implement.
|
||||
(grub_video_vbe_set_active_render_target): Handle double buffering.
|
||||
(grub_video_vbe_get_active_render_target): Likewise.
|
||||
(grub_video_vbe_get_info_and_fini): Likewise. Free offscreen_buffer.
|
||||
(grub_video_vbe_adapter): Use grub_video_vbe_get_active_render_target.
|
||||
(grub_video_vbe_enable_double_buffering): Likewise.
|
||||
(grub_video_vbe_swap_buffers): Use update_screen.
|
||||
(grub_video_set_mode): Use double buffering.
|
|
@ -315,7 +315,6 @@ grub_mini_cmd_lsmod (struct grub_command *cmd __attribute__ ((unused)),
|
|||
grub_printf ("%s", dep->mod->name);
|
||||
}
|
||||
grub_putchar ('\n');
|
||||
grub_refresh ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,9 @@ struct grub_video_render_target;
|
|||
struct grub_video_bitmap;
|
||||
|
||||
/* Defines used to describe video mode or rendering target. */
|
||||
/* If following is set render target contains previously displayed image
|
||||
after swapping buffers (otherwise it contains newly displayedd image).
|
||||
*/
|
||||
#define GRUB_VIDEO_MODE_TYPE_PURE_TEXT 0x00000040
|
||||
#define GRUB_VIDEO_MODE_TYPE_ALPHA 0x00000020
|
||||
#define GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED 0x00000010
|
||||
|
@ -48,6 +51,8 @@ struct grub_video_bitmap;
|
|||
#define GRUB_VIDEO_MODE_TYPE_DEPTH_MASK 0x0000ff00
|
||||
#define GRUB_VIDEO_MODE_TYPE_DEPTH_POS 8
|
||||
|
||||
/* The basic render target representing the whole display. This always
|
||||
renders to the back buffer when double-buffering is in use. */
|
||||
#define GRUB_VIDEO_RENDER_TARGET_DISPLAY \
|
||||
((struct grub_video_render_target *) 0)
|
||||
|
||||
|
|
|
@ -115,4 +115,15 @@ 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);
|
||||
|
||||
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);
|
||||
|
||||
#endif /* ! GRUB_VIDEO_FB_HEADER */
|
||||
|
|
|
@ -161,7 +161,6 @@ grub_vprintf (const char *fmt, va_list args)
|
|||
int ret;
|
||||
|
||||
ret = grub_vsprintf (0, fmt, args);
|
||||
grub_refresh ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -818,9 +817,6 @@ grub_vsprintf (char *str, const char *fmt, va_list args)
|
|||
if (str)
|
||||
*str = '\0';
|
||||
|
||||
if (count && !str)
|
||||
grub_refresh ();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
|
@ -131,6 +131,7 @@ grub_getcharwidth (grub_uint32_t code)
|
|||
int
|
||||
grub_getkey (void)
|
||||
{
|
||||
grub_refresh ();
|
||||
return (grub_cur_term_input->getkey) ();
|
||||
}
|
||||
|
||||
|
|
|
@ -199,8 +199,6 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
|
|||
xpos = (plen + lpos) % 79;
|
||||
ypos = ystart + (plen + lpos) / 79;
|
||||
grub_gotoxy (xpos, ypos);
|
||||
|
||||
grub_refresh ();
|
||||
}
|
||||
|
||||
void cl_print (int pos, int c)
|
||||
|
@ -241,8 +239,6 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
|
|||
cl_print (lpos - len, echo_char);
|
||||
cl_set_pos ();
|
||||
}
|
||||
|
||||
grub_refresh ();
|
||||
}
|
||||
|
||||
void cl_delete (unsigned len)
|
||||
|
@ -262,8 +258,6 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
|
|||
cl_print (lpos, echo_char);
|
||||
cl_set_pos ();
|
||||
}
|
||||
|
||||
grub_refresh ();
|
||||
}
|
||||
|
||||
plen = grub_strlen (prompt);
|
||||
|
@ -283,6 +277,8 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
|
|||
if (history && hist_used == 0)
|
||||
grub_history_add (buf);
|
||||
|
||||
grub_refresh ();
|
||||
|
||||
while ((key = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != '\n' && key != '\r')
|
||||
{
|
||||
if (readline)
|
||||
|
@ -457,6 +453,8 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
grub_refresh ();
|
||||
}
|
||||
|
||||
grub_putchar ('\n');
|
||||
|
|
|
@ -124,6 +124,8 @@ static unsigned int calculate_normal_character_width (grub_font_t font);
|
|||
|
||||
static unsigned char calculate_character_width (struct grub_font_glyph *glyph);
|
||||
|
||||
static void grub_gfxterm_refresh (void);
|
||||
|
||||
static void
|
||||
set_term_color (grub_uint8_t term_color)
|
||||
{
|
||||
|
@ -815,6 +817,9 @@ grub_gfxterm_cls (void)
|
|||
|
||||
/* Mark virtual screen to be redrawn. */
|
||||
dirty_region_add_virtualscreen ();
|
||||
|
||||
dirty_region_redraw ();
|
||||
grub_gfxterm_refresh ();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -877,6 +882,8 @@ grub_gfxterm_refresh (void)
|
|||
{
|
||||
/* Redraw only changed regions. */
|
||||
dirty_region_redraw ();
|
||||
|
||||
grub_video_swap_buffers ();
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
|
|
|
@ -66,6 +66,8 @@ grub_video_fb_init (void)
|
|||
grub_err_t
|
||||
grub_video_fb_fini (void)
|
||||
{
|
||||
/* TODO: destroy render targets. */
|
||||
|
||||
grub_free (palette);
|
||||
render_target = 0;
|
||||
palette = 0;
|
||||
|
@ -1182,3 +1184,53 @@ grub_video_fb_get_active_render_target (struct grub_video_fbrender_target **targ
|
|||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
doublebuf_blit_update_screen (struct grub_video_fbrender_target *front,
|
||||
struct grub_video_fbrender_target *back)
|
||||
{
|
||||
grub_memcpy (front->data, back->data,
|
||||
front->mode_info.pitch * front->mode_info.height);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
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);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
offscreen_buffer = grub_malloc (page_size);
|
||||
if (! offscreen_buffer)
|
||||
{
|
||||
grub_video_fb_delete_render_target (*front);
|
||||
*front = 0;
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
err = grub_video_fb_create_render_target_from_pointer (back, &mode_info,
|
||||
offscreen_buffer);
|
||||
|
||||
if (err)
|
||||
{
|
||||
grub_video_fb_delete_render_target (*front);
|
||||
grub_free (offscreen_buffer);
|
||||
*front = 0;
|
||||
return grub_errno;
|
||||
}
|
||||
(*back)->is_allocated = 1;
|
||||
|
||||
*update_screen = doublebuf_blit_update_screen;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
|
|
@ -36,13 +36,25 @@ static struct grub_vbe_mode_info_block active_vbe_mode_info;
|
|||
static struct
|
||||
{
|
||||
struct grub_video_mode_info mode_info;
|
||||
struct grub_video_render_target *render_target;
|
||||
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;
|
||||
|
@ -344,6 +356,7 @@ static grub_err_t
|
|||
grub_video_vbe_fini (void)
|
||||
{
|
||||
grub_vbe_status_t status;
|
||||
grub_err_t err;
|
||||
|
||||
/* Restore old video mode. */
|
||||
status = grub_vbe_bios_set_mode (initial_vbe_mode, 0);
|
||||
|
@ -355,11 +368,170 @@ grub_video_vbe_fini (void)
|
|||
grub_free (vbe_mode_list);
|
||||
vbe_mode_list = NULL;
|
||||
|
||||
/* TODO: destroy render targets. */
|
||||
|
||||
return grub_video_fb_fini ();
|
||||
err = grub_video_fb_fini ();
|
||||
grub_free (framebuffer.offscreen_buffer);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
Set framebuffer render target page and display the proper page, based on
|
||||
`doublebuf_state.render_page' and `doublebuf_state.displayed_page',
|
||||
respectively.
|
||||
*/
|
||||
static grub_err_t
|
||||
doublebuf_pageflipping_commit (void)
|
||||
{
|
||||
/* Tell the video adapter to display the new front page. */
|
||||
int display_start_line
|
||||
= framebuffer.mode_info.height * framebuffer.displayed_page;
|
||||
|
||||
grub_vbe_status_t vbe_err =
|
||||
grub_vbe_bios_set_display_start (0, display_start_line);
|
||||
|
||||
if (vbe_err != GRUB_VBE_STATUS_OK)
|
||||
return grub_error (GRUB_ERR_IO, "couldn't commit pageflip");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (grub_video_check_mode_flag (mode_type, mode_mask,
|
||||
GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED, 1))
|
||||
{
|
||||
err = doublebuf_pageflipping_init ();
|
||||
if (!err)
|
||||
{
|
||||
framebuffer.mode_info.mode_type
|
||||
|= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
err = grub_video_fb_doublebuf_blit_init (&framebuffer.front_target,
|
||||
&framebuffer.back_target,
|
||||
&framebuffer.update_screen,
|
||||
framebuffer.mode_info,
|
||||
framebuffer.ptr);
|
||||
|
||||
if (!err)
|
||||
{
|
||||
framebuffer.mode_info.mode_type
|
||||
|= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -488,12 +660,12 @@ grub_video_vbe_setup (unsigned int width, unsigned int height,
|
|||
|
||||
framebuffer.mode_info.blit_format = grub_video_get_blit_format (&framebuffer.mode_info);
|
||||
|
||||
err = grub_video_fb_create_render_target_from_pointer (&framebuffer.render_target, &framebuffer.mode_info, framebuffer.ptr);
|
||||
|
||||
/* 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.render_target);
|
||||
err = grub_video_fb_set_active_render_target (framebuffer.back_target);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -530,7 +702,15 @@ grub_video_vbe_set_palette (unsigned int start, unsigned int count,
|
|||
static grub_err_t
|
||||
grub_video_vbe_swap_buffers (void)
|
||||
{
|
||||
/* TODO: Implement buffer swapping. */
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -538,27 +718,42 @@ 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.render_target;
|
||||
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;
|
||||
*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;
|
||||
}
|
||||
|
||||
|
||||
static struct grub_video_adapter grub_video_vbe_adapter =
|
||||
{
|
||||
.name = "VESA BIOS Extension Video Driver",
|
||||
|
@ -584,7 +779,7 @@ static struct grub_video_adapter grub_video_vbe_adapter =
|
|||
.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_fb_get_active_render_target,
|
||||
.get_active_render_target = grub_video_vbe_get_active_render_target,
|
||||
|
||||
.next = 0
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue