为什么需要平铺资源?

需要平铺资源,因此更少的图形处理单元 (GPU) 内存会浪费在存储应用程序知道无法访问的图面区域,并且硬件可以了解如何跨相邻磁贴进行筛选。

在图形系统 (即操作系统、显示驱动程序和图形硬件) 没有平铺资源支持,图形系统以子资源粒度管理所有 Direct3D 内存分配。 对于 缓冲区,整个缓冲区是子资源。 对于 纹理 (例如 Texture2D) ,每个 mip 级别都是一个子资源;对于纹理数组 (例如 Texture2DArray) ,给定数组切片中的每个 mip 级别都是一个子资源。 图形系统只能以该子资源粒度管理分配映射。 在平铺资源的上下文中,“映射”是指使数据对 GPU 可见。

假定应用程序了解特定的呈现操作只需要查看一小部分的 mipmap 链图像(可能只查看某个特定 mipmap 的部分区域)。 理想的情况下,应用程序最好要向图形系统告知此需求。 只有在为了确保在不占用太多内存的情况下在 GPU 上映射所需内存的情况下,图形系统才会干预。 实际上,如果没有平铺资源支持,图形系统只能被告知需要以子资源粒度 (GPU 上映射的内存,例如,) 可以访问的一系列完整的 mipmap 级别。 在图形系统方面也没有要求,因此可能需要额外使用大量的 GPU 内存,才能在执行呈现命令(参考任何部分的内存)之前映射完整的子资源。 这只是一个问题,使得在没有平铺资源支持的情况下难以在 Direct3D 中使用大型内存分配。

Direct3D 11 支持给定一侧最多 16384 像素的 Texture2D 表面。 16384x16384(宽 x 高)的图像,每个像素为 4 字节,可占用 1GB 的视频内存(且添加 mipmap 可能使内存占用加倍)。 事实上,在单个呈现操作中很少需要用满 1GB。

一些游戏开发人员的地形表面建模尺寸相当大,为 128K x 128K。 为了使其适用于现有的 GPU,游戏开发人员会将表面分为若干足够小以便硬件处理的磁贴。 应用程序必须查明可能需要哪些磁贴,并将其加载到 GPU(软件编页系统)上的纹理缓存区。 此方法的一个重大缺点是硬件对正在进行的分页没有任何了解:当图像的一部分需要在屏幕上显示跨越磁贴时,硬件不知道如何执行固定功能 (也就是说,跨磁贴高效) 筛选。 这意味着,自主管理软件平铺的应用程序必须依靠使用着色器代码的手动纹理筛选(如果希望获得良好的各向异性筛选效果,代价将变得十分高昂),以及/或者耗用内存在磁贴周围创建栏距(包含相邻磁贴的数据),以便固定的硬件筛选功能继续有效。

如果图面分配的平铺表示形式可能是图形系统中的第一类功能,则应用程序可以告知硬件哪些磁贴可用。 通过这种方式只需用到很少的 GPU 内存(因为不会访问应用程序知道的表面存储区域),而且硬件了解如何在相邻磁贴间筛选,极大地方便了独立执行软件平铺的开发人员。

为了使解决方案更加完善,我们还必须有所作为,因为不考虑是否支持表面区域内平铺,表面尺寸目前最大为 16384(与应用程序希望的 128K+ 还相差甚远)。 一种方法是只需要硬件支持更大尺寸的纹理,但这种方法会产生高昂的成本并且/或者使效果大打折扣。 Direct3D 11 的纹理筛选器路径和呈现路径在支持 16K 纹理的精度方面已经饱和,并满足其他要求,例如支持在渲染过程中从图面上掉落的视区范围,或在筛选期间支持纹理从表面边缘环绕。 一种可能是确定一种折衷方案以便使纹理尺寸突破 16K,但这在一定程度上影响到功能性/精确性。 但即便作出此让步,也必须针对整个硬件系统的寻址能力投入额外的硬件成本,以便处理更大尺寸的纹理。

当纹理变得非常大时,单精度浮点数纹理坐标(以及用以支持光栅化的相关内插)就不能准确指定表面位置。 接着,纹理筛选会出现抖晃。 解决方案是依靠双精度内插支持,但这样做成本高昂,但凡出现合理的替代方案,这个解决方案就会被取代。

平铺资源的替代名称是“稀疏纹理”。“稀疏”既传达了资源的平铺性质,也或许是平铺这些资源的主要原因,即并非所有资源都预计会同时映射。 事实上,应用程序可以想而知地创作了一个平铺资源,其中没有针对资源的所有区域和 mips 编写数据。 因此,内容本身可能稀疏,在给定时间 GPU 内存中的内容映射将是该 (更稀疏) 的一个子集。

可通过平铺资源提供的另一种方案是启用不同维度/格式的多个资源来共享同一内存。 有时,应用程序包含已知不能同时使用的专用资源集,或者只为了短暂使用而创建且在创建其他资源之后即销毁的资源。 “平铺资源”的一种通用性形式是,允许用户将多个不同资源指向同一 (重叠) 内存。 换言之,从应用程序角度看,“资源”(定义尺寸/格式等)的创建以及销毁可独立于内存管理(内存管理是资源的基础)。

平铺资源