diff --git a/ChangeLog b/ChangeLog index 42206a69c..20dd6860a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2012-05-26 Matthew Garrett + + * grub-core/term/efi/console.c (grub_efi_console_init): Set text mode. + (grub_efi_console_fini): Likewise. + * grub-core/video/efi_gop.c (framebuffer): New field offscreen. + (grub_video_gop_fill_mode_info): Rename to ... + (grub_video_gop_fill_real_mode_info): ... this. + (grub_video_gop_fill_mode_info): New function. + (grub_video_gop_setup): Setup double framebuffer. + (grub_video_gop_get_info_and_fini): Use original framebuffer. + Free offscreen. + (grub_video_gop_swap_buffers): Copy framebuffer. + (grub_video_gop_fini): Free offscreen buffer. + * include/grub/efi/graphics_output.h (grub_efi_gop_blt_operation_t): + New enum. + (grub_efi_gop_blt_pixel): New struct. + 2012-05-26 Vladimir Serbinenko * gentpl.py: Remove error disabling for objconv. diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c index 8fd89b093..e57a815b0 100644 --- a/grub-core/term/efi/console.c +++ b/grub-core/term/efi/console.c @@ -234,6 +234,7 @@ grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)), static grub_err_t grub_efi_console_init (struct grub_term_output *term) { + grub_efi_set_text_mode (1); grub_console_setcursor (term, 1); return 0; } @@ -242,6 +243,7 @@ static grub_err_t grub_efi_console_fini (struct grub_term_output *term) { grub_console_setcursor (term, 0); + grub_efi_set_text_mode (0); return 0; } diff --git a/grub-core/video/efi_gop.c b/grub-core/video/efi_gop.c index 73c5d08e5..3e1cc2357 100644 --- a/grub-core/video/efi_gop.c +++ b/grub-core/video/efi_gop.c @@ -49,6 +49,7 @@ static struct struct grub_video_mode_info mode_info; struct grub_video_render_target *render_target; grub_uint8_t *ptr; + grub_uint8_t *offscreen; } framebuffer; @@ -105,6 +106,8 @@ grub_video_gop_fini (void) efi_call_2 (gop->set_mode, gop, old_mode); restore_needed = 0; } + grub_free (framebuffer.offscreen); + framebuffer.offscreen = 0; return grub_video_fb_fini (); } @@ -165,9 +168,9 @@ grub_video_gop_get_bitmask (grub_uint32_t mask, unsigned int *mask_size, } static grub_err_t -grub_video_gop_fill_mode_info (unsigned mode, - struct grub_efi_gop_mode_info *in, - struct grub_video_mode_info *out) +grub_video_gop_fill_real_mode_info (unsigned mode, + struct grub_efi_gop_mode_info *in, + struct grub_video_mode_info *out) { out->mode_number = mode; out->number_of_colors = 256; @@ -223,6 +226,35 @@ grub_video_gop_fill_mode_info (unsigned mode, return GRUB_ERR_NONE; } +static grub_err_t +grub_video_gop_fill_mode_info (unsigned mode, + struct grub_efi_gop_mode_info *in, + struct grub_video_mode_info *out) +{ + out->mode_number = mode; + out->number_of_colors = 256; + out->width = in->width; + out->height = in->height; + out->mode_type = GRUB_VIDEO_MODE_TYPE_RGB; + out->bytes_per_pixel = sizeof (struct grub_efi_gop_blt_pixel); + out->bpp = out->bytes_per_pixel << 3; + out->pitch = in->width * out->bytes_per_pixel; + out->red_mask_size = 8; + out->red_field_pos = 16; + out->green_mask_size = 8; + out->green_field_pos = 8; + out->blue_mask_size = 8; + out->blue_field_pos = 0; + out->reserved_mask_size = 8; + out->reserved_field_pos = 24; + + out->blit_format = GRUB_VIDEO_BLIT_FORMAT_BGRA_8888; + out->mode_type |= (GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED + | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); + + return GRUB_ERR_NONE; +} + static int grub_video_gop_iterate (int (*hook) (const struct grub_video_mode_info *info)) { @@ -327,6 +359,7 @@ grub_video_gop_setup (unsigned int width, unsigned int height, int found = 0; unsigned long long best_volume = 0; unsigned int preferred_width = 0, preferred_height = 0; + grub_uint8_t *buffer; depth = (mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK) >> GRUB_VIDEO_MODE_TYPE_DEPTH_POS; @@ -442,13 +475,28 @@ grub_video_gop_setup (unsigned int width, unsigned int height, } framebuffer.ptr = (void *) (grub_addr_t) gop->mode->fb_base; + framebuffer.offscreen + = grub_malloc (framebuffer.mode_info.height + * framebuffer.mode_info.width + * sizeof (struct grub_efi_gop_blt_pixel)); + buffer = framebuffer.offscreen; + + if (!buffer) + { + grub_dprintf ("video", "GOP: couldn't allocate shadow\n"); + grub_errno = 0; + err = grub_video_gop_fill_mode_info (gop->mode->mode, info, + &framebuffer.mode_info); + buffer = framebuffer.ptr; + } + grub_dprintf ("video", "GOP: 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); + (&framebuffer.render_target, &framebuffer.mode_info, buffer); if (err) { @@ -478,7 +526,13 @@ grub_video_gop_setup (unsigned int width, unsigned int height, static grub_err_t grub_video_gop_swap_buffers (void) { - /* TODO: Implement buffer swapping. */ + if (framebuffer.offscreen) + { + efi_call_10 (gop->blt, gop, framebuffer.offscreen, + GRUB_EFI_BLT_BUFFER_TO_VIDEO, 0, 0, 0, 0, + framebuffer.mode_info.width, framebuffer.mode_info.height, + framebuffer.mode_info.width * 4); + } return GRUB_ERR_NONE; } @@ -495,11 +549,23 @@ static grub_err_t grub_video_gop_get_info_and_fini (struct grub_video_mode_info *mode_info, void **framebuf) { - grub_memcpy (mode_info, &(framebuffer.mode_info), sizeof (*mode_info)); + grub_err_t err; + + err = grub_video_gop_fill_real_mode_info (gop->mode->mode, gop->mode->info, + mode_info); + if (err) + { + grub_dprintf ("video", "GOP: couldn't fill mode info\n"); + return err; + } + *framebuf = (char *) framebuffer.ptr; grub_video_fb_fini (); + grub_free (framebuffer.offscreen); + framebuffer.offscreen = 0; + return GRUB_ERR_NONE; } diff --git a/include/grub/efi/graphics_output.h b/include/grub/efi/graphics_output.h index a29221919..129777411 100644 --- a/include/grub/efi/graphics_output.h +++ b/include/grub/efi/graphics_output.h @@ -32,6 +32,24 @@ typedef enum } grub_efi_gop_pixel_format_t; +typedef enum + { + GRUB_EFI_BLT_VIDEO_FILL, + GRUB_EFI_BLT_VIDEO_TO_BLT_BUFFER, + GRUB_EFI_BLT_BUFFER_TO_VIDEO, + GRUB_EFI_BLT_VIDEO_TO_VIDEO, + GRUB_EFI_BLT_OPERATION_MAX + } + grub_efi_gop_blt_operation_t; + +struct grub_efi_gop_blt_pixel +{ + grub_uint8_t blue; + grub_uint8_t green; + grub_uint8_t red; + grub_uint8_t reserved; +}; + struct grub_efi_gop_pixel_bitmask { grub_uint32_t r;