在Init进程中(system/core/init),有一个功能,显示一个开机画面,在system/core/init/init.c中console_init_action()函数中。
#if !defined(BOOT_ANIMATION)
if( load_565rle_image(INIT_IMAGE_FILE) ){
fd = open("/dev/tty0", O_WRONLY);
if (fd >= 0) {
const char *msg;
msg = "\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n" // console is 40cols x 30 lines
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
" A N D R O I D";
write(fd, msg, strlen(msg));
close(fd);
}
}
#endif
load_565rle_image()支持RGB888的LCD
简单来讲就是Load一个RLE-565格式的文件,然后拷贝到Framebuffer中显示。load_565rle_image()在同logo.c中实现。看了一下当前的实现,比较老,居然不支持RGB888格式的LCD,如果是RGB888的LCD,在Framebuffer中是24bpp的,但按照16bpp送到Framebuffer的话,会显示成四个只有四分之一大小的LOGO。
为了支持RGB888正常显示,需要修改一下,当LCD为24bpp时,把每个像素的值扩展成32bit( 还有8bit为Alpha通道)。修改文件system/core/init/logo.c
--- a/system/core/init/logo.c
+++ b/system/core/init/logo.c
@@ -38,6 +38,15 @@ static void android_memset16(void *_ptr, unsignedshort val, unsigned count)
while(count--)
*ptr++ = val;
}
+
+typedef unsigned intuint32_t;
+static voidandroid_memset32(uint32_t* dst, uint32_t value, size_t size)
+{
+ size >>= 2;
+ while (size--) {
+ *dst++ = value;
+ }
+}
#endif
struct FB {
@@ -50,7 +59,9 @@ struct FB {
#define fb_width(fb) ((fb)->vi.xres)
#define fb_height(fb) ((fb)->vi.yres)
-#define fb_size(fb)((fb)->vi.xres * (fb)->vi.yres * 2)
+#define fb_bpp(fb)((fb)->vi.bits_per_pixel)
+#define fb_size(fb)((fb)->vi.xres * (fb)->vi.yres * \
+ ((fb)->vi.bits_per_pixel/8))
static int fb_open(struct FB *fb)
{
@@ -108,6 +119,7 @@ intload_565rle_image(char *fn)
struct FB fb;
struct stat s;
unsigned short *data, *bits, *ptr;
+ uint32_t rgb32, red, green, blue, alpha;
unsigned count, max;
int fd;
@@ -139,8 +151,24 @@ intload_565rle_image(char *fn)
unsigned n = ptr[0];
if (n > max)
break;
- android_memset16(bits, ptr[1], n<< 1);
- bits += n;
+ if (fb_bpp(&fb) == 16) {
+ android_memset16(bits, ptr[1], n<< 1);
+ bits += n;
+ }else {
+ /* convert 16 bits to 32 bits */
+ red = ((ptr[1] >> 11) &0x1F);
+ red = (red << 3) | (red>> 2);
+ green = ((ptr[1] >> 5) &0x3F);
+ green = (green << 2) | (green>> 4);
+ blue = ((ptr[1]) & 0x1F);
+ blue = (blue << 3) | (blue>> 2);
+ alpha = 0xff;
+ rgb32 = (alpha << 24) | (red<< 16)
+ | (green << 8) |(blue << 0);
+ android_memset32((uint32_t *)bits,rgb32, n << 2);
+ bits += (n * 2);
+ }
+
max -= n;
ptr += 2;
count -= 4;
这样就可以在RGB888的LCD上正常显示Logo了,但这只要把RGB565的图扩展成RGB888显示,并不是真正的RGB888的图。如果图形中有一些过渡色的话,就会比较容易出现色阶现象。
增加load_888rle_image()函数
为了能够真正支持24bpp的图,需要实现加载24bppRLE格式图像的功能,RLE属于游程编码,格式是颜色值+连续点数。自己扩展一下RLE-565的格式,把它变成RLE-888的格式。实现的函数如下:
+intload_888rle_image(char *fn)
+{
+ struct FB fb;
+ struct stat s;
+ int fd, count, err = 0;
+ unsigned max;
+ uint32_t rgb32, red, green, blue, alpha;
+ unsigned short *data, *ptr, *bits, rgb16;
+
+ NOTICE("%s: load_888rle_imagefilename: %s\n",
+ __func__, fn);
+
+ if (vt_set_mode(1))
+ return -1;
+
+ fd = open(fn, O_RDONLY);
+ if (fd < 0) {
+ ERROR("cannot open '%s'\n",fn);
+ goto fail_restore_text;
+ }
+
+ if (fstat(fd, &s) < 0) {
+ goto fail_close_file;
+ }
+
+ data = mmap(0, s.st_size, PROT_READ,MAP_SHARED, fd, 0);
+ if (data == MAP_FAILED)
+ goto fail_close_file;
+
+ if (fb_open(&fb))
+ goto fail_unmap_data;
+
+ max = fb_width(&fb) *fb_height(&fb);
+ ptr = data;
+ count = s.st_size;
+ bits = fb.bits;
+ NOTICE("load_888rle_image %d x %d @%d\n",
+ fb_width(&fb),fb_height(&fb),fb_bpp(&fb));
+
+ while (count > 7) {
+ unsigned n = ptr[0];
+ if (n > max)
+ break;
+ red = blue = (ptr[1] & 0xFF);
+ green = ((ptr[1] >> 8) &0xFF);
+ red = ((ptr[3] >> 8) & 0xFF);
+ if (fb_bpp(&fb) == 16) {
+ /* convert 32 bits to 16 bits */
+ rgb16 = ((((red) >> 3)<< 11) | (((green) >> 2) << 5) | ((blue) >> 3));
+ android_memset16(bits, rgb16, n<< 1);
+ bits += n;
+ } else {
+ alpha = 0x0;
+ rgb32 = (alpha << 24) | (red<< 16) | (green << 8) | (blue << 0);
+ android_memset32((uint32_t *)bits,rgb32, n << 2);
+ bits += (n * 2);
+ }
+
+ max -= n;
+ ptr += 4;
+ count -= 8;
+ }
+ munmap(data, s.st_size);
+ fb_update(&fb);
+ fb_close(&fb);
+ close(fd);
+ unlink(fn);
+ return 0;
+
+fail_unmap_data:
+ munmap(data, s.st_size);
+fail_close_file:
+ close(fd);
+fail_restore_text:
+ vt_set_mode(0);
+ return -1;
+}
rgb2888的小工具
当然还需要实现rgb2888的小工具来转换原始图像为RLE-888格式。参考to565的实现,自己写一个to888。to565位于build/tools/rgb2565下。
转换函数实现示例如下
void to_888_rle(int maxcount)
{
unsigned char in[3], c1[3];
unsigned short last, color, count;
unsignedtotal = 0;
int subtotal = 0;
count = 0;
while(read(0, in, 3) == 3) {
subtotal ++;
if ( (maxcount != -1) && (subtotal > maxcount ) )
break;
color = to565(in[0],in[1],in[2]);
if (count) {
if(((in[0]==in[2])||(color==0xffff)||(!color)) && (color == last)&& (count != 65535)) {
count++;
continue;
} else {
write(1, &count, 2);
write(1, &c1[0], 1);
write(1, &c1[1], 1);
write(1, &count, 2);
write(1, &c1[2], 1);
write(1, &c1[2], 1);
total += count;
}
}
last = color;
memcpy(c1,in,3);
count = 1;
}
if (count) {
write(1, &count, 2);
write(1, &c1[0], 1);
write(1, &c1[1], 1);
write(1, &count, 2);
write(1, &c1[2], 1);
write(1, &c1[2], 1);
total += count;
}
fprintf(stderr,"%d pixels\n",total);
}
编译生成小工具Makefile
include$(CLEAR_VARS)
LOCAL_SRC_FILES:= to888.c
LOCAL_CFLAGS +=-O2 -Wall -Wno-unused-parameter
LOCAL_MODULE :=rgb2888
include$(BUILD_HOST_EXECUTABLE)
用法和rgb2565相同,示例如下:
convert-depth 8 foo.png rgb:foo.raw
rgb2888 -rle < foo.raw > foo.rle