Signed-off-by: Wayne Xia xiawenc@linux.vnet.ibm.com --- Makefile | 4 +- src/bmp.c | 90 +++++++++++++++++++++++++++++++++++++ src/bmp.h | 67 +++++++++++++++++++++++++++ src/bootsplash.c | 131 ++++++++++++++++++++++++++++++++++++++++++------------ 4 files changed, 262 insertions(+), 30 deletions(-) create mode 100644 src/bmp.c create mode 100644 src/bmp.h
diff --git a/Makefile b/Makefile index d17f85a..214fe80 100644 --- a/Makefile +++ b/Makefile @@ -15,12 +15,12 @@ SRCBOTH=misc.c pmm.c stacks.c output.c util.c block.c floppy.c ata.c mouse.c \ kbd.c pci.c serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \ pnpbios.c pirtable.c vgahooks.c ramdisk.c pcibios.c blockcmd.c \ usb.c usb-uhci.c usb-ohci.c usb-ehci.c usb-hid.c usb-msc.c \ - virtio-ring.c virtio-pci.c virtio-blk.c apm.c ahci.c + virtio-ring.c virtio-pci.c virtio-blk.c apm.c ahci.c bmp.c SRC16=$(SRCBOTH) system.c disk.c font.c SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \ acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \ lzmadecode.c bootsplash.c jpeg.c usb-hub.c paravirt.c dev-i440fx.c \ - pci_region.c + pci_region.c bmp.c SRC32SEG=util.c output.c pci.c pcibios.c apm.c stacks.c
cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \ diff --git a/src/bmp.c b/src/bmp.c new file mode 100644 index 0000000..9507878 --- /dev/null +++ b/src/bmp.c @@ -0,0 +1,90 @@ +/* +* Basic BMP data process and Raw picture data handle functions. +* Could be used to adjust pixel data format, get infomation, etc. +* +* Copyright (C) 2011 Wayne Xia xiawenc@cn.ibm.com +* +* This work is licensed under the terms of the GNU LGPLv3. +*/ +#include "util.h" +#include "bmp.h" + +void raw_data_format_adjust_24bpp(u8 *src, u8 *dest, int width, int height, + int bytes_per_line_src, int bytes_per_line_dest, u8 switch_flag) +{ + int cy = height; + u8 *pd, *ps, *pd_valid, *ps_lastline; + u8 t; + u8 rgb_switch_flag = switch_flag & SWITCH_RGB; + u8 line_switch_flag = switch_flag & SWITCH_LINE; + while (cy > 0) { + ps = bytes_per_line_src*cy + src - 1; + if (line_switch_flag) { + pd = bytes_per_line_dest * (height - cy + 1) + dest - 1; + } else { + pd = bytes_per_line_dest * cy + dest - 1; + } + ps_lastline = ps-bytes_per_line_src; + pd_valid = pd - (bytes_per_line_dest - bytes_per_line_src); + while (pd > pd_valid) { + *pd = 0; + pd--; + } + while (ps > ps_lastline) { + if (rgb_switch_flag) { + t = *ps; + *ps = *(ps-2); + *(ps-2) = t; + } + *(pd--) = *(ps--); + *(pd--) = *(ps--); + *(pd--) = *(ps--); + } + cy--; + } +} + +struct bmp_decdata *bmp_alloc(void) +{ + struct bmp_decdata *bmp = malloc_tmphigh(sizeof(*bmp)); + return bmp; +} + +int bmp_decode(struct bmp_decdata *bmp, unsigned char *data, int data_size) +{ + if (data_size < 54) + return 1; + + u16 bmp_filehead = bmp_load2byte(data + 0); + if (bmp_filehead != 0x4d42) + return 2; + u32 bmp_recordsize = bmp_load4byte(data + 2); + if (bmp_recordsize != data_size) + return 3; + u32 bmp_dataoffset = bmp_load4byte(data + 10); + bmp->datap = (unsigned char *)data + bmp_dataoffset; + bmp->width = bmp_load4byte(data + 18); + bmp->height = bmp_load4byte(data + 22); + bmp->bpp = bmp_load2byte(data + 28); + return 0; +} + +void bmp_get_size(struct bmp_decdata *bmp, int *width, int *height) +{ + *width = bmp->width; + *height = bmp->height; +} + + +int bmp_show(struct bmp_decdata *bmp, unsigned char *pic + , int width, int height, int depth) +{ + if (bmp->datap == pic) { + return 0; + } + if ((depth == 24) && (bmp->bpp == 24)) { + memcpy(pic, bmp->datap, width*height*24/8); + return 0; + } + return 1; +} diff --git a/src/bmp.h b/src/bmp.h new file mode 100644 index 0000000..faf5d74 --- /dev/null +++ b/src/bmp.h @@ -0,0 +1,67 @@ +#ifndef BMP_H +#define BMP_H +#include "types.h" + +#define WIDTHBYTES(bits) (((bits)+31)/32*4) + + + +typedef struct tagBITMAPFILEHEADER { +u8 bfType[2]; +u8 bfSize[4]; +u8 bfReserved1[2]; +u8 bfReserved2[2]; +u8 bfOffBits[4]; +} BITMAPFILEHEADER, tagBITMAPFILEHEADER; + +typedef struct tagBITMAPINFOHEADER { +u8 biSize[4]; +u8 biWidth[4]; +u8 biHeight[4]; +u8 biPlanes[2]; +u8 biBitCount[2]; +u8 biCompression[4]; +u8 biSizeImage[4]; +u8 biXPelsPerMeter[4]; +u8 biYPelsPerMeter[4]; +u8 biClrUsed[4]; +u8 biClrImportant[4]; +} BITMAPINFOHEADER, tagBITMAPINFOHEADER; + +typedef struct tagRGBQUAD { +u8 rgbBlue; +u8 rgbGreen; +u8 rgbRed; +u8 rgbReserved; +} RGBQUAD, tagRGBQUAD; + +struct bmp_decdata { + struct tagRGBQUAD *quadp; + unsigned char *datap; + int width; + int height; + int bpp; +}; + +#define bmp_load4byte(addr) ((addr)[0] + ((addr)[1]<<8) \ + + ((addr)[2]<<16) + ((addr)[3]<<24)) +#define bmp_load2byte(addr) ((addr)[0] + ((addr)[1]<<8)) + +#define SWITCH_RGB 0x01 +#define SWITCH_LINE 0x02 +/* src can be equal to dest, if not need to switch the lines from bottom to top, +bytes_per_line_src must be less or eqaul than bytes_per_line_dest */ +void raw_data_format_adjust_24bpp(u8 *src, u8 *dest, int width, int height, + int bytes_per_line_src, int bytes_per_line_dest, u8 switch_flag); + +/* retrieve basic infomation of bmp file +int bmp_get_info(u8 *data, int data_size, int *width_p, int *height_p, + int *bpp_p, int *offset_p); +*/ + +struct bmp_decdata *bmp_alloc(void); +int bmp_decode(struct bmp_decdata *bmp, unsigned char *data, int data_size); +void bmp_get_size(struct bmp_decdata *bmp, int *width, int *height); +int bmp_show(struct bmp_decdata *bmp, unsigned char *pic + , int width, int height, int depth); +#endif diff --git a/src/bootsplash.c b/src/bootsplash.c index cf1a603..6ac5010 100644 --- a/src/bootsplash.c +++ b/src/bootsplash.c @@ -12,7 +12,7 @@ #include "jpeg.h" // splash #include "biosvar.h" // SET_EBDA #include "paravirt.h" // romfile_find - +#include "bmp.h"
/**************************************************************** * VESA structures @@ -109,7 +109,7 @@ enable_vga_console(void)
static int find_videomode(struct vesa_info *vesa_info, struct vesa_mode_info *mode_info - , int width, int height) + , int width, int height, int bpp_req) { dprintf(3, "Finding vesa mode with dimensions %d/%d\n", width, height); u16 *videomodes = SEGOFF_TO_FLATPTR(vesa_info->video_mode_ptr); @@ -135,8 +135,15 @@ find_videomode(struct vesa_info *vesa_info, struct vesa_mode_info *mode_info || mode_info->y_resolution != height) continue; u8 depth = mode_info->bits_per_pixel; - if (depth != 16 && depth != 24 && depth != 32) - continue; + if (bpp_req == 0) { + if (depth != 16 && depth != 24 && depth != 32) { + continue; + } + } else { + if (depth != bpp_req) { + continue; + } + } return videomode; } } @@ -146,19 +153,29 @@ static int BootsplashActive; void enable_bootsplash(void) { - if (!CONFIG_BOOTSPLASH) + if (!CONFIG_BOOTSPLASH) { return; + } dprintf(3, "Checking for bootsplash\n"); + u8 type = 0; /* 0 means jpg, 1 means bmp, default is 0=jpg */ int filesize; u8 *filedata = romfile_loadfile("bootsplash.jpg", &filesize); - if (!filedata) - return; + if (!filedata) { + filedata = romfile_loadfile("bootsplash.bmp", &filesize); + if (!filedata) { + return; + } + type = 1; + } + dprintf(3, "start showing bootsplash\n");
- u8 *picture = NULL; + u8 *picture = NULL; /* data buff used to be flushded to the video buff */ + u8 *picture_post = NULL; /* another buff, used to do some post process */ + struct jpeg_decdata *jpeg = NULL; + struct bmp_decdata *bmp = NULL; struct vesa_info *vesa_info = malloc_tmplow(sizeof(*vesa_info)); struct vesa_mode_info *mode_info = malloc_tmplow(sizeof(*mode_info)); - struct jpeg_decdata *jpeg = jpeg_alloc(); - if (!jpeg || !vesa_info || !mode_info) { + if (!vesa_info || !mode_info) { warn_noalloc(); goto done; } @@ -184,20 +201,48 @@ enable_bootsplash(void) vesa_info->vesa_version>>8, vesa_info->vesa_version&0xff, vendor, product);
- // Parse jpeg and get image size. - dprintf(5, "Decoding bootsplash.jpg\n"); - int ret = jpeg_decode(jpeg, filedata); - if (ret) { - dprintf(1, "jpeg_decode failed with return code %d...\n", ret); - goto done; + int ret, width, height; + int bpp_require = 0; + u8 post_flag = 0; + if (type == 0) { + jpeg = jpeg_alloc(); + if (!jpeg) { + warn_noalloc(); + goto done; + } + /* Parse jpeg and get image size. */ + dprintf(5, "Decoding bootsplash.jpg\n"); + ret = jpeg_decode(jpeg, filedata); + if (ret) { + dprintf(1, "jpeg_decode failed with return code %d...\n", ret); + goto done; + } + jpeg_get_size(jpeg, &width, &height); + } else { + bmp = bmp_alloc(); + if (!bmp) { + warn_noalloc(); + goto done; + } + /* Parse bmp and get image size. */ + dprintf(5, "Decoding bootsplash.bmp\n"); + ret = bmp_decode(bmp, filedata, filesize); + if (ret) { + dprintf(1, "bmp_decode failed with return code %d...\n", ret); + goto done; + } + bmp_get_size(bmp, &width, &height); } - int width, height; - jpeg_get_size(jpeg, &width, &height); + bpp_require = 24;/* for better vision effect, use 24 bpp mode */
// Try to find a graphics mode with the corresponding dimensions. - int videomode = find_videomode(vesa_info, mode_info, width, height); - if (videomode < 0) + int videomode = find_videomode(vesa_info, mode_info, width, height, + bpp_require); + if (videomode < 0) { + dprintf(1, "failed to find a videomode with %dx%d %dbpp (0=any).\n", + width, height, bpp_require); goto done; + } void *framebuffer = mode_info->phys_base_ptr; int depth = mode_info->bits_per_pixel; dprintf(3, "mode: %04x\n", videomode); @@ -206,17 +251,44 @@ enable_bootsplash(void) dprintf(3, "bits per pixel: %d\n", depth);
// Allocate space for image and decompress it. - int imagesize = width * height * (depth / 8); + int imagesize = height * mode_info->bytes_per_scanline; picture = malloc_tmphigh(imagesize); if (!picture) { warn_noalloc(); goto done; } - dprintf(5, "Decompressing bootsplash.jpg\n"); - ret = jpeg_show(jpeg, picture, width, height, depth); - if (ret) { - dprintf(1, "jpeg_show failed with return code %d...\n", ret); - goto done; + + if (type == 0) { + dprintf(5, "Decompressing bootsplash.jpg\n"); + ret = jpeg_show(jpeg, picture, width, height, depth); + if (ret) { + dprintf(1, "jpeg_show failed with return code %d...\n", ret); + goto done; + } + picture_post = picture; + post_flag |= SWITCH_RGB; + if (depth == 24 && mode_info->bytes_per_scanline >= width * 24 / 8) { + raw_data_format_adjust_24bpp(picture_post, picture, width, height, + width * 24 / 8, mode_info->bytes_per_scanline, post_flag); + } + } else { + picture_post = malloc_tmphigh(imagesize); + if (!picture_post) { + warn_noalloc(); + goto done; + } + dprintf(5, "Decompressing bootsplash.bmp\n"); + ret = bmp_show(bmp, picture_post, width, height, depth); + if (ret) { + dprintf(1, "bmp_show failed with return code %d...\n", ret); + goto done; + } + post_flag |= SWITCH_LINE; + if (depth == 24 && mode_info->bytes_per_scanline >= width * 24 / 8) { + raw_data_format_adjust_24bpp(picture_post, picture, width, height, + width * 24 / 8, mode_info->bytes_per_scanline, post_flag); + } + free(picture_post); }
/* Switch to graphics mode */ @@ -231,7 +303,7 @@ enable_bootsplash(void) }
/* Show the picture */ - dprintf(5, "Showing bootsplash.jpg\n"); + dprintf(5, "Showing bootsplash picture\n"); iomemcpy(framebuffer, picture, imagesize); dprintf(5, "Bootsplash copy complete\n"); BootsplashActive = 1; @@ -241,7 +313,10 @@ done: free(picture); free(vesa_info); free(mode_info); - free(jpeg); + if (jpeg != NULL) + free(jpeg); + if (bmp != NULL) + free(bmp); return; }
On Wed, Jun 22, 2011 at 08:24:16PM +0800, Wayne Xia wrote:
Signed-off-by: Wayne Xia xiawenc@linux.vnet.ibm.com
Thanks. See my comments below.
[...]
+void raw_data_format_adjust_24bpp(u8 *src, u8 *dest, int width, int height,
int bytes_per_line_src, int bytes_per_line_dest, u8 switch_flag)
+{
It's still not clear to me what this function does. It seems like it is adjusting for extra space in the framebuffer at the end of every horizontal line. However, it's unclear why BMP would use SWITCH_LINE and JPEG would use SWITCH_RGB or why either is needed.
The purpose of jpeg_show (and bmp_show) is to decode the picture - if the picture isn't decoded properly then I think the xxx_show() function should be fixed instead of re-copying the picture to correct the decoding.
[...]
+typedef struct tagBITMAPFILEHEADER { +u8 bfType[2]; +u8 bfSize[4];
Indentation.
void enable_bootsplash(void) {
- if (!CONFIG_BOOTSPLASH)
- if (!CONFIG_BOOTSPLASH) { return;
- }
Unneeded style change.
[...]
- int width, height;
- jpeg_get_size(jpeg, &width, &height);
- bpp_require = 24;/* for better vision effect, use 24 bpp mode */
This could break existing users that use 16bit or 32bit modes.
-Kevin