以CRT(cathode-ray tube)阴极射线管显示器为例,把计算机数据信号转换并传给CRT显示的部件叫显示适配器(video display adapter),适配器所在的线路板就是大家所熟知的显卡(video board)
二维图像显示看起来有点复杂,简单来说图像是由一束光(beam)快速连续扫过整个屏幕生成的,从屏幕左上角开始,水平扫到右边,到头另起一行重新开始,直到最右下角结束。每一条水平的线叫做扫描线,扫完整个屏幕生成一张图像,每秒生成六十张图像,这个速度足够快,不会出现一闪一闪体验不好,也就是通常所说的卡顿。为什么选择60Hz而不是其他,可以看这里,大意是CRT因为构造原理关系对磁场非常敏感,为了降低交流电磁场的影响,选择和北美交流电一样的频率。我国交流电受前苏联影响是50Hz。
早期的显示器(电视机)是黑白的,因为原理和成本相比彩色会比较简单便宜,0.5v代表黑色,2v代表白色,这两个电压之间表示灰色
接下来让我们把目光从电视机转向计算机,从计算机的角度来看,生成一张图像,最方便的办法是把图像分解为一个网格(rectangular grid),每一个格子叫做一个像素pixel (picture element)
由于早期电视显示带宽4.2MHz的限制,显示分辨率最高为320*200,横向320像素,纵向200像素,每一个像素在黑白之间切换,一共可以显示64000个像素。
现在我们想在这些格子里显示一些文本,一次性能显示多少内容呢?这个取决于每一个字符用多少个像素来实现。下图是一个8*8像素的实现
上图中显示的是常用的一些ASCII码,在内存中,占用的大小是7bit,如果要显示,对应占用的大小就是64bit,这64bit所代表的数值也可以看作是字符的一种码。按照这种定义,我们可以在320*200分辨率的屏幕上显示每行40字,一共25行的文本内容。
为了动态显示,显示适配器配备一个RAM来存要显示的内容,CPU可以访问更新数据,也包含一个字符串生成器,里面记录着ASCII码对应的像素排列格式,只读形式,字符的像素排列一旦定下里,不能随意改动(ROM)。
在八十年代,硬件成本非常昂贵,7bit字符对应64bit显示,会显得有点大,为了节约成本,进化出了另一种对应的显示方式
左边每一行是10bit,右边是8bit,每行对应,左边前7位依然是ASCII码,后三位代表第几行,从上往下数一共8行,最终的效果是
在文本输入过程中,会有一个游标紧跟其后,来提醒用户下一个字符应该出现在哪里,行和列的坐标数据存放在显示适配器上一个8bit的寄存器(register)里,CPU进行实时计算更新
在IBM1981年发售第一款PC时搭配的显示器(上图)每行显示80个字符,一共25行,每行显示80个字符是因为IBM早期的计算机使用打孔卡片,上面一次性最多显示80个
到了1987年,IBM和Apple计算机图形显示分辨率都提升为640*480 (4:3,爱迪生电影公司制定的标准),随着后面像素的提升,800 * 600,1024 * 768,1280 * 960,都是按照这个比例。
后面随着技术的发展和需求的提升,出现了图形化界面,显卡的功能从text only进化到多媒体
在早期的显卡工作过程中,cpu把数据写入显存的同时,还在画图,包括富文本的大小和字体,因此比仅显示文本的显卡拥有更多的内存,上面举例的显示分辨率有64000个像素,每个像素为1bit,显示黑与白,对应的内存就为64000bit大小,8000字节。在实际使用过程中,需要显示的图像不仅仅是非黑即白,也需要显示黑白中间的颜色,也就是灰色,每个像素就需要扩大为1字节(8bit),00h代表黑色,FFh代表白色,中间的值代表不同颜色的灰,内存扩大为64000字节(byte)。
如果需要显示彩色,我们知道任何颜色都是由三原色组成,Red,Green,Blue,RGB
每个像素三个bit,可以呈现出八种颜色,最终呈现的效果是
在现实生活中,色彩的种类更加丰富,把每个像素点上升到3字节,每个字节代表一种原色,每一种原色都有256种程度表示,组合起来一共可以显示1677,7261种颜色,这被称作full color,真彩色
在显示器成像方面,有两种成像的方式,vector和raster
显示发展到这一步,交互呼之欲出
鼠标是怎么移动的?在第一台GUI Alto计算机上,屏幕的分辨率是606*808,一共489648像素,每一个像素对应一个bit,颜色为黑白,需要64KB显存。在显存写入数据,经过计算呈现在屏幕上,移动鼠标时,底部的滚轮通过传感器输入坐标,显存根据坐标在不同的位置计算01的变化,呈现鼠标移动的效果,如果鼠标点击了按钮,对应位置的比特通过计算来响应按钮的点击事件。这种新颖的交互方式同时也催生了世界上第一款面向对象的语言–Small Talk
说到这里,顺便提一下bitmap,屏幕上像素显示的图像如果想存起来,最简单的方法就是对应的矩阵像素点在内存中对应存起来,这种数据类型存起来以后就是bitmap
存起来以后发现文件很大,并且很多数据是重复的,比如图中有一大片蓝天和白云
我们可以存储1000这个数字和一个蓝点来表示蓝色像素有一千个,更加节省bit,这就是压缩算法的基本思想,为了节省空间。有的压缩算法会导致数据有损,但损失可接受,不影响图片效果,比如最常见的JPEG(Joint Photography Experts Group)
OCR
前面讲过,ASCII码转为像素形式显示,显卡内部的ROM有一一对应关系,如果逆向过来,已知一个像素排列阵型(pixel pattern),如何确定对应的ASCII码呢?通常来说有些困难,因为通常得到的bitmap不一定和ROM预先存储的一样,需要一些软件算法来尽量还原,这就是OCR(optical character recognition)。简单阐述大致原理是根据每一种特定的排列通过特定的算法生成一列哈希值,然后去和已知图像的哈希值对比,最接近的便是首选答案。
衍生问题:显示卡顿优化
一秒播放六十张图片,低于这个频率视觉上会有卡顿,每16.7毫秒需要生成一张图片,图片生成需要CPU计算生成bitmap,交给GPU渲染,然后放到frame缓冲区等待显示到屏幕上
CPU方面:减少计算量
- 视图轻量级(减少点)
- 视图布局简单(减少点)
- 减少修改属性
- 合理使用线程,避免线程卡顿
- 富文本处理合理
- 图片解码合理
GPU方面:减少渲染量
视图层级简单(减少点)
渲染图片少(减少点)
渲染图片小(减少点)
合理使用透明度
避免离屏渲染(阴影,圆角,遮罩)(减少点)
完。
PS:如果文中某些图片加载失败,请参考这里设置host文件
参考链接:
https://en.wikipedia.org/wiki/Code:_The_Hidden_Language_of_Computer_Hardware_and_Software
https://blog.infolink.com.tw/2021/rediscover-pixel-dpi-ppi-and-pixel-density/