1、1面向 3D 图形处理器快速分层的深度预测试方法摘要:提出了一种快速分层的深度预测试方法.通过结合 Z_max和Z_min算法,从像素块和像素点两个单位层次,快速地预剔除了无需绘制的像素点,避免了诸如深度值、颜色值和纹理值的读写等针对像素点的绘制操作,降低了渲染场景所需的时间.合理的共享像素块缓存(TileZcache)的设计,有效地提高了命中率,进一步减少了预测试的时间.同时提出的动态更新像素块的方法,以更小的硬件代价,提高了深度预测试的效率.仿真结果表明,对于随机测试的绘制场景,这种快速分层的深度预测试方法,使得每帧绘制时间减少了 12.5%25.6%,访存的带宽节省与每个像素点的存储面积
2、比最大增加了 43.8%,适用于嵌入式3D的渲染引擎中. 关键词:3D 图形处理器;深度预测试;存储带宽 中图分类号:TP391 文献标识码:A A Fast and Hierarchical Early Z-Test for 3D Graphics Processors ZHANG Jun-jie1,WEI Ji-zeng2,WANG Hang-sheng2,GUO Wei2,3 (1.School of Electronic Information Engineering,Tianjin Univ,Tianjin 300072,China; 2.School of Computer Sci
3、ence and Technology,Tianjin Univ,Tianjin 300072,China; 23. Tianjin Key Laboratory of Cognitive Computing and Application(Tianjin Univ) ,Tianjin 300072,China) Abstract: A Fast and Hierarchical Early Z-Test (FH-EZT) was proposed to reject the pixels unnecessary to draw as soon as possible from the til
4、e level and pixel level by combining Z_max and Z_min algorithm. Redundant pre-pixel operations including Z reads/writes, color reads/writes and texture reads were avoided efficiently to decrease the rendering times. Shared tile cache (TileZcache) with high hit rate cuts down the testing cycles and t
5、he values of tiles can update dynamically utilizing less cost. Experiments show that the proposed algorithm can reduce 12.5% up to 25.6% rendering cycles for each random tested frame and enhance 4% up to 43.8% for the ratio of bandwidth reduction and storage area per pixel, which is suitable for emb
6、edded 3D engine. Key words: 3D graphics processors;early Z-test;memory bandwidth 随着嵌入式终端的迅猛发展,游戏、3D 导航、人机接口等多媒体应用得到广泛关注.因此,如何在高分辨率的屏幕上,以最小的功耗代价实时地对复杂 3D场景进行绘制,是嵌入式图形处理器亟需解决的问题.帧渲染时间和存储器带宽是影响嵌入式 GPU速度和功耗的两个重要的性能指标,虽然半导体技术的高速发展带来了速度和性能的极大提升,但是3渲染的时间和存储器的访问依旧成为瓶颈.并行或离线渲染不同的帧可以有效地缩短渲染时间,但是需要很大的芯片面积和存储面积
7、,不适合应用于嵌入式系统,而且在绘制一帧时并不能做到并行渲染,所以尽可能快速地分辨每帧处理像素点的有效性,能够间接地提高渲染速度.另一方面,存储器的带宽是有限的,在图形系统绘制流水线的像素处理阶段,存在 5种类型的存储器访问,深度值的读取、深度值的写回、颜色值的读取、颜色值的写回和纹理值的读取,而有关深度数据读写的带宽需求至少占据 40%1,所以通过深度预测试及早判断像素点的有效性,减少不必要的存储器的访问,不仅可以加快处理速度,而且能够降低系统功耗. 许多利用深度预测试以节省存储器带宽的方法在以往的资料中被提出,大体上可以分为 3类,即 Z_max算法、Z_min 算法和混合型算法.利用 Z
8、_max算法,能够及早剔除被遮挡的像素点,有效地避免了不必要的存储器访问.HZbuffer 算法采取了减小深度缓存分辨率的方式,在纹理读取等操作之前剔除了不可见的像素点,避免了 5种类型的存储器访问.但是需要较大的片上存储空间,而且更新繁琐,后来被 ATI结合深度压缩等方法用于商用1,但并不适用于嵌入式系统.Depth Filter的算法2在绘制每帧时,采用一个或几个确定的平面,通过 mask值记录每一个像素点之前绘制的历史信息,用以剔除不可见的像素点,剔除的效果与平面的数量成正比,但是面积也会随之增大.虽然平面的位置会有更新,但是确定位置的方法比较苛刻,而且对场景有着很大的依赖性,所以性能不
9、会一直有保证.Midtexturing 的算法3分别是在纹理读取之前和之后4进行两次深度测试,但只剔除了不必要的纹理的读取,而且两次深度测试之间过长的流水线引起的访存一致性问题,会降低深度缓存(Z cache)的命中率,采取对应的改善措施后效果也不显著.后来他们对这种算法进行了改进4,依据相邻像素间的一致性,通过判断标志位,预测出将要处理的像素点的可见性,可以选择性地将其中一次深度测试设置为有效,而不是让两次都进行处理,但是两次深度测试之间的流水线长度决定了标志位的更新不会很及时,可能需要较长时间的等待,而且在没有或者很少纹理映射的情况下,会适得其反. Z_min 算法是Mller提出的与 Z
10、_max剔除不可见像素点截然相反的想法5,对于当前处理的像素块,计算出内部包含所有像素点的最大值 Zmax_curruent,与从片外取来的对应像素块的最小值 Zmin_previous比较,若Zmax_curruent Zmax _previous) then Tilei is defined as absolutely occluded, go to step 2. 7else then Tilei is defined as uncertain, go to step 2. 2:move to the next tile, go to step 1. 在 Tri-Setup中预先计算出当
11、前处理的三角形 3个顶点深度的最小值 Zmin_tri,可以将其看作光栅扫描到的每个待处理像素块的最小值,与从 TileZcache或者片外的 TileZbuffer中读取当前处理像素块之前的最大值 Zmax_previous作比较,若 Zmin_triZmax_previous,则判断出当前像素块(或者整个三角形,当三角形完全在一个像素块内部时)可以被完全剔除;否则认为其无法判定,将其送入后续的流水线阶段进行处理.该流水线阶段对于 TileZcache的访问是只读的,对 Zmax_previous值不必进行更新写回,具体 TileZcache的设计及其原因详见第 2.3节. 这种基于像素块的
12、深度预测试粗粒度地判定了像素块可能存在的位置,只需一个周期的处理时间,而不是针对逐个像素点进行处理所用的M(像素块包含的有效像素点数量)个周期,通过增加很少的预计算量,有效地节省了存储器带宽的同时,也极大地缩短了每帧渲染的时间. 1.2 Pixel-EZT Pixel-EZT 结合了混合型算法的基本思想,实现的功能如算法 2和图3所描述.对于 Tile-EZT测试失败的像素块,通过 Pixel-Scan的扫描,将像素块内部有效的像素点仍以该像素块为集合送入到 Pixel-EZT阶段.针对每个像素点的深度值 Z_pixel,逐一与从 TileZcache或者片外的TileZbuffer中读取当前
13、处理像素块之前的最大值 Zmax_previous和最小8值 Zmin_previous作比较,若 Z_pixel Zmax_previous,则判断出当前像素点为不可见的;否则认为其无法判定,将其送入后续的流水线阶段进行处理. 算法 2 Pixel Early Z-Test Alg orithm(Pixel-EZT) input: Z_pixel,Zmin _previous, Zmax _previous 1: initialize Zmin _current,Zmax _current. Zmin _current=1.0, Zmax _current=1.0 2: if(Z_pixel
14、Zmax _previous) then Pixeli is defined as absolutely occluded, go to step 3. else then Pixeli is defined as uncertain, go to step 3. 3:traverse the next valid pixel. if there are pixels valid next, go to step 2. esle update to Zmin _previous,Zmax _previous. Zmin _previous=Zmin _current, Zmax _previo
15、us=Zmax _current. 4:move to the next tile, go to step 1. 9该流水阶段对于 TileZcache的访问是可读可写的,对Zmax_previous值和 Zmin_previous值需要不断进行更新写回,以保证深度预测试的效率.对于 Zmax_previous值,只有在当前像素块内所有像素点的深度值均小于 Zmax_previous且全部判断完时,才对其进行更新,把其中所有像素点的最大值写回 TileZcache,成为新的 Zmax_previous值,如图 3中的点 a.因为 Zmax_previous值的更新是要不断往视点的方向移动,若非
16、像素块内部的所有像素点都有效,则更新后的Zmax_previous值可能使得那些无效像素点的位置由原来不确定的区域变成完全剔除的区域,实施了错误的剔除.而对于 Zmin_previous值,只需要在当前像素块内所有有效的像素点全部判断完后,就可以对其进行更新,把其中所有有效像素点的最小值写回 TileZcache,成为新的Zmin_previous值,如图 3中的点 b.因为 Zmin_previous值的更新也是要不断往视点的方向移动,但是更新后的 Zmin_previous值并不能影响原来像素块内部那些无效像素点的可见性,可能只不过是由原本完全可见的区域变成了不确定的区域,但不会产生绘制的
17、错误. 这种基于像素点的深度预测试细粒度地判定了像素点可能存在的位置,不借助额外的标志位等辅助信息,通过保守地动态更新所在像素块的最大值和最小值,使得深度预测试以更小的代价实现了较好的性能.可以简单地证明,一个包含有 mn大小的像素块只需要一个最大深度值和一个最小深度值的位宽存储开销,以深度值的精度为 32位、mn 取 32为例,平均每个像素点只需要两位的存储代价,即可满足功能的需求. 1.3 共享 TileZcache 10Tile-EZT 和 Pixel-EZT两个层次的深度预测试阶段形成了流水线式的处理,对于 Tile-EZT阶段测试失败的像素块将会流水到 Pixel-EZT阶段,因此需
18、要重复读取同一像素块的最大值或最小值,此时共享的TileZcache的设计是必要的,可尽量减少冗余的访存. Tile-EZT 阶段只涉及 TileZcache中 Zmax_previous值的读取,因为此时并不确定与之作比较的当前处理的像素块真正的最小值,硬性地写回可能会对下一次相同位置像素块是否剔除产生错误的判断.同时对于像素块是否完全可见的快速预判断并不支持,而且也无必要,即无需读取TileZcache中 Zmin_previous值,原因是后面 Pixel-EZT阶段会不定时地更新 TileZcache,可能使得前面 Tile-EZT阶段读取下一次相同位置像素块的 Zmin_previo
19、us值并不及时,引起 TileZcache的一致性问题,从而导致判断的失误.即使增加复杂的逻辑判断或流水线等待以避免这一问题,也会因为已经判定为完全可见的像素块也要送入 Pixel-Scan中进行逐个像素的光栅扫描处理,并不能节省处理的周期时间. Pixel-EZT 阶段会重复读写从 Tile-EZT阶段接收过来的同一像素块的最大值或最小值,添加的 TileZcache实现两个阶段的共享,可以有效地减少访问存储器的次数,进一步缩短了深度预测试所需的周期时间.为了有效地提高读写 TileZcache的命中率,可以采取以下两个措施:一是将 TileZcache设计成先进先出(FIFO)的替换策略,使得当前处理的像素块与存储在缓存中的相应的最大值和最小值信息保持同步的流水;二是使设计的 TileZcache的尺寸不小于两个阶段之间的最大流水线级数,主要是由缓存待处理像素块(Tile-FIFO)的深度决定的.综合以上两点,