《红楼梦》里有一回的题目叫《葫芦僧乱判葫芦案》,讲的是新官上任的贾雨村怕得罪人而胡乱判案的故事。
对于软件问题来说,也有不同的解法。比如著名的“三重法”:重跑,重装,重启。
除了三重法,还有枚举法,也称排除法,就是做各种排列组合,把系统里的各个部件做替换,换了一样不行再换另一样,直到把问题解决。
用这些方法时,不在乎是否找到真凶,只在乎是否把事情摆平,就像贾雨村那样。
我一向不喜欢这样的方法,但是也有例外的时候,比如今天就用了一次。因为很少使用,所以特别记录下来。
问题发生在u-boot中,症状是显示的启动徽标(logo)不好看。背景是对u-boot代码做了一些修改,改变了读取logo位图的方法。以前是读文件,现在改为使用C数组(C Array)。
到底如何不好看呢?起初是很小不好看,后来是大了,但是中间有一条“雪花带”。
我第一次看到这个现象时,以为是个简单问题,是绘制的代码里有小bug,一上调试器就手到擒来了。
但是看了代码后,才知道不是这么回事。
在u-boot阶段,没有操作系统,没有什么可以依赖的基础设施,所有东西都是自己控制,依靠“自己”的代码。因此,对于显示logo这件事,根本不是像OS阶段那样解码出位图阵列,然后调用DrawBitmap或者PutPixel那样的函数。
没有OS可以依靠,没有现成的API可以调用,那u-boot靠谁来显示位图呢?
答案是靠硬件。长话短说就是初始化硬件的帧缓冲区(Frame Buffer),然后把一堆像素直接memcpy过去。
其实这种手段在Linux下也经常用,还有个简单的名字,“直接写FB”。
直接写FB太暴力了,也没有“协作”意识,多个软件一起写的话,屏幕就成涂鸦了。因为此,今天在Linux下比较少用了。
看了是直接写FB后,我意识到这个问题不能继续用调试器了,因为一团数据写到FB后,后面就交给硬件了。
哪里来的雪花带呢?<此处故意省略200字>
前路不通,只好绕行了。
多年前读书时,曾经写代码解析BMP文件。读u-boot中解析bmp头的代码,一些模糊的记忆又慢慢清晰起来。
深究起来,BMP格式也有很多说道,比如是否用调色板,是否压缩,到底用多少比特表达一个像素等。这些信息都体现在BMP文件的头上,也就是下面这个结构体:
struct __packed bmp_header {
/* Header */
char signature[2];
__u32 file_size;
__u32 reserved;
__u32 data_offset;
/* InfoHeader */
__u32 size;
__u32 width;
__u32 height;
__u16 planes;
__u16 bit_count;
__u32 compression;
__u32 image_size;
__u32 x_pixels_per_m;
__u32 y_pixels_per_m;
__u32 colors_used;
__u32 colors_important;
/* ColorTable */
};
我让小伙伴尝试不同的文件格式。试了几种都不能让硬件满意。
盲猜太费时间了。结合上面的结构体定义,我仔细看能够正常显示的位图数据。出乎我预料的是,能正常显示的几张位图(显示充电状态的)居然是8比特表示一个像素(所谓的8bpp),也就是256色。而且居然还是压缩的。
于是我也让小伙伴试验8比特的格式,但是手头的几个工具居然都不支持8位了,包括非常著名的绘图软件。
在今天这样的后多媒体时代里,256色的确太老了。
没有现成的工具,我想到了找源代码,github上找到了个项目BitmapLib,编译很顺利,运行默认的示例图片也可以,但是只能产生8bpp的新图片,不能转换老的文件。还试了一个国内同学的代码,能转换出8bpp的文件,但是所有看图软件都不能显示。
一筹莫展之时,突然想到了一个主意,找到使用多年的Windows XP虚拟机镜像——winxpsp3.ova,让小伙伴下载VirtualBox,导入,然后用里面的经典画笔程序打开要转换的logo文件,另存为256色位图文件。再转化为C Array,再编译刷新。
虽然步骤看起来挺多,但是只用了几分钟,小伙伴就报告好消息,“这下可以了!”
底层的软件开发有太多坑,有太多难缠的细节,讲这个故事也是让做上层开发的同行感觉到“幸福”。在操作系统上面写代码还是好写多了,效率也高。
(写文章很辛苦,恳请各位读者点击“在看”,也欢迎转发)
*************************************************
正心诚意,格物致知,以人文情怀审视软件,以软件技术改变人生
扫描下方二维码或者在微信中搜索“盛格塾”小程序,可以阅读更多文章和有声读物
也欢迎关注格友公众号