走进图形的世界
提起图形处理和显卡相关的内容,尤其是玩电脑游戏的时候(通常是安装时)很多人是不是很容易就想起了一个熟悉的名词叫做Direct X,通常什么Direct 9.0c之类的东西都是打游戏必备的。那么大家知道DirectX是什么吗?另外你知道一个类似名词OpenGL是什么吗?本文将对他们进行简要的介绍和对比,希望对大家了解和显卡密切相关的Direct X和OpenGL。
Direct X是什么
Direct X是Direct eXtension的简写,可以进一步简写成DX。为微软公司开发的多媒体编程接口,目前只支持Windows平台,虽然Linux等平台依靠wine等程序也能实现DirectX但是性能相当可怜。
Direct X发展到现在已经有11代产品了,目前最常用的有两个Direct X 11.1和Direct 9.0c。前者是Windows7/8的标准配置,后者是WindowsXP的标准。对于很多新游戏而言都以Direct X 11为接口。Direct X有很多API接口, 可以分为以下几个部分:
Direct Draw和Driect 3D为主的显示部分。其中Direct Draw是负责平面显示的,而Direct 3D是负责3D运算的。通常而言大型3D游戏运用的就是Direct 3D部分(当然,如果采用Direct X作渲染的话)。
以DirectSound为主的声音部分
以DirectInput为主的输入设备,键盘鼠标遥感等游戏控制设备的输入就在这里完成
以DirectPlay为主的网络波分,方便网络游戏等操作……
Direct X借助Windows的顺风车已经占领了相当大的 市场,但是仅仅支持Windows系统这个弊端就促使其他操作系统进行自己的多媒体编程计划,目前最强大的就是OpenGL。
OpenGL是什么
OpenGL是由开源社区提供的免费开源的多媒体编程接口,全称是Open Graphics Library。OpenGL功能非常强大,但是使用起来也是相当的复杂, 开源社区为任何操作系统提供OpenGL支持,所以适用范围也是相当的广。很多游戏开发采用OpenGL作为渲染方式,这样可以方便的向Linux和OS X等平台移植。
而且另一个超级编程语言java也已经完成了和OpenGL的整合,意味着使用java 3D编写的3D程序等可以实现OpenGL整合。当然是用java 3D也可以调用Direct X来进行加速。
在非Windows平台下,目前仅能使用OpenGL进行加速,而在Windows平台下视频功能可以由DirectX或者OpenGL完成。由于开发商的选择不同,通常的硬件都是支持者两种加速方式的。客观的来说在超高端硬件上对OpenGL的支持更好。
在Windows平台下,常规硬件(非服务器级别的)下,Direct X对3D的渲染性能要比OpenGL略微好点,尤其是在Windows7/8上。但是在Linux平台下OpenGL的渲染要比在Windows下对OpenGL的渲染强。
总的来说,Windows下Direct X性能比较好,不过Open GL也不差。但是同样是OpenGL在Linux,OS X下比Windows下渲染效果要好。
异同点 对 比
Direct x
opengl
概念是由微软公司创建的多媒体编程接口由开源社区(ARB->06Khronos Group)提供的免费开源的多媒体编程接口语言c,c++c,c++作用电子游戏开发。DirectX亦被用於開發許多虛擬三維圖形相關軟體渲染2D、3D矢量圖形CAD、虛擬實境、科學視覺化程式和電子遊戲開發。平台Microsoft Windows、Microsoft XBOX、Microsoft XBOX 360和Microsoft XBOX ONEwindows,linux,Linux,mac,android,ios,web游戏市场pc和xbox市场基本占有手机游戏硬件支持良好不太好OpenGL ES
对 比
Direct x
opengl
OpenGL ES(OpenGL for Embedded Systems)是 OpenGL 三维图形API的子集,针对手机、PDA和游戏主机等嵌入式设备而设计,OpenGLES是从OpenGL裁剪定制而来的,去除了glBegin/glEnd,四边形(GL_QUADS)、多边形(GL_POLYGONS)等复杂图元等许多非绝对必要的特性。经过多年发展,现在主要有两个版本,OpenGL ES 1.x针对固定管线硬件的,OpenGLES2.x针对可编程管线硬件。目前从Android4.3以上版本开始支持ESIOS从IOS7以上版本开始支持ES 3.0
版本对比 版本
特点
1x针对固定管线硬件(固定管道),通过它内建的功能来设置诸如灯光,顶点(图形的顶点数),颜色,相机等等的东西。2x针对可编程管线硬件(可编程管道),需要自己动手编写任何功能。与此同时,2.0相比于1.0更具灵活性,功能也更强大.可以自定义顶点和像素计算,可以让表现方式更加准确3xOpenGL ES3.0扩展了OpenGL ES2.0,支持许多新的渲染技术,优化和显示质量改进,包括 - 引入了许多和纹理相关的新功能,对着色语言进行了重大更新和支持着色器新功能的API特性,引入了多种与几何形状规范和图元渲染控制相关的新功能,引入了新的缓冲区对象,增添了许多与屏幕外渲染到帧缓冲区对象相关的新功能,OpenGL ES 3.0向后兼容OpenGL ES 2.0,但由于3.0 / 2.0不支持1.x支持的固定功能管线,3.0 / 2.0不能向后兼容1.x.帧率以及刷新卡顿的概念
版本
特点
概念
一帧就是一副静止的画面,连续的帧就形成动画,如电影等。我们通常所说的帧数就是在秒钟时间里传输的图片的帧数,通常用fpsframes Per Second)表示。每一帧都是静止的图像,快速连续地显示帧便形成了运动的假象,还原了物体当时的状态。高帧率可以得到更流畅、更逼真的动画。每秒钟帧数(fps)愈多,所显示的动作就会愈流畅。一般来说,图像帧率设置为25fps30fps已经足够。
错误
手机等单子设备达到每秒60帧就不卡否则就会卡。这个说法是不太准确的。应当说在快速刷新的情况下能达到60帧左右的就不会感觉到很卡。静止状态下的化不需如此高的帧数.很多游戏都在30帧左右也不会卡一般来说,战略类(比如XCOM未知敌人,植物大战僵尸),速度不快的平台类(比如时空幻境),速度不快第三人称(比如寂静岭),文字冒险(<--废话)都是可以在30帧下保持流畅的。游戏中的快速动作场景多很多, 电影中的奔跑, 赛车追逐等快速动作场景很多都出现在高潮部分, 而quake, CS, Halo这样快速的第一人称射击游戏全场都是快速动作这种类型的就需要高fps,射击游戏对操作响应速度的要求非常高,一旦帧数低了操作也会反应不过来,RPG游戏对操作反应速度要求明显低多了,像回合制的压根就无所谓了,喝杯茶再来操作都行,射击游戏里的生死都在毫秒间,帧数一低随时挂掉,像Quake3中某个跳跃动作甚至还要求帧数必须在125帧以上才能完成。
游戏和电影的不同
虽然电影每秒仅24帧也不如60帧的流畅,但是不会让人觉得卡,而每秒24帧的游戏能让人很明显的感受到卡,甚至没法正常玩,为什么?
1.首先,还是不得不提视觉暂留这个概念。我们知道,我们之所以看到的电影画面、游戏画面是连续的,就是因为我们眼睛视网膜上成的像不会立即消去,因此间断的图像会让我们看起来像连续的影像。
16 视觉暂留(英文:Persistence of vision)是光对视网膜所产生的视觉,在光停止作用后,仍保留一段时间的现象,其具体应用是电影的拍摄和放映。原因是由视神经的反应速度造成的,其时值约是1/16秒,对于不同频率的光有不同的暂留时间。是动画、电影等视觉媒体形成和传播的根据。比如:直视太阳数秒后,人眼将残留一个强光源的影像。我们日常使用的日光灯每秒大约熄灭100余次,但我们基本感觉不到日光灯的闪动。这都是因为视觉暂留的作用。所以,要达成最基本的视觉暂留效果至少需要10fps(参考视频的帧率)。
这里似乎有些奇怪的地方,因为其中提到 10fps 就可以达成基本的条件,而视神经的反映速度时值约是1/16秒。意思是,10 fps 很流畅,16 fps 以上人眼感受不出区别。不对啊,这个 fps 我还在看幻灯片呢。因此,我不得不得出这个结论:人主观觉得画面是否流畅,帧率只是因素之一。
第二个原因就是电影的帧数是稳定的,而游戏则是不稳定的。
Android 的图像显示原理
Android设备的显示屏被抽象为一个帧缓冲区,而Android系统中的SurfaceFlinger服务就是通过向这个帧缓冲区写入内容来绘制应用程序的用户界面的。Android系统在硬件抽象层中提供了一个Gralloc模块,封装了对帧缓冲区的所有访问操作。
Linux内核在启动的过程中会创建一个类别和名称分别为“graphics”和“fb0”的设备,用来描述系统中的第一个帧缓冲区,即第一个显示屏,其中,数字0表示从设备号。注意,系统中至少要存在一个显示屏,因此,名称为“fb0”的设备是肯定会存在的,否则的话,就是出错了。
init进程在启动的过程中,会启动另外一个进程ueventd来管理系统的设备文件。当ueventd进程启动起来之后,会通过netlink接口来Linux内核通信,以便可以获得内核中的硬件设备变化通知。而当ueventd进程发现内核中创建了一个类型和名称分别为“graphics”和“fb0”的设备的时候,就会这个设备创建一个/dev/graphics/fb0设备文件。这样,用户空间的应用程序就可以通过设备文件/dev/graphics/fb0来访问内核中的帧缓冲区,即在设备的显示屏中绘制指定的画面。注意,用户空间的应用程序一般是通过内存映射的方式来访问设备文件/dev/graphics/fb0的。
Android系统在硬件抽象层中提供了一个Gralloc模块,封装了对帧缓冲区的所有访问操作。用户空间的应用程序在使用帧缓冲区之间,首先要加载Gralloc模块,并且获得一个gralloc设备和一个fb设备。有了gralloc设备之后,用户空间中的应用程序就可以申请分配一块图形缓冲区,并且将这块图形缓冲区映射到应用程序的地址空间来,以便可以向里面写入要绘制的画面的内容。最后,用户空间中的应用程序就通过fb设备来将已经准备好了的图形缓冲区渲染到帧缓冲区中去,即将图形缓冲区的内容绘制到显示屏中去。相应地,当用户空间中的应用程序不再需要使用一块图形缓冲区的时候,就可以通过gralloc设备来释放它,并且将它从地址空间中解除映射。
Android框架中提供SurfaceFlinger服务负责绘制应用程序的UI,管理Android系统的帧缓冲区(frame Buffer)
Android应用程序与SurfaceFlinger服务的关系
surfaceFlinger服务运行在Android系统的System进程中,它负责管理Android系统的帧缓冲区(frame Buffer)Android应用程序为了能够将自己的UI绘制在系统的帧缓冲区上,它们就必须要与SurfaceFlinger服务进行通信。
Android应用程序与SurfaceFlinger服务的关系
Android应用程序与SurfaceFlinger服务是运行在不同的进程中的,通过binder对象连接,Android应用程序在通知SurfaceFlinger服务来绘制自己的UI的时候,需要将UI元数据传递给SurfaceFlinger服务,例如,要绘制UI的区域、位置等信息。一个Android应用程序可能会有很多个窗口,而每一个窗口都有自己的UI元数据。通过Android系统的匿名共享内存机制(Anonymous Shared Memory)传递数据。
Android应用程序与SurfaceFlinger,共享内存的关系Android将这段共享内存叫做sharedClient
sharedClient结构在每一个SharedClient里面,有至多31个SharedBufferStack。每一个SharedBufferStack就是用来描述一系列需要按照一定规则来访问的描述UI元数据的缓冲区。一般我们就绘制UI的时候,都会采用一种称为“双缓冲”的技术。双缓冲意味着要使用两个缓冲区,其中一个称为Front Buffer,另外一个称为Back Buffer。UI总是先在Back Buffer中绘制,然后再和Front Buffer交换,渲染到显示设备中。SurfaceFlinger服务只不过是将传统的“双缓冲”技术升华和抽象为了一个SharedBufferStack。有了SharedBufferStack之后,SurfaceFlinger服务就可以使用N个缓冲区技术来绘制UI了。N值的取值范围为2到16,在SurfaceFlinger服务中,每一个SharedBufferStack都对应一个Surface,即一个窗口。
sharedBufferStatic结构
前面我们说过,SharedBufferStack中的缓冲区只是用来描述UI元数据的,这意味着它们不包含真正的UI数据。真正的UI数据保存在GraphicBuffer中,后面我们再描述GaphicBuffer。因此,为了完整地描述一个UI,SharedBufferStack中的每一个已经使用了的缓冲区都对应有一个GraphicBuffer,用来描述真正的UI数据。当SurfaceFlinger服务缓制Buffer-1和Buffer-2的时候,就会找到与它们所对应的GraphicBuffer,这样就可以将对应的UI绘制出来了。
当Android应用程序需要更新一个Surface的时候,它就会找到与它所对应的SharedBufferStack,并且从它的空闲缓冲区列表的尾部取出一个空闲的Buffer。我们假设这个取出来的空闲Buffer的编号为index。接下来Android应用程序就请求SurfaceFlinger服务为这个编号为index的Buffer分配一个图形缓冲区GraphicBuffer。SurfaceFlinger服务分配好图形缓冲区GraphicBuffer之后,会将它的编号设置为index,然后再将这个图形缓冲区GraphicBuffer返回给Android应用程序访问。Android应用程序得到了SurfaceFlinger服务返回的图形缓冲区GraphicBuffer之后,就在里面写入UI数据。写完之后,就将与它所对应的缓冲区,即编号为index的Buffer,插入到对应的SharedBufferStack的已经使用了的缓冲区列表的头部去。这一步完成了之后,Android应用程序就通知SurfaceFlinger服务去绘制那些保存在已经使用了的缓冲区所描述的图形缓冲区GraphicBuffer了。用图5的例子来说,SurfaceFlinger服务需要绘制的是编号为1和2的Buffer所对应的图形缓冲区GraphicBuffer。由于SurfaceFlinger服务知道编号为1和2的Buffer所对应的图形缓冲区GraphicBuffer在哪里,因此,Android应用程序只需要告诉SurfaceFlinger服务要绘制的Buffer的编号就OK了。当一个已经被使用了的Buffer被绘制了之后,它就重新变成一个空闲的Buffer了
Android的16ms和垂直同步以及三重缓存 GPU 除了帧缓冲区用以交给手机屏幕进行绘制外、还有一个缓冲区 Back Buffer这个用以交给应用的,让CPU往里面填充数据。GPU会定期交换 Back Buffer 和 frame Buffer ,也就是对Back Buffer中的数据进行栅格化后将其转到 frame Buffer 然后交给屏幕进行显示绘制,同时让原先的frame Buffer 变成 Back Buffer 让程序处理。4.1Project Butter对AndroidDisplay系统进行了重构,引入了三个核心元素,即VSYNC、Triple Buffer和Choreographer。其中, VSYNC是理解Project Buffer的核心。VSYNC是Vertical Synchronization(垂直同步)的缩写,是一种在PC上已经很早就广泛使用的技术。 可简单的把它认为是一种定时中断。
没有VSYNC的情况
有VSYNC的情况
三级缓存
Android的视图分类 View:显示视图,内置画布Canvas,提供图形绘制函数、触屏事件、按键事件函数等;必须在UI主线程内更新画面,速度较慢。SurfaceView or textureView:基于view视图进行拓展的视图类,更适合2D游戏的开发;是view的子类,类似使用双缓机制,在新的线程中更新画面所以刷新界面速度比view快。GLSurfaceView:基于SurfaceView视图再次进行拓展的视图类,专用于3D游戏开发的视图;是SurfaceView的子类,openGL专用怎么选择
Android中提供了View进行绘图处理,View可以满足大部分的绘图需求,但是有时候,View却显得力不从心,所以Android提供了SurfaceView和textureView给Android开发者,以满足更多的绘图需求。
SurfaceView专门提供了嵌入视图层级的绘制界面,开发者可以控制该界面像Size等的形式,能保证界面在屏幕上的正确位置。但也有局限:由于是独立的一层View,更像是独立的一个Window,不能加上动画、平移、缩放;两个SurfaceView不能相互覆盖 同时配合scrollView的使用会有一定的风险TextureView更像是一般的View,像TextView那样能被缩放、平移,也能加上动画。TextureView只能在开启了硬件加速的Window中使用,并且消费的内存要比SurfaceView多,并伴随着1-3帧的延迟surfaceView遇到的问题 和类scrollView配合使用内容不显示重写onMeasure方法确定UNSPECIFIED模式的的大小配合scrollView之后的内容不显示在scrollview外部添加view动态添加或者在xml上第一次添加会出现闪屏现象不能设置背景色参考
1.Opengl与Directx的区别 http://mtoou.info/directx-opengl-shenme/index.html
2.Windows 支持 DirectX 和 OpenGL,为什么大多数 PC 游戏还是 DirectX 开发 https://www.zhihu.com/question/23241456
3.OpenGL ES 3.0 支持的设备和模拟器 https://www.cnblogs.com/singmelody/p/3774638.html
4.OpenGL ES 3.0入门 https://www.jianshu.com/p/2ce67644eae8
5.Android应用程序与SurfaceFlinger服务的关系概述 https://blog.csdn.net/luoshengyang/article/details/7846923
6.是不是游戏帧数一般要到 60 帧每秒才流畅,而过去的大部分电影帧数只有 24 帧每秒却没有不流畅感?https://www.zhihu.com/question/21081976
7.Android的16ms和垂直同步以及三重缓存http://dandanlove.com/2018/04/13/android-16ms/