Mali GPU-抽象机器

来源:互联网 发布:windows xp翻墙 编辑:程序博客网 时间:2024/06/07 06:12

帧渲染管线

主要3部分
1. cpu-gpu渲染管线
2. 基于tile的渲染
3. 着色器核心架构

渲染管线

同步API,异步执行

如果强制渲染操作同步执行,那么当cpu忙于准备下一个渲染操作的状态时,gpu就会空闲。当gpu渲染时,cpu空闲。
这里写图片描述
为了减少空闲时间,我们用OpenGL ES驱动使表面上看是同步渲染的,实际上异步处理渲染和帧交换。通过异步执行,我们可以挤压一些工作,允许gpu处理渲染管线一端的工作时,cpu往另一端放新的工作。这样的好处是,让管线充实,总是有gpu上要做的工作,提高性能。
这里写图片描述
mali GPU渲染管线的工作单元是一个渲染目标,或者是一个窗体表面或者是线下渲染buffer。一个单独的渲染目标是通过两步处理的:(1)gpu处理渲染目标的所有渲染调用的顶点着色;(2)全部渲染目标的片元着色。所以,mali的逻辑渲染管线是3个阶段:cpu处理、几何处理、片元处理。
这里写图片描述

管道节流

用心的读者会发现,上面图中的片元工作是3个操作中最慢的,远远落后与cpu和几何处理阶段。这个现象很常见,大部分内容的片元都远远大于顶点的着色,所以片元着色往往是最重要的处理操作。
实际上,最迫切的需求是减小cpu工作完成到帧渲染完成之间的延迟——没有比终端用户的交互设备输入和显示在屏幕上的数据之间延迟100多毫秒更沮丧的事儿了。所以我们不想让等待片元处理的挤压工作增长的太多。简单的说,我们需要一些机制来阶段性地放慢cpu线程的工作,当管道已经很满来保证性能的情况下,停止让cpu挤压工作。
这种节流机制通常由主机窗口系统提供,而不是由图形驱动程序本身提供。在Android上,比如,我们不能在一个帧中处理任何绘制操作,知道我们知道缓冲区的方向,因为用户可能已经旋转了他们的设备,改变了帧的大小。surfaceFlinger,Android窗口曲面管理器,可以通过拒绝向应用的缓冲区返回图形堆栈(如果已经有超过N个缓冲区排队等待渲染)来控制流水线深度。
如果出现这种情况,只要达到N,就会发现cpu一帧空闲一次,在egl或OpenGL es API函数中阻塞,直到显示消耗了一个待定缓冲区,释放一个用于新渲染的操作。
这里写图片描述

如果图形堆栈的运行速度快于显示刷新速率,则该方案也限制了流水线缓冲,这种情况下,内容是“vsync限制”,等待垂直空白信号,告诉显示控制器它可以切换到下一个。如果gpu产生的帧比显示器能够显示的快,那么SurfaceFlinger将累积许多已经完成渲染但仍然需要在屏幕上显示的缓冲区,即使这些缓冲区不再是Mali管道的一部分。
这里写图片描述
正如你在上面流水线图中看到的,如果内容是vsynv限制,那么通常会有cpu和gpu都完全空闲的时期。在这些情况下,平台动态电压和频率调整(DVFS)通常会尝试降低当前的工作频率,从而降低电压和能量消耗,但是由于DVFS频率选择通常比较粗糙,因此需要预计一定量的空闲时间。

总结

在这个部分,我们看到了OpenGL ES API提供的同步错觉,以及在API下面实际运行异步渲染管道的原因。下一次调整,我将继续进一步开发抽象机,看看Mali GPU的基于瓦片的渲染方法。

基于图块的渲染

传统方式

在传统的有电源供电的桌面GPU架构中,片元着色器在每个渲染调用中依次在每个图元上执行。
这里写图片描述
由于流中的任何三角形都可能覆盖屏幕的任何部分,因此由这些渲染器维护的数据的工作集很大,一般全屏幕的大小的color buffer、深度缓冲或者可能模板缓冲。一个现代设备的典型的工作集大小是32bit每像素颜色,32bit每像素(bpp)填充深度/模板。因此,1080p显示器的工作集为16MB,而4k2k电视机的工作集为64MB。由于他们的大小,这些工作缓冲区必须存储在DRAM的片外。
这里写图片描述
每个混合,深度测试和模板测试操作都需要从当前工作集中获取当前片段像素坐标的当前数据值。所有着色的片元都会触及这个工作集,所以在高分辨率下,尽管告诉缓存可以稍微减轻这些影响,这个内存上的带宽负载可能非常高,每个片元有多个读-修改-写操作。高带宽访问的需求会发过来驱动需要有大量引脚的宽存储器接口以及专用的高频存储器,这两者都导致特别耗能的大量外部存储器的访问。

Mali方式

