From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with archive (Exim 4.43) id 1KZiYt-0002hT-8w for mharc-grub-devel@gnu.org; Sun, 31 Aug 2008 04:45:31 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1KZiYr-0002gf-Oj for grub-devel@gnu.org; Sun, 31 Aug 2008 04:45:29 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1KZiYp-0002f7-Af for grub-devel@gnu.org; Sun, 31 Aug 2008 04:45:29 -0400 Received: from [199.232.76.173] (port=39209 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1KZiYp-0002f4-3T for grub-devel@gnu.org; Sun, 31 Aug 2008 04:45:27 -0400 Received: from gateway08.websitewelcome.com ([69.41.248.18]:55169) by monty-python.gnu.org with smtp (Exim 4.60) (envelope-from ) id 1KZiYm-0002VY-W7 for grub-devel@gnu.org; Sun, 31 Aug 2008 04:45:26 -0400 Received: (qmail 31493 invoked from network); 31 Aug 2008 07:11:22 -0000 Received: from gator297.hostgator.com (74.53.228.114) by gateway08.websitewelcome.com with SMTP; 31 Aug 2008 07:11:22 -0000 Received: from c-67-185-142-228.hsd1.wa.comcast.net ([67.185.142.228]:43521 helo=gamma.lan) by gator297.hostgator.com with esmtpsa (TLSv1:AES128-SHA:128) (Exim 4.68) (envelope-from ) id 1KZgtO-0005on-Cc for grub-devel@gnu.org; Sun, 31 Aug 2008 01:58:34 -0500 Date: Sat, 30 Aug 2008 23:58:33 -0700 From: Colin D Bennett To: grub-devel@gnu.org Message-ID: <20080830235833.3b29b3c2@gamma.lan> X-Mailer: Claws Mail 3.5.0 (GTK+ 2.12.11; i686-pc-linux-gnu) Mime-Version: 1.0 Content-Type: multipart/signed; boundary="Sig_/B.ofmYsA5=MeWOG6Dnm4hzy"; protocol="application/pgp-signature"; micalg=PGP-SHA1 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - gator297.hostgator.com X-AntiAbuse: Original Domain - gnu.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - gibibit.com X-detected-kernel: by monty-python.gnu.org: Linux 2.6 (newer, 3) Subject: [PATCH] GSoC #07 VBE double buffering X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: The development of GRUB 2 List-Id: The development of GRUB 2 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 31 Aug 2008 08:45:30 -0000 --Sig_/B.ofmYsA5=MeWOG6Dnm4hzy Content-Type: multipart/mixed; boundary="MP_/mK7gEZ93HgBPb3+gVTalZuN" --MP_/mK7gEZ93HgBPb3+gVTalZuN Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: quoted-printable Content-Disposition: inline This patch adds double buffering support to the VBE video driver. It uses page flipping if possible, and falls back on using an offscreen buffer which is blitted to video memory if page flipping is not possible. Regards, Colin --MP_/mK7gEZ93HgBPb3+gVTalZuN Content-Type: text/plain; name=07_ChangeLog.txt Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename=07_ChangeLog.txt 2008-08-30 Colin D Bennett VBE smart double buffering using page flipping or blitting. * include/grub/video.h (GRUB_VIDEO_RENDER_TARGET_FRONT_BUFFER): Removed. (GRUB_VIDEO_RENDER_TARGET_BACK_BUFFER): Removed. * video/i386/pc/vbe.c (framebuffer): Added is_double_buffered field. (doublebuf_state): New struct. (double_buffering_init): New function. (grub_video_vbe_init): Clear doublebuf_state. (grub_video_vbe_fini): Destroy doublebuf_state. (grub_video_vbe_setup): Call double_buffering_init to initialize double buffering. (doublebuf_pageflipping_commit): New function. (doublebuf_pageflipping_update_screen): New function. (doublebuf_pageflipping_destroy): New function. (doublebuf_pageflipping_init): New function. (doublebuf_blit_update_screen): New function. (doublebuf_blit_destroy): New function. (doublebuf_blit_init): New function. (doublebuf_null_update_screen): New function. (doublebuf_null_destroy): New function. (doublebuf_null_init): New function. (double_buffering_init): New function. (grub_video_vbe_swap_buffers): Implement buffer swapping. (grub_video_vbe_set_active_render_target): Handle special target GRUB_VIDEO_RENDER_TARGET_DISPLAY and neither GRUB_VIDEO_RENDER_TARGET_FRONT_BUFFER nor GRUB_VIDEO_RENDER_TARGET_BACK_BUFFER. --MP_/mK7gEZ93HgBPb3+gVTalZuN Content-Type: text/x-patch; name=07_vbe-doublebuf.patch Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename=07_vbe-doublebuf.patch =3D=3D=3D modified file 'include/grub/video.h' --- include/grub/video.h 2008-08-31 01:02:11 +0000 +++ include/grub/video.h 2008-08-31 06:19:25 +0000 @@ -47,10 +47,11 @@ #define GRUB_VIDEO_MODE_TYPE_DEPTH_MASK 0x0000ff00 #define GRUB_VIDEO_MODE_TYPE_DEPTH_POS 8 =20 -/* Defined predefined render targets. */ -#define GRUB_VIDEO_RENDER_TARGET_DISPLAY ((struct grub_video_render_target= *) 0) -#define GRUB_VIDEO_RENDER_TARGET_FRONT_BUFFER ((struct grub_video_render_t= arget *) 0) -#define GRUB_VIDEO_RENDER_TARGET_BACK_BUFFER ((struct grub_video_render_ta= rget *) 1) +/* Predefined render target: */ +/* The render target that client code should render to. */ +#define GRUB_VIDEO_RENDER_TARGET_DISPLAY \ + ((struct grub_video_render_target *) 0) + =20 /* Defined blitting formats. */ enum grub_video_blit_format @@ -267,6 +268,9 @@ =20 grub_err_t grub_video_scroll (grub_video_color_t color, int dx, int dy); =20 +/* Swap the pages referred to by the front buffer and back buffer render + * targets, and the page previously referred to by the back buffer is made + * visible on the display. */ grub_err_t grub_video_swap_buffers (void); =20 grub_err_t grub_video_create_render_target (struct grub_video_render_targe= t **result, =3D=3D=3D modified file 'video/i386/pc/vbe.c' --- video/i386/pc/vbe.c 2008-08-31 01:07:22 +0000 +++ video/i386/pc/vbe.c 2008-08-31 06:19:26 +0000 @@ -63,6 +63,7 @@ static struct { struct grub_video_render_target render_target; + int is_double_buffered; /* Is the video mode double buffered? */ =20 unsigned int bytes_per_scan_line; unsigned int bytes_per_pixel; @@ -77,6 +78,24 @@ static grub_uint32_t mode_in_use =3D 0x55aa; static grub_uint16_t *mode_list; =20 +static struct=20 +{ + 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. */ + + /* For blit strategy. */ + grub_uint8_t *offscreen_buffer; + + /* Virtual functions. */ + int (*update_screen) (void); + int (*destroy) (void); +} doublebuf_state; + +static void double_buffering_init (void); + static void * real2pm (grub_vbe_farptr_t ptr) { @@ -376,6 +395,7 @@ /* Reset frame buffer and render target variables. */ grub_memset (&framebuffer, 0, sizeof(framebuffer)); render_target =3D &framebuffer.render_target; + grub_memset (&doublebuf_state, 0, sizeof(doublebuf_state)); =20 return GRUB_ERR_NONE; } @@ -391,6 +411,9 @@ /* TODO: Decide, is this something we want to do. */ return grub_errno; =20 + if (doublebuf_state.destroy) + doublebuf_state.destroy(); + /* TODO: Free any resources allocated by driver. */ grub_free (mode_list); mode_list =3D 0; @@ -533,9 +556,13 @@ render_target->viewport.width =3D active_mode_info.x_resolution; render_target->viewport.height =3D active_mode_info.y_resolution; =20 - /* Set framebuffer pointer and mark it as non allocated. */ + /* Mark framebuffer memory as non allocated. */ render_target->is_allocated =3D 0; - render_target->data =3D framebuffer.ptr; + + /* Set up double buffering information. */ + framebuffer.is_double_buffered =3D + ((mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED) !=3D 0); + double_buffering_init (); =20 /* Copy default palette to initialize emulated palette. */ for (i =3D 0;=20 @@ -556,6 +583,166 @@ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching mode found."); } =20 +/*=20 + Set framebuffer render target page and display the proper page, based on + `doublebuf_state.render_page' and `doublebuf_state.displayed_page', + respectively.=20 + + Returns 0 upon success, nonzero upon failure. + */ +static int +doublebuf_pageflipping_commit (void) +{ + /* Set the render target's data pointer to the start of the render_page.= */ + framebuffer.render_target.data =3D + ((char *) framebuffer.ptr) + + doublebuf_state.page_size * doublebuf_state.render_page; + + /* Tell the video adapter to display the new front page. */ + int display_start_line =3D + framebuffer.render_target.mode_info.height=20 + * doublebuf_state.displayed_page; +=20 + grub_vbe_status_t vbe_err =3D=20 + grub_vbe_bios_set_display_start (0, display_start_line); + if (vbe_err !=3D GRUB_VBE_STATUS_OK) + return 1; + + return 0; +} + +static int +doublebuf_pageflipping_update_screen (void) +{ + /* Swap the page numbers in the framebuffer struct. */ + int new_displayed_page =3D doublebuf_state.render_page; + doublebuf_state.render_page =3D doublebuf_state.displayed_page; + doublebuf_state.displayed_page =3D new_displayed_page; + + return doublebuf_pageflipping_commit (); +} + +static int +doublebuf_pageflipping_destroy (void) +{ + doublebuf_state.update_screen =3D 0; + doublebuf_state.destroy =3D 0; + return 0; +} + +static int +doublebuf_pageflipping_init (void) +{ + doublebuf_state.page_size =3D + framebuffer.bytes_per_scan_line * render_target->mode_info.height; + =20 + /* Get video RAM size in bytes. */ + grub_size_t vram_size =3D controller_info.total_memory << 16; + + if (2 * doublebuf_state.page_size > vram_size) + return 1; /* Not enough video memory for 2 pages. */ + + doublebuf_state.displayed_page =3D 0; + doublebuf_state.render_page =3D 1; + + doublebuf_state.update_screen =3D doublebuf_pageflipping_update_screen; + doublebuf_state.destroy =3D doublebuf_pageflipping_destroy; + + /* Set the framebuffer memory data pointer and display the right page. */ + if (doublebuf_pageflipping_commit () !=3D GRUB_ERR_NONE) + return 1; /* Unable to set the display start. */ + + framebuffer.render_target.mode_info.mode_type + |=3D GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED; + return 0; +} + +static int +doublebuf_blit_update_screen (void) +{ + grub_memcpy (framebuffer.ptr, + doublebuf_state.offscreen_buffer,=20 + doublebuf_state.page_size); + return 0; +} + +static int +doublebuf_blit_destroy (void) +{ + grub_free (doublebuf_state.offscreen_buffer); + doublebuf_state.offscreen_buffer =3D 0; + + doublebuf_state.update_screen =3D 0; + doublebuf_state.destroy =3D 0; + return 0; +} + +static int +doublebuf_blit_init (void) +{ + doublebuf_state.page_size =3D + framebuffer.bytes_per_scan_line * render_target->mode_info.height; + + doublebuf_state.offscreen_buffer =3D (grub_uint8_t *) + grub_malloc (doublebuf_state.page_size); + if (doublebuf_state.offscreen_buffer =3D=3D 0) + return 1; /* Error. */ + + framebuffer.render_target.data =3D doublebuf_state.offscreen_buffer; + doublebuf_state.update_screen =3D doublebuf_blit_update_screen; + doublebuf_state.destroy =3D doublebuf_blit_destroy; + + framebuffer.render_target.mode_info.mode_type + |=3D GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED; + return 0; +} + +static int +doublebuf_null_update_screen (void) +{ + return 0; +} + +static int +doublebuf_null_destroy (void) +{ + doublebuf_state.update_screen =3D 0; + doublebuf_state.destroy =3D 0; + return 0; +} + +static int +doublebuf_null_init (void) +{ + framebuffer.render_target.data =3D framebuffer.ptr; + doublebuf_state.update_screen =3D doublebuf_null_update_screen; + doublebuf_state.destroy =3D doublebuf_null_destroy; + + framebuffer.render_target.mode_info.mode_type + &=3D ~GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED; + return 0; +} + +/* Select the best double buffering mode available. */ +static void +double_buffering_init (void) +{ + if (doublebuf_state.destroy) + doublebuf_state.destroy(); + + if (framebuffer.is_double_buffered) + { + if (doublebuf_pageflipping_init () =3D=3D 0) + return; + + if (doublebuf_blit_init () =3D=3D 0) + return; + } + + /* Fall back to no double buffering. */ + doublebuf_null_init (); +} + static grub_err_t grub_video_vbe_get_info (struct grub_video_mode_info *mode_info) { @@ -1485,10 +1672,13 @@ return GRUB_ERR_NONE; } =20 -static grub_err_t=20 +static grub_err_t grub_video_vbe_swap_buffers (void) { - /* TODO: Implement buffer swapping. */ + if (doublebuf_state.update_screen () !=3D 0) + return grub_error (GRUB_ERR_INVALID_COMMAND, + "Double buffer update failed"); + return GRUB_ERR_NONE; } =20 @@ -1587,17 +1777,13 @@ static grub_err_t grub_video_vbe_set_active_render_target (struct grub_video_render_target *= target) { - if (target =3D=3D GRUB_VIDEO_RENDER_TARGET_FRONT_BUFFER) + if (target =3D=3D GRUB_VIDEO_RENDER_TARGET_DISPLAY) { render_target =3D &framebuffer.render_target; - + =20 return GRUB_ERR_NONE; } =20 - if (target =3D=3D GRUB_VIDEO_RENDER_TARGET_BACK_BUFFER) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,=20 - "double buffering not implemented yet."); - if (! target->data) return grub_error (GRUB_ERR_BAD_ARGUMENT,=20 "invalid render target given."); --MP_/mK7gEZ93HgBPb3+gVTalZuN-- --Sig_/B.ofmYsA5=MeWOG6Dnm4hzy Content-Type: application/pgp-signature; name=signature.asc Content-Disposition: attachment; filename=signature.asc -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.9 (GNU/Linux) iEYEARECAAYFAki6QRwACgkQokx8fzcGbYd++QCePRyvu4V/6BLG321SV8VgZ4hX W0MAnRNiMn2T3bbnOJ00sbOkTj+JwiZV =bYQs -----END PGP SIGNATURE----- --Sig_/B.ofmYsA5=MeWOG6Dnm4hzy--