本文是该系列的最后一篇文章。该系列文章在我的网页上已载有数月,由于Vulkan产品的发布占用了我很多时间,最后收官之作的发表可能有些晚,希望大家还能关注它。本文中,我将阐述为何Vulkan比上一代API更适合硬件,同时,我还将深入PowerVR GPU的一些细节,并援引具体案例。
OpenGL ES
首先,让我们看看当下行业领先的API及其问题存在的原因。距OpenGL ES的发行已有12年多,而API是基于OpenGL ES的产品。OpenGL早在23年前便已设计问世,其最初设计的硬件与当下使用的各式硬件大为不同。
状态机
OpenGL是一款大型的全球状态机,每次 *** 作均需要考虑当前状态的各个部分,如混合模式、当前的着色器、深度测试信息等。所有的事情看似一个简单的制动开关或杠杆,可以不计实际的后果随意改变开关状态——它只是一个函数调用?对于现代硬件而言这是不切实际的——例如很多状态会被转化为着色代码。
在移动产品的高效性一文中,我已经提到,考虑到挂接及渲染期间CPU的使用率,着色器修复是不确定的。还有另一个我之前未提及的问题——着色器本身的低效率。如果必须修复着色器状态,则会出现优化后编译,即附加至剩余的着色器中是有效的。如果在编译时状态已知,则可以一直优化编译,以避免出现几条指令。为解决此问题,驱动器可能会进行背景的重新编译,但这本身也是一个问题(消耗更多的CPU时间)。
隐含同步
OpenGL ES假设很多东西是相互隐含同步的。只有引入栅栏时,计算着色器及其不良反应才被认为是任何形式的异步工作。大部分API仅仅只是工作——事实上这可以归结为资源跟踪、缓存刷新和场景后的依赖关系链建设。
驱动器不可能非常准确地检测依赖项——它们十分保守,以能实现OpenGL ES功能。这意味着将不可避免地进行一些不必要的缓存刷新或不必要的序列化工作——换言之,硬件需要做更多的工作。
立即模式
自始至终,OpenGL ES中指定的命令应该严格按照规定的先后顺序来执行。一个简单的命令如绘制调用通常被当作一个单一的整体工作单元,其在GPU中有规定的队列顺序。这种行为即立即执行模式——每个指定的工作以某种方式被即刻发送至GPU进行处理。
在过去,立即渲染模式(IMR)架构可以很好地映射到这种思维方式中,但现代IMR倾向于批量处理工作以提高性能。
基于区块贴图的渲染 (TBR)或基于区块贴图的延迟渲染 (TBDR)从未以这种方式工作。迄今为止存在的最多产的类型是GPU架构类型:这些架构类型的主要工作单元非常大——渲染通道便是很好的诠释——所有的绘制调用都集中在相同的帧缓冲区中。
TBR和TBDR都有两级渲染,早期阶段主要处理几何图形及在屏幕空间贴图中进行分类排序。第二阶段则将贴图栅格化,使整个贴图完全保存在片上帧缓冲区中——这可节省大量的带宽,其在移动市场占据优势。Rys Sommefeldt做了更详细的阐述,感兴趣的可以查阅他的文章。
关键在于,在光栅化阶段,绘制调用是无意义的——一个单一的绘制调用可能产生多个贴图的光栅化,每个贴图包含了多个绘制调用的工作。如果某些信息引起绘图之间的冲刷,则整个渲染就会分裂,这就需要对很多贴图进行再次渲染。在贴图开始和结束时,必须加载帧缓冲区数据到贴图中,并随后进行存储——这样重复多次后便失去了基于区块贴图架构的优势,而架构本身是极力避免消耗此类带宽的。
总之,现代硬件倾向于批量处理工作,且提交单个绘制调用会降低效率。在OpenGL ES中有很多 *** 作迫使驱动器提交单个绘制调用,这一点大家有目共睹。在TBR或TBDR中,这会产生很多不必要的且驱动器无力应对的带宽。
Vulkan
我可能呈现给大家的OpenGL ES是比较沉闷的形象,但不要灰心,不然当今的移动世界便不会有如此多精彩的图像内容。
Vulkan甚至比一个高度优化的OpenGL ES驱动器做的更好。我以前提过,Vulkan是显式的,且需要在应用程序中获取大量的信息——所有这些都是确保Vulkan可以流畅地工作,且不会产生很多用户不可见的成本。
管线
Vulkan假定所有的状态都将被再次启用,因此其比OpenGL ES看起来更为静态。管线多采用先前的动态状态,并与着色器一起被编译。这意味着任何先前需要着色器修复的信息现在可以提前被编译。在编译时拥有这些信息意味着可以对绘制调用即刻使用的着色器和状态进行完整的编译和优化,且不需要在渲染循环中将这些信息进行打包处理。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)