图形显示原理
说实话,显示器是最难做的东西之一,因为完全是时序逻辑在控制还要顾及到和使用者的交互。而且图形的东西对面积体积时间等问题要求极其严格(现实中的显示器没必要考虑那么多,因为这些都不是瓶颈)。而图形处理器就更是天方夜谭了,有很多玩家会说要是在Minecraft 里造一台计算机可以玩Minecraft就吊炸天。这显然不可能,而且想做一个纯粹靠通用处理器运算来玩的小游戏都绝对不可能。比如贪吃蛇这种图像刷新率低的游戏,肯定做不出来。
先简单介绍一下现实中的图形处理器以及显示器是如何工作的,这对理解一些设计理念有很大帮助,也能解释为啥MC里如此难以实现标准意义上的显卡。这一部分专业术语过多,仅供做相关参考,可以直接跳过看下面本工程的图形设备的设计。
现实中的图形显示是按照“图形流水线”(graphic pipeline)来完成的。一般我们玩的3D游戏中,显卡是图像处理的设备。显卡的核心是GPU,CPU将应用程序的图像请求发送往GPU,GPU是图形处理器,作为协处理器。操作系统将所有的设备统一编址,并具有各自规范,所以每一个操作系统要调用GPU必须要有相应GPU的软件驱动程序。现在的GPU较为独立,CPU大部分时间不参与图形运算。GPU直接运行的是shader API,驱动程序指导GPU运行shader API,GPU的硬件结构将API编译成一条一条instruction。现在常用的shader API是OpenGL和Direct3D。由于图形运算是密集型并行运算,所以GPU内部有成百上千的unified shader ALU组成若干模块如nVIDIA GPU中的SM或者AMD GPU中的CU ,这些模块是程序员直接面对的对象,包含FPU,Load/Store Unit和SFU等等。还有TMU,Tessellator,rasterizer等等流水线上其他的功能单元,我们叫这些东西为:Fixed Function Unit。GPU的底层指令按照warp/wave的模式每一个指令周期都有成百上千条被发射,这些指令相关性小,一般都是顶点,像素,几何或纹理的shader指令。指令列队叫thread,每一个thread都会对应一个像素或顶点,若干shader ALU组成的vector单元同一时间用不同数据执行不同thread中相同的指令(因为front-end单元稀缺)。 每一个周期有成百上千个thread的某些指令被处理完,若干周期后所有thread都处理完,这时候一张画面就被初步执行完了,一般都是接近百万个像素点比如1280x720分辨率的显示器。之后图形流水线会将画面光栅化-rasterization,经过各种纹理,抗锯齿处理后,完整的具有正确几何信息和颜色信息的画面就处理完了。然后该幅画面就被送往帧缓存-framebuffer,这个是在显存中划出来的模块,等到合适的时机,该幅画面就传送往显示器输出,一张画面称为一帧。每秒钟一个GPU绘制出几十张这样的画面,人的肉眼就会看到流畅的画面。
GPU是典型的SIMD结构,单指令多数据的大规模并行运算。并且其运算的数据多为浮点型。GPU耗费的晶体管数量会大于CPU,需要造一大堆重复的ALU阵列和寄存器阵列。
下面贴三张GPU架构图,都是AMD(ATI)和nVIDIA这两年的GPU产品。
可以很明显的看出GPU一般重复结构较多,都是SIMD阵列加上少数dispatch和其他shading pipeline结构,所以如果在minecraft中简化到极致,比如每一个模块只造一个单元确实可以造出一个具有完整结构的显卡,但是想要做一个可以持续输出流畅画面的GPU对于minecraft来说基本是不可能,光是造一个浮点ALU就要占据几百乘以几百乘以几十的体积。假若一个屏幕按照30x30的像素来计算,并且是bitmap,只有亮暗两种色彩。就算是2D的图像程序,一共900个像素,再放宽条件要求每3秒才出一帧,那么每一秒钟也要处理300个像素,按照最简单的2D指令,假若平均一个像素只需要3条指令就能得出其是亮还是暗,那么就需要300个ALU每秒运算3次。到这里也不需要考虑其他什么图形流水线了,光是ALU团簇已经这么多,造出标准意义的显卡基本不可能。很多玩家认为在minecraft里面可以造出运行minecraft的计算机,这种宏图大业是不可能完成了。就算是常用的显示程序比如操作系统界面,也没不可能造出鼠标这种东西了,因为不可能做出点控的设备。
然后回归正题,既然造标准意义的显卡不可能,那么就退而求其次,做一些功能弱一些的显示设备,比如说只要求显示器输出部分字符,并不要求其控制每一个像素。这样可行度会大大提高。
演示视频中的计算器和字符显示器都是可以控制输出字符的显示设备。那么该如何用尽量少的电路来实现这些结构并且能够让其反应迅速呢?又如何增加显示设备与玩家的交互性呢?
前面已经介绍过minecraft中常见的图像信号组成方式:红石灯和阴影。视频里正好展示了这两种,计算器和电子表部分用的是阴影,字符显示器用的是红石灯。为什么这样选择呢,这和方块的特性也有一定关系不过这个无关紧要。先来介绍计算器的数字显示。
常接触单片机的人很容易看出我用的是七段数码显示器。七段显示器顾名思义,所有十进制数字信息都可以由七个部分组成的,3横4竖。电话机,老式收银机上的数字都是用这种方式显示的。“8”这个数字是最复杂的,它把7个段都用到了,如下图,右边的“2”显然是“8”去掉左上和右下两个段,其他所有数字都可以用少于7个段表示。
那么如何用二进制电路表示十进制数呢?编码的原则是越简单越好,显然10个十进制数字可以用10个4位二进制数表示,比如3是0011, 9是1001,这就是BCD码。计算机说到底就是一堆不同种类的码来回转换的过程。要达到数字显示到屏幕上的过程,需要如下步骤:二进制码发射到A单元上,A单元将二进制码对应的十进制数连接到各数字对应的七段信息上,比如0100是数字4,而4对应的七段信息如上图是左上,右上,中,右下四个段,最后这四个段每段3个方块的活塞抽回来,则数字4就被显示出来,这整个过程译码了两次,一次是二进制码BIN转十进制码BCD一次,然后十进制码转对应的七段信息是第二次。字符显示也一样是这种原理,具体后面具体再说。
更多相关资讯请关注:我的世界专区