使用 英特尔 流式 SIMD 扩展 优化 动画 模型 的 渲染流水线
作者JMP van Waveren, Id Software,Inc.
介绍
以下文章描述了渲染管道中使用的各个例程,以及如何使用英特尔Streaming SIMD扩展进行优化。
今天的大部分电脑游戏都带有实时照明和阴影的动画多边形模型。电脑游戏DOOM * III(2004年8月)和Quake * 4(2005年10月)也不例外。两台电脑游戏都使用骨架动画系统。通常被称为“皮肤”的多边形网格连续地改变形状,其中底层结构通常被称为“骨架”。通过动画化骨骼,皮肤被转化。将皮肤转变的过程称为“剥皮”。两个游戏也使用阴影卷定义在遮挡物阴影的空间中的区域。阴影体积由包含多边形封堵器阴影的体积的多边形边界表示定义。
以下文章概述了SIMD优化的动画模型渲染流水线,其性能与电脑游戏DOOM III中使用的性能相当。
这个改进的渲染流水线在计算机游戏Quake 4中实现。大部分渲染流水线在CPU上运行,而管道中的几个步骤可以运行在当今许多显卡上可用的GPU上。
然而,在CPU上运行大部分管道可以提高广泛系统的兼容性。
较旧的系统可能具有不支持在GPU上执行动画和蒙皮的必要功能的图形卡
(如GeForce2和GeForce4MX)。
允许在GPU上进行皮肤化的显卡可能具有将大型骨架模型细分为多个网格的限制,
从而降低效率。
此外,需要后变换的皮肤来构建阴影卷,
并且当前的图形卡在处理之后不允许检索此数据。
阴影体积结构可以完全卸载到GPU,
但是如果闭塞器具有高三角形数量或者如果有大量阴影投射光源,
则这可能无法提高性能。
由于这些原因,电脑游戏DOOM III和Quake 4运行CPU上的大部分管道,
允许游戏在各种系统配置下运行。
此外,在CPU上运行的流水线几乎没有任何限制,
SIMD优化使得流水线与(部分)GPU实现相竞争。
渲染管道可以细分为四个一般阶段。
这些阶段是动画,皮肤,阴影体积建设和裁剪和光栅化。下图显示了这些阶段为大型浅灰色块。每个阶段被细分为更小的步骤,其中处理的数据以倾斜框显示,并且处理该数据的例程显示在较暗的灰色框中。这些框的黑色角落中的数字对应于底部描述例程的文章以及如何使用英特尔Streaming SIMD扩展进行优化。
动画系统可以混合一个或多个动画。在上图中仅显示了两个动画,
但是可以将更多的动画混合在一起以产生复杂的运动混合。
动画是一系列动画帧。
每个动画框架将骨架的姿态定义为使用四元数描述方位的关节位置 和 方向的列表。
关节的位置和方向与骨骼层次结构中关节的父母相关。
点击图片查看大图。
系统从动画中抽取时间t0和t1的两帧,使得当前时间在t0和t1之间。
然后系统在这两个帧之间进行插值,以获得当前时间的骨架姿势。
然后将正在播放的所有动画的内插帧混合在一起以获得骨架的最终姿态。
接下来,将关节位置和四元数变换为3×4矩阵。
此外,联合矩阵用其父母的联合矩阵进行变换,以在模型空间中创建骨架。
点击图片查看大图。 (图片请参照原文........)
模型空间中的骨架用于为通常称为蒙皮的三角形网格生成动画。
基于三角形网格是用于渲染还是仅用于创建阴影卷或进行碰撞检测,
系统可以决定最佳的剥皮方法。
如果模型没有使用漫反射,法线和法线贴图,
则通常不需要在顶点位置计算正态和切线矢量。
如果不需要,可以通过不动画化和计算这些附加顶点属性来节省时间。
确定计算正态和切向矢量的剥皮方法要求将骨架的关节进行变形,
使得它们相对于被变换以创建动画网格的基础姿势的关节。
点击图片查看大图。 在下一阶段,为与三角形网格相互作用的每个光源构建阴影体。
阴影体定义空间中具有附加几何的对象空间中遮挡物阴影的空间区域。
可以为点光源,聚光灯和定向光源构建阴影卷,
并始终产生像素精确但硬的阴影。
在构造任何阴影卷之前,需要导出三角形网格中三角形的平面方程。
这些平面方程用于找到面向或远离光源的三角形,并确定几何图形的阴影轮廓边缘。
这样的轮廓边缘是点燃和未点燃三角形之间的边界。
点击图片查看大图。 在最后一个阶段,
通常在GPU上运行,三角形网格和阴影体被裁剪和光栅化。
阴影体 被渲染到模板缓冲区,
当在屏幕上渲染三角形网格 以 确定 哪些 像素 处于 阴影 时 被查询。
要确定空间中三角形网格的阴影区域,
模板缓冲区首先被清除为全零。
然后用适当的深度测试将三角形网格的阴影卷呈现到模板缓冲区。
前面的阴影体积三角形增量和背面三角形减少模板缓冲区像素。
现在在阴影中考虑了具有不等于零的模板缓冲区值的像素。
下表显示了在渲染管道中使用的所有SIMD优化例程的概述。
该表显示了90nm技术上的Intel®Pentium®4处理器上的例程的热缓存 时钟 周期 计数。
将例程的加速因子与执行相同计算的C / C ++中的参考实现进行比较。
但是,C / C ++源代码编译成在基于x86 FPU的常规堆栈上运行的代码。
前面的阴影体积三角形增量和背面三角形减少模板缓冲区像素。
现在在阴影中考虑了模板缓冲区值不等于零的像素。
下表显示了在渲染管道中使用的所有SIMD优化例程的概述。
该表显示了90nm技术上的Intel®Pentium®4处理器上的例程的热缓存时钟周期计数。
将例程的加速因子与执行相同计算的C / C ++中的参考实现进行比较。
但是,C / C ++源代码编译成在基于x86 FPU的常规堆栈上运行的代码。
前面的阴影体积三角形增量和背面三角形减少模板缓冲区像素。
现在在阴影中考虑了具有不等于零的模板缓冲区值的像素。
下表显示了在渲染管道中使用的所有SIMD优化例程的概述。
该表显示了90nm技术上的Intel®Pentium®4处理器上的例程的热缓存时钟周期计数。
将例程的加速因子与执行相同计算的C / C ++中的参考实现进行比较。
但是,C / C ++源代码编译成在基于x86 FPU的常规堆栈上运行的代码。
下表显示了在渲染管道中使用的所有SIMD优化例程的概述。
该表显示了90nm技术上的Intel®Pentium®4处理器上的例程的热缓存时钟周期计数。
将例程的加速因子与执行相同计算的C / C ++中的参考实现进行比较。
但是,C / C ++源代码编译成在基于x86 FPU的常规堆栈上运行的代码。
下表显示了在渲染管道中使用的所有SIMD优化例程的概述。
该表显示了90nm技术上的Intel®Pentium®4处理器上的例程的热缓存时钟周期计数。
将例程的加速因子与执行相同计算的C / C ++中的参考实现进行比较。
但是,C / C ++源代码编译成在基于x86 FPU的常规堆栈上运行 的 代码。
常规 | 加速系数 | 说明每次迭代 | 每次迭代的元素 | 数迭代 | 总指示 | 总时钟周期 | 每个元件的时钟周期 | 每个指令的时钟周期 |
SlerpJoints | 7.9 | 213 | 4 | 256 | 54549 | 131517 | 128 | 2.4(2.411) |
LerpJoints | 4.8 | 132 | 4 | 256 | 33819 | 52848 | 52 | 1.6(1.563) |
ConvertJointQuatsToJointMats | 1.8 | 34 | 1 | 1024 | 34823 | 34362 | 34 | 1.0(0.987) |
ConvertJointMatsToJointQuats | 2.4 | 207 | 4 | 256 | 53003 | 73710 | 72 | 1.4(1.391) |
TransformSkeleton | 3.0 | 45 | 1 | 1024 | 46093 | 54297 | 53 | 1.2(1.178) |
UntransformSkeleton | 2.8 | 48 | 1 | 1024 | 49164 | 57285 | 56 | 1.2(1.165) |
TransformJoints | 3.0 | 41 | 1 | 1024 | 41995 | 48906 | 48 | 1.2(1.165) |
TransformVerts | 3.0 | 39 | 1 | 1024 | 39946 | 43956 | 43 | 1.1(1.100) |
TransformVerts(SSE3) | 3.1 | 33 | 1 | 1024 | 33802 | 41963 | 41 | 1.2(1.241) |
TransformVertsAndTangents | 2.6 | 80 | 1 | 1024 | 81930 | 89775 | 88 | 1.1(1.096) |
TransformVertsAndTangents(SSE3) | 2.8 | 61 | 1 | 1024 | 62474 | 81855 | 80 | 1.3(1.310) |
DeriveTrianglePlanes | 4.2 | 121 | 4 | 256 | 30990 | 36128 | 35 | 1.2(1.165) |
CountFacing | 59.2 | 31 + 4 | 256 + 16 | 5 + 4 | 196 | 383 | 0.3 | 2.0(1.954) |
CountFacingCull | 2.1 | 37 | 4 | 336 | 12454 | 13883 | 10 | 1.1(1.115) |
CreateSilTriangles | 1.2 | 70 | 4 | 504 | 35300 | 36901 | 18 | 1.0(1.045) |
CreateCapTriangles | 2.4 | 54 | 4 | 336 | 18170 | 14205 | 11 | 0.8(0.782) |
所有呈现的例程假设被处理的数据都在缓存中。可选的预取指令可以添加到例程中。
然而,预取距离不仅取决于CPU类型,还取决于CPU速度,内存速度,缓存速度,
缓存级别数以及其他几个因素。
因此,在所有系统配置上都没有最佳的预取距离。
英特尔手册提供了使用预取指令优化特定配置的内存访问的指标。
通常可以通过一次将模型推下一个管道来提高缓存的使用率。
因此,流水线中的一个步骤的结果在流水线的下一步骤中从高速缓存取出后
通过缓存和快速写入存储器。
与130nm技术上的较早的英特尔®奔腾®4处理器相比,
在90nm技术的较新英特尔®奔腾®4处理器上执行代码时,
文章中提供的一些热缓存时钟周期计数略高。
首先,这些CPU之间的这些热缓存时钟周期差异与所呈现的优化的性能改进无关。
90nm技术上的英特尔®奔腾®4处理器具有更深的流水线,预期稍高一些的热缓存时钟周期。
然而,90nm技术上的英特尔®奔腾®4处理器可以提供更高的频率,
并且由于更长的管道,由此架构可实现的频率增加高于热缓存时钟周期计数的增加。
此外,90nm技术上的英特尔®奔腾®4处理器具有许多改进,
在许多情况下,实际上使其在130nm技术上以相同频率运行的英特尔®奔腾®4处理器的性能更好。
采用130nm技术的英特尔®奔腾®4处理器,
90nm技术架构上的英特尔®奔腾®4处理器的一些改进包括:
- 较大的缓存。
- 改进的软件和硬件预取。
- 更好的静态和动态分支预测。
- 增加调度程序队列,以改进对并行性的利用。
- 认识到更多的指示可能会破坏依赖关系链。
- 减少一些指令的延迟,如整数乘法和逐位逻辑移位。
- 新的指令,如浮点整型转换,截断,线程同步指令和流式SIMD扩展3(SSE3)。
130nm技术上的英特尔®奔腾®4处理器从1.6 GHz扩展到3.4 GHz,
并附带512 kB片上缓存。90nm技术的英特尔®奔腾®4处理器的尺寸为2.4 GHz至3.8 GHz,
并带有1或2 MB片上缓存。