对于 PC 来说,支持 24 位真彩色显示没有任何问题,但对于手机来说就不一定了。首先手机用的显示屏出于成本的考量不一定支持24 位色彩深度,可能只有18 位、16 位,早期的彩屏手机甚至只支持 4096 色;其次手机操作系统也往往不支持 16 位以上的色彩深度,比如微软的 Windows Mobile 各版本始终只能支持 16 位色以至于常遭一些用户诟病(最新的 Windows Phone 7 我不清楚是否还是这样?)。
大部分手机不能支持 24 位色真彩色显示其实也是有道理的,就象上面说的,只要设计 UI 时尽量避免使用渐变色就不会影响用户视觉体验(个人认为这是完全可以做到的,很多优秀的 UI 设计并不依靠绚丽的色彩取胜),另一方面使用较少的色彩位数有利于降低对内存和处理器性能的要求,屏也不需要支持24 位,可以大大降低成本。但技术在飞速发展,智能手机的硬件配置和运算能力已经越来越接近 PC ,用户对界面显示效果的要求也越来越高,所以手机制造商也考虑在显示上支持 24 位真彩色。
最近两年在智能手机市场火起来的 Android 的早期版本也象 Windows Mobile 一样只支持 16 位色,并不支持 24 位真彩色显示。去年5 月上市的联想的乐phone 应该是世界上第一款真正支持 24 位色显示的 Android 手机,为了实现这个特性,我们对乐phone 所使用的 Android 1.6 (Donut )进行了修改和优化。下面就以高通 QSD8250 平台为例介绍在 Donut 上实现 24 位真彩色显示的前提条件和大致方法。
1.屏必须支持24 位显示。手机用的很多屏本身只支持16 位或18 位的色彩深度,所以要想实现24 位真彩色显示,就必须选用24 位的屏。
2.将framebuffer 修改为24 位即RGB888 格式。高通Donut 代码默认的framebuffer driver 是16 位即RGB565 的,在硬件上芯片内部的显示控制器将软件输出的16 位数据转换成24 位给到屏。高通的framebuffer driver 支持24 位,只需要改一处代码即可。伴随着将framebuffer 改为24 位,必须调整系统内存分配布局,增大framebuffer (一般位于PMEM 中)的大小,同时可能还需要适当增加用于给SurfaceFlinger 分配Surface 所用的PMEM 的大小,否则可能会出现分配Surface 失败(在后面会再谈到这个问题)。
3.修改copybit HAL 部分的代码,使其支持RGB888 格式(即24 位色)的blit ,QSD8250 的MDP 本身是支持RGB888 格式的,只是原来的代码没有实现,只要修改几处即可。
4.修改EGL 与framebuffer 接口代码,即frameworks/base/libs/ui/EGLDisplaySurface.cpp ,原先的代码是按照RGB565 的framebuffer 写死的,需按照RGB888 格式修改有关参数。
5.最最关键的一步,修改frameworks/base/libs/surfaceflinger/SurfaceFlinger.cpp 中的函数SurfaceFlinger::createNormalSurfaceLocked ,将case PIXEL_FORMAT_OPAQUE: 下面的format = PIXEL_FORMAT_RGB_565; 修改为format = PIXEL_FORMAT_RGBA_8888; 这处修改是实现24 位真彩色UI 视觉效果的关键。但这样一来又引出两个问题,一是格式为PIXEL_FORMAT_OPAQUE 的Surface 分配占用的内存是原先的两倍(RGBA8888 相对于RGB565 多用一倍的内存),在某些情况下可能导致Surface 内存分配失败,可通过适当增大给Surface 分配内存预留的PMEM 大小来解决这个问题,同时也要在UI 设计上尽量避免过于复杂的界面(越复杂同时分配的Surface 越多);第二个问题是造成OpenGL ES 应用程序(主要是3D 游戏)不能正常显示,这是因为绝大多数OpenGL ES 应用程序缺省使用RGB565 显示模式,而Surface 改成了RGBA8888 就造成了两者不匹配,显示出来的画面不正常,解决的办法是在函数SurfaceFlinger::createNormalSurfaceLocked 里利用输入参数flags 区分上层调用者是OpenGL ES 应用程序还是普通应用程序,如果是OpenGL ES 应用程序则flags 里会带有标志位eGPU ,因此只要判断这个eGPU 标志位,只有在普通应用程序时才改成RGBA8888 的格式就OK 了,OpenGL ES 应用程序仍旧使用RGB565 的格式进行显示,实际上这也有利于OpenGL ES 应用程序获得较好的性能,因为RGBA8888 相对于RGB565 会导致占用更多内存和更慢的操作速度,对性能有一定影响,而这对3D 程序来说是不能忽视的。
6.修改与显示有关的其他代码。由于Android 1.6 (Donut )缺省的显示色彩位数是16 位(即RGB565 模式),很多与显示有关的代码都是按照RGB565 写死的,当framebuffer 改成24 位即RGB888 模式后与显示相关的一些代码也必须相应被修改,包括显示开机logo 画面(system/core/init/logo.c )、DDMS 中的截屏功能(system/core/adb/framebuffer_service.c )等。
7.此外还要考虑与模拟器(emulator )的兼容性,因为在调试应用程序时通常会在emulator 上进行,但emulator 仍是RGB565 的显示模式,因此要确保同一份代码跑在手机和emulator 上都可以正常显示,可在代码中通过宏等手段来实现兼容性。当然也可以把emulator 改成跟手机一致的RGB888 显示模式,需要下载goldfish (即emulator 上运行的内核)源代码进行修改,目前没有做。
经过上述修改后在Android 1.6 (Donut )上实现了24 位真彩色显示,在UI 设计中如果使用了色彩连续渐变的图就不会出现色斑,使界面色彩更加丰富炫丽,比其他Android 手机更能吸引用户的眼球。总的代码修改量并不大,不影响Android 原有的图形显示架构。
虽然24 位真彩色给UI 设计带来了好处,但因为原生的Donut 并不支持24 位色,上述修改也会带来副作用以及一些没有预见到的问题。
首先是性能问题,如前所述,24 位色下的2D 图形性能稍低于16 位色,也会占用更多内存,经分析瓶颈在2D 图形库skia ,该库是Android 图形显示系统的核心模块,其性能对UI 操作的流畅度影响很大,在Donut 中skia 并未针对硬件平台进行优化,更没有考虑对RGBA8888 色彩模式的优化。为此我们利用ARMv7 的neon 指令对skia 中涉及RGBA8888 模式的关键代码及bionic 中的memcpy 进行优化,同时对UI 动效设计进行优化,结果benchmark 得分及实际用户体验不逊于原生Donut 。
其次是某些应用程序的背景色在原生Donut 上运行时为黑色,但在修改后的24 位色系统上运行时变成透明色,原因在于使用了@android:color/transparent 或@null 作为背景色,对应为全0 的颜色值,而全0 在RGB565 模式就是黑色,但在RGBA8888 模式则是全透明(即alpha 为0 ),其实这是正常现象,不能算是系统的bug ,但为了保持与原生Donut 的一致性,修改了有关代码将上述颜色值强制为使用黑色(即@android:color/black )。
Android 升级到Eclair 之后,显示部分的架构发生了较大变化,并逐渐增强了对24 位真彩色模式的支持,同时对skia 进行了针对ARMv7 处理器的优化。在Froyo 里framebuffer 缺省已经是32 位,因此只需较少的修改就可实现24 位真彩色,但标志位eGPU 已被取消,不能在函数SurfaceFlinger::createNormalSurfaceLocked 中利用eGPU 判断是否为OpenGL ES 应用程序,只能修改SurfaceView.java 、GLSurfaceView.java 等处代码来强制OpenGL ES 应用程序使用RGB565 的surface 以便保持向下兼容性,相对来说比在Donut 上的处理要复杂些。
到了Gingerbread 更进了一步,在高通等平台上的Gingerbread 原生代码缺省已经支持完全的24 位真彩色,我们自己不需要再做任何修改,可见Google 也认为有必要在手机等移动设备上支持24 位真彩色显示。阅读代码可见Google 做的修改很多与我们在Froyo 上改的是相同的,但在函数SurfaceFlinger::createNormalSurface 中case PIXEL_FORMAT_OPAQUE: 下面的format 是采用的PIXEL_FORMAT_RGBX_8888 ,这个更合理。
原文出自:
http://blog.csdn.net/SkyGray/archive/2011/05/05/6397840.aspx
阅读(2116) | 评论(7) | 转发(1) |