映射到磁贴池

使用 D3D11_RESOURCE_MISC_TILED 标志创建资源时,构成资源的磁贴来自指向磁贴池中的位置。 磁贴池是内存池(由一个或多个分配在后台提供支持 - 对应用程序不可见)。 操作系统和显示驱动程序负责管理这个内存池,内存占用很容易被应用程序所理解。 平铺资源通过指向磁贴池中的位置来映射 64KB 区域。 此设置有一个副作用:它允许多个资源共享和重复使用相同的磁贴,并允许在资源中的不同位置重复使用相同的磁贴(如果需要)。

为磁贴池以外的资源填充磁贴具有较高的灵活性,但这是有代价的:该资源必须完成定义和维护映射工作,即磁贴池中的哪些磁贴代表该资源所需的磁贴。 可以更改磁贴映射。 此外,不必一次性映射资源中的所有磁贴;资源可以有 NULL 映射。 NULL 映射定义了从访问磁贴的资源角度来看不可用的磁贴。

可以创建多个磁贴池,并且任意数量的平铺资源可以同时映射到任何给定的磁贴池中。 磁贴池还可以增大或收缩。 有关详细信息,请参阅磁贴池调整大小。 为简化显示驱动程序和运行时实现而存在的一个约束是,给定的平铺资源一次最多只能有一个磁贴池的映射 (,而不是) 同时映射到多个磁贴池。

与平铺资源本身关联的存储量 (即独立的磁贴池内存) 大致与任何给定时间实际映射到池的磁贴数成正比。 在硬件中,这一事实归结为页表存储的内存占用情况大致上与被映射的磁贴数量对应(例如,可以视情况使用多级页表方案)。

你可以将磁贴池想象成一种完全的软件抽象,它使得 Direct3D 应用程序能够有效地在图形处理单元 (GPU) 上编写页表,而不必知道低级的实现细节(或不必直接处理指针地址)。 磁贴池不会在硬件中应用任何额外的间接级别。 使用页目录等结构对单级页表进行的优化独立于磁贴池概念。

我们来讨论一下在最坏的情况下页表本身需要多少存储(实际上,实现只需要与映射内容大致成正比的存储)。

假设每个页表条目为 64 位。

假设在 Direct3D 11 中的资源限制的情况下,单个图面的网页表大小命中情况最差,假设创建平铺资源时采用每元素 128 位格式 (例如 RGBA 浮点数) ,因此 64KB 的磁贴仅包含 4096 像素。 最大支持的 Texture2DArray 大小为 16384*16384*2048(但只有一个 mipmap),如果使用 64 位表条目完全填充(不包括 mipmap),则其在页表中需要约 1GB 的存储空间。 添加 mipmap 会使完全映射(最坏情况)的页表存储增长约三分之一,达到约 1.3GB。

这种情况需要访问约 10.6 TB 的可寻址内存。 但可寻址内存的量可能存在限制,这将减少这些数量,可能缩减至约 TB 范围。

要考虑的另一种情况是单个 Texture2D 平铺资源(16384*16384),每个元素 32 位格式,包括 mipmap。 在完全填充的页表中,其需要约 170KB 的空间(64 位表条目)。

最后,考虑一个使用 BC 格式的示例,假设有一个 128 位的 BC7,每个磁贴为 4x4 像素。 每个像素占一个字节。 包括 mipmap 的大小为 16384*16384*2048 的 Texture2DArray 将需要约 85MB 的空间才能在页表中完全填充此内存。 考虑到这种情况允许一个平铺资源跨 550 gigapixels (512 GB 内存,在这种情况下) ,这还不错。

实际上,受可用物理内存容量的限制,每次能够映射和引用的位置要少得多,远远达不到完全映射的程度。 但借助磁贴池,应用程序可以选择重复使用磁贴(举个简单的示例,对于图像中的大块黑色区域,可以重复使用“黑色”磁贴),从而有效地将磁贴池(也就是页表映射)当作内存压缩工具使用。

对于所有条目,页表的初始内容为 NULL。 应用程序也不能为表面的内存内容传递初始数据,因为它开始时没有内存支持。

在本节中

主题 说明
创建磁贴池
通过 ID3D11Device::CreateBuffer API 创建磁贴池,方法是在 pDesc 参数指向的 D3D11_BUFFER_DESC 结构的 MiscFlags 成员中传递 D3D11_RESOURCE_MISC_TILE_POOL标志。
磁贴池调整大小
如果使用 ID3D11DeviceContext2::ResizeTilePool API 来扩展磁贴池,则应用程序需要更多工作集来映射到磁贴池中;如果需要较少的空间,请使用 ID3D11DeviceContext2::ResizeTilePool API 来扩大磁贴池。
危险跟踪与磁贴池资源
对于非平铺资源,Direct3D 可以在呈现期间防止某些危险条件,但由于对平铺资源进行危险跟踪处于平铺级别,因此在渲染平铺资源期间跟踪危险条件可能过于昂贵。

创建平铺资源