Mali GPU系列采用了一种非常不同的方法,通常称为基于图块的渲染,旨在最大限度地减少渲染过程中外部存储器访问量所需的耗电。正如上一部分所说,对于每个渲染对象,mali用了分开的两个阶段渲染算法。它首先执行所有的几何处理,然后执行所有的碎片处理。在几何处理阶段,Mali GPU将屏幕分解成16x16像素的小块,并在每个块中构建一个列表,显示哪些渲染原语存在。当GPU片段着色步骤运行时,每个着色器核一次处理一个16x16像素的图块,在开始下一个之前将其渲染完成。
这里写图片描述
由于16x16的图块只占整个屏幕区域的一小部分,因此可以将整个图块的整个工作集(颜色,深度和模板)保存在与GPU着色器核心紧密耦合的快速RAM中。
这里写图片描述
这种基于瓦片的方法具有许多优点。它们对于开发人员来说通常是透明的,但值得了解,尤其是在试图了解内容的带宽成本时:
+ 所有对工作集的访问都是本地访问,快速又低消耗。读取或写入外部DRAM的功耗随系统设计而变化,但每提供1GByte / s的带宽,容易达到120mW左右。内部存储器的访问量比这少了大约一个数量级的能量密集度,所以你可以看到这确实很重要。
+ 混合既快速又省电,因为许多混合方程所需的目标颜色数据是容易获得的。
+ 瓦片足够小,以至于我们可以在瓦片存储器中本地存储足够的样本,以允许4倍,8倍和16倍的多重取样消除噪声。这提供了高质量和非常低的开销抗锯齿。
+ 马里只需要把一块瓦片的颜色数据写回到瓦片末端的内存中,我们就知道它的最终状态。我们可以通过CRC校验(一种称为事务消除(Transaction Elimination))的过程将块的颜色与主存储器中的当前数据进行比较,如果块内容相同,则完全跳过写入,从而节省SoC电源。
+ 我们可以使用快速,无损压缩方案(ARM帧缓冲压缩(AFBC))对存在事务清除(Transaction Elimination)的瓦片的颜色数据进行压缩,从而使我们能够进一步降低带宽和功耗。这种压缩可以应用于屏幕外的FBO渲染目标,在系统的后续渲染过程中,这些目标可以作为纹理读取,也可以应用于主窗口表面,前提是系统中有一个兼容AFBC的显示控制器,如Mali-DP500。
+ 大多数内容具有深度和模板缓冲区,但是一旦帧渲染完成就不需要保留其内容。如果开发人员告诉Mali驱动程序深度和模板缓冲区不需要保存,理想情况下通过调用glDiscardFramebufferEXT(OpenGL ES 2.0)或glInvalidateFramebuffer(OpenGL ES 3.0),尽管在某些情况下可以由驱动程序推断。另一大带宽和节能!

从上面的列表可以清楚地看出,基于瓦片的渲染具有许多优点,特别是与帧缓冲器数据相关的带宽和功率显着降低,并且能够提供低成本的抗锯齿。
任何基于瓦片的渲染方案的主要额外开销是从顶点着色器到片段着色器的交接点。几何处理阶段的输出,每个顶点的变化和砖瓦中间状态必须被写出到主存储器中,然后由分段处理阶段重新读取。因此,在为变化的数据和瓦片状态花费额外带宽和为帧缓冲器数据节省带宽之间需要进行平衡。
在现代消费电子产品中,现在有一个向更高分辨率显示器的转变,1080p对于智能手机来说是正常的,像Mali-T604供电的谷歌Nexus 10以WQXGA(2560x1600)运行,而在电视市场下,4k2k则成为新的必须。
屏幕分辨率和帧缓冲带宽正在快速增长。在这个领域,mali真的很闪耀,而且对于应用程序开发人员来说,这样做的方式通常是透明的 - 您可以免费获得所有这些好东西,而无需更改应用程序!
在几何方面,玛丽需要应付复杂性。 许多高端基准测试每帧接近一百万个三角形,比Android应用程序商店上的流行游戏应用程序复杂一个数量级(或两个)。但是,由于中间几何数据确实击中了主内存,因此可以使用一些有用的提示和技巧来微调GPU性能,从而获得最佳的系统性能。

总结

比较了桌面风格的立即模式渲染器和Mali使用的基于瓦片的方法,特别是在两者的内存带宽方面。

Midgard着色器核心

GPU机制

Mali GPU(Mali-T600,Mali-T700和Mali-T800系列)的“Midgard”系列采用统一的着色器核心架构,这意味着设计中只存在单一类型的着色器核心。 这个单核可以执行所有类型的可编程着色器代码,包括顶点着色器,片段着色器和计算内核。 特定硅芯片中的着色器核心的确切数量是变化的,我们的芯片伙伴可以根据它们的性能需求和芯片面积限制来选择它们实现的着色器核心数量。 Mali-T760 GPU可以从低端设备的单核扩展到最高性能设计的16核,但是4到8核之间是最常见的实现。
这里写图片描述

参考:翻译:https://community.arm.com/graphics/b/blog/posts/the-mali-gpu-an-abstract-machine-part-1—frame-pipelining
http://fileadmin.cs.lth.se/cs/Education/EDAN35/guestLectures/ARM-Mali.pdf