首先介绍有关色彩深度的知识。

计算机显示器上同时能显示的颜色数量是由色彩深度(Color Depth)决定的,例如色彩深度若为16则同时能显示2的16次方即65536种颜色,色彩深度若为24则同时能显示2的24次方即16777216种颜色。在显卡驱动设置里通常把16位色模式称为“增强色”,24位色模式称为“真彩色”。至于显卡支持的 32位色模式,只是为了更好地处理色彩,实际上液晶面板能支持的色彩深度通常还是24位,也就是红绿蓝各8位。

正常人眼可分辨的颜色种类可达几十万种以上,而用测色器则可以分辨出一百万种以上的颜色。所以一般来说24位色(即真彩色)已经能很好地表现人眼所能看到的自然界真实的色彩,比如数码相机拍摄的照片一般就是以24位色模式保存的。

一台显示器实际能显示的最大色彩深度由硬件和软件两方面决定。硬件方面,CRT显示器的R、G、B由模拟信号控制,理论上能显示的色彩种类是无穷多的,液晶显示器则取决于液晶面板和驱动电路对色彩的处理能力,以及显卡支持的色彩深度。目前计算机用的液晶显示器至少都可以支持24位色显示,显卡也没有任何问题。软件方面,则要看显卡驱动程序和操作系统是否能支持24位色显示,目前的主流 PC操作系统如 Windows 系列、Linux 也都没问题。

实际上通常情况下人眼也不易分辨出16位色与24位色的差异,若将计算机显卡设为16位色模式观看数码相机拍的照片,通常看不出来与在真彩色模式下有什么差别。

但如果在屏幕上显示色彩连续渐变的图形,不同的色彩深度就会看到明显的差异。如下图所示(此图片引用自http://www.hi-pda.com/forum/viewthread.php?tid=501100),最左边的图片是原始图,颜色从橙色到红色过渡很平滑,中间和右边的图是在16位色的系统上显示的效果,色彩渐变的过渡带出现了明显的色斑。

一般来说,象这种由于色彩连续渐变导致出现色斑的情形在数码相机拍摄的自然界景物的照片中并不多见,所以数码照片无论是在16位色还是在真彩色模式下看起来的效果其实差别不大;但在人工设计的图片中则比较常见这种情形,比如在手机产品开发中,有些UI设计师喜欢用绚丽多变的色彩来吸引用户的眼球,包括大量使用渐变色,他们设计的 UI图片如果在 16位色的手机上显示就会出现上述的色斑,严重影响了视觉效果,为了解决这种问题,要么修改UI设计,尽量避免使用渐变色,要么就只能修改软硬件实现真正的24位真彩色显示。

对于 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了,OpenGLES应用程序仍旧使用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中casePIXEL_FORMAT_OPAQUE:下面的format是采用的PIXEL_FORMAT_RGBX_8888,这个更合理。

(完)

Android的显示色彩位数相关推荐

  1. android sdcard 不存在,在android中显示sdcard上不存在的文件的提醒

    以下代码可正常运行,并播放sd卡上的音乐文件. 我想在sdcard上不存在音乐文件("不存在的音乐文件")时显示警报. 我该写些什么?在android中显示sdcard上不存在的文 ...

  2. [Android]只显示月和日的DatePickerDialog

    一.效果图 1.1 默认 1.2 处理后 二.实现代码 2.1 代码片段1     /**      * 从当前Dialog中查找DatePicker子控件      *       * @param ...

  3. 【Android】显示Emoji表情字符

    一.下载AndroidEmoji.ttf字体 地址1:Github Android Platform 地址2:AndroidEmoji.ttf.zip 二.使用 2.1 将字体拷贝到assets/fo ...

  4. android 电量控件,Android实现显示电量的控件代码

    下面介绍了Android实现显示电量的控件代码,具体代码如下: 1.目录结构,本人是使用安卓死丢丢. 2.运行界面,输入框中输入数值,点击刷新,会再电池中显示出相应的电量 3.绘制自定义电池控件,首先 ...

  5. Android 滑动显示下一层界面

    Android 滑动显示下一层界面 主要activity: public class UpPage extends Activity { private Button upButton; privat ...

  6. android Word 显示文档结构图

    今天,简单讲讲android里浏览Word文档时,如何显示文档的文档结构图. 这个其实也很简单,之前我把自己用WPS写成的文档发送给领导查看,他用的是Word查看的文档,所以没有显示我在WPS上设置的 ...

  7. Android 不显示标题栏和全屏的设置方法

    Android 不显示标题栏和全屏的设置方法 1.在Manifest.xml中设置 不显示标题栏 android:theme="@android:style/Theme.NoTitleBar ...

  8. Android OpenGL显示任意3D模型文件

    转载请注明出处:[huachao1001的专栏:http://blog.csdn.net/huachao1001] *本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 前面两篇文章我 ...

  9. 如何旋转Android模拟器显示? [重复]

    本文翻译自:How do I rotate the Android emulator display? [duplicate] This question already has an answer ...

最新文章

  1. 蓝桥哈夫曼树C语言,实验四 哈夫曼树及哈夫曼编码
  2. angularjs中$http模块发送post请求request payload转form data
  3. 如何调试Android Framework?
  4. 2018 年,我们该如何使用 JavaScript?
  5. Java扑克牌(洗牌Collections.shuffle)
  6. GET和POST两种基本请求方法的区别(转载)
  7. 《编译原理》实验教学大纲
  8. SQL Server 2008故障转移集群+数据库镜像配置实例之三
  9. cisco ios命令
  10. iQOO Neo6现身安兔兔数据库:高导热稀土散热加入 跑分轻松破百万
  11. postman下载使用教程
  12. AJAX视频教程下载
  13. iOS8过渡到iOS9,Xcode6过渡到Xcode7
  14. 《高效人士的七个习惯》读后感-总结
  15. STM32驱动步进电机;步进电机的驱动;步进电机驱动板的使用;STM32输出不同频率的波形;
  16. Html给网页加icon图标
  17. 计算机程序运算逻辑图,算术逻辑运算单元(ALU).ppt
  18. VMware虚拟机拷贝mac冲突解决方法(及软件安装)
  19. 這些食物絕對不能放隔夜(圖)
  20. Springboot使用s7connector 实现对西门子PLC数据读写

热门文章

  1. 【大厂面试】堆的内存结构及GC垃圾回收机制
  2. 推荐收藏系列:一文理解JVM虚拟机(内存、垃圾回收、性能优化)解决面试中遇到问题(图解版)
  3. mysql connect by prior start with_start with connect by prior 递归查询用法
  4. 汉字区位码位研究之生成指定数目的汉字
  5. 梅梅之最新设计——改了又改!!~~
  6. 移动电影院2.0发布及垂直社交等功能体验
  7. Fiddler抓包及_Fiddler过滤
  8. 程序员圈 内的 鄙视链
  9. springboot+websocket+token验证+jedis支持集群部署发消息
  10. PB处理BLOB类型的方法