虚拟纹理内存池

介绍虚拟纹理物理内存池的GPU内存分配。

Choose your operating system:

Windows

macOS

Linux

虚拟纹理系统主要有两种GPU内存分配方式:页表内存(Page Table Memory)和物理内存池(Physical Memory Pool)。

  • 页表内存(Page Table Memory) 提供了从纹理坐标间接访问纹理数据的方法,可以按需分配。它会随着时间推移不断增大;除非释放其中的全部内容,否则无法从内存中释放。用户无法控制该存储类型。

  • 物理内存池(Physical Memory Pool) 包含了当前驻留的纹理数据,并且由多个独立的池构成。虚拟纹理系统所查看的每一种纹理格式都有对应的内存池。对应格式的虚拟纹理进行第一次实例化时会分配内存池。每个内存池都具有固定的大小,不会逐渐增大。用户可以控制每个池的大小。

本文档将介绍如何定义和调试虚拟纹理物理内存池。

理解物理内存池的行为

物理内存池都是由页组成的。每一页都包含了一个虚拟纹理区块的数据。内存池的行为类似于以使用时间远近为基础的缓存。当虚拟纹理系统请求区块时,它就会被流送或渲染到内存池里的一个可用页中。如果没有可用页,那么包含使用时间最久远的区块的页就会被去除,为新区块腾出空间。

如果视图中包含的可见虚拟纹理过多,无法存储到虚拟纹理内存池中,系统就无法正确渲染视图。在这些情况下,你必须调整虚拟纹理内存池的大小,从而满足数据使用量要求。

 配置物理内存池

虚拟纹理的 内存池大小 可以在 BaseEngine.ini 配置文件中设置。

内存池可以根据 纹理格式组(Texture Format Group)区块大小(Tile Size) 进行设置。你也可以在项目中设置自己的[配置文件](),从而覆盖各个项目或平台。

虚拟纹理内存池的所有配置设置都可以在"/Script/Engine.VirtualTexturePoolConfig"条目下找到。

以下示例能够将所有包含BC7纹理的虚拟纹理内存池的大小设置为100MB。大小仅为近似大小,系统实际分配的大小为低于100MB、容纳页数为整数的最大平方数。

[/Script/Engine.VirtualTexturePoolConfig]
+Pools=(Formats=(PF_BC7), SizeInMegabyte=100)

在使用默认池大小的配置中,Formats不需要有对应的输入。在无纹理组格式的情况下定义一个池就可以超过默认值。

[/Script/Engine.VirtualTexturePoolConfig]
+Pools=(SizeInMegabyte=64)

有些池包含了多层,每层都有自己的格式。大部分运行时虚拟纹理设置都是这个情况。此时,配置文件需要输入对应的层格式。

例如,一个在材质中使用 基础颜色,法线,粗糙度,高光 的运行时虚拟纹理可以如下设置:

[/Script/Engine.VirtualTexturePoolConfig]
+Pools=(Formats=(PF_DXT5, PF_DXT5), SizeInMegabyte=128)

所有内存池配置输入都可以包含额外设置,包括:

内存池配置设置

说明

bAllowSizeScale

允许通过 r.VT.PoolSizeScale.Group <X> 扩展控制台变量,对内存池大小应用额外的扩展系数。

ScalabilityGroup

设置`bAllowSizeScale`使用的群组索引(0-2)。拥有多个群组集合为每个内存池设置不同的扩展性。

bEnableResidencyMipMapBias

允许在内存池超额时,对虚拟纹理应用MipMap偏差。

物理内存池驻留

虚拟纹理内存池的当前使用情况被称为 驻留(Residency)。当内存池的所有页都分配了当前可见的区块,驻留即为100%。

驻留为100%时,内存池即为超额(oversubscribe),并会开始删除可视区块的数据。由于纹理数据会在内存中重复加载与删除,这将导致意外的输入输出和屏幕闪烁。

你可以启用界面通知,在内存池超额时显示通知。该通知可使用控制台命令 r.VT.Residency.Notify 1 启用。

虚拟纹理池超额通知

该警告表明,你需要在配置文件中扩大内存池大小,或者更改虚拟纹理或材质。请查看下文部分,了解如何解决该类问题通知。

 驻留MipMap偏差

如果启用 bEnableResidencyMipMapBias 配置内存池,就会在超额时设置MipMap偏差来降低驻留。这能避免出现意外的输入输出和屏幕闪烁,但渲染的虚拟纹理分辨率会降低。

该设置适合在驻留鲜少超额、不愿为这种罕见情况分配内存的时候使用。超额的屏幕信息会包含应用的MipMap偏差。

驻留产生的MipMap偏差是全局性的。所有物理内存池的最大当前偏差会应用于 所有 虚拟纹理采样。

物理内存池HUD显示

设置合理的内存池大小是监控驻留、减少超额情况的关键。你可以使用屏幕抬头显示(HUD),展示每个虚拟纹理物理内存池当前的驻留。

该功能更可通过 r.VT.Residency.Show 1 启用。

虚拟纹理池驻留水平编辑器视图

虚拟纹理物理内存池HUD会显示每个纹理格式的当前驻留及其分配的内存。

虚拟纹理池驻留图表

屏幕上的每个图表都代表一个虚拟纹理物理内存池。总共有三种线状图表:

  • 红色 表示当前池驻留为0-100%。

  • 黄色 表示固定池占用为0-100%。

    • 这表示的是标记为锁定的页占用。通常每个虚拟纹理都会锁定一页。加载大量虚拟纹理资产时,即使虚拟纹理不可见,也会降低可用的池空间。

  • 绿色 表示应用MipMap偏差将驻留控制在100%以下。

调试物理内存池驻留

当虚拟纹理内存池超额时,可以从以下领域开始调试并检查内容。

内存池大小

对于虚拟纹理内存池的大小,你需要检查以下方面:

  • 检查内存池大小是否足够大,能够容纳预期的全部虚拟纹理数据。

    • 页规模越大,内存池就应当越大。例如,一个纹理格式为 PF_A32B32G32R32F 的内存池的内存要求就比纹理格式为 PF_DXT1 的内存池更大。同样地,包含更多层数的内存池也需要更大的内存。

  • 渲染的输出分辨率越高,内存池就应当越大。

    • 高分辨率输出通常需要更高分辨率的mip区块。

  • 区块大小越大,内存池就应当越大。

    • 流送虚拟纹理的默认区块大小为128纹素。然而,该值可以被覆盖。

    • 运行时虚拟纹理的区块大小最大为1024纹素。较大的区块大小可能会浪费内存池的空间。

 超额

超额(Oversubscription)的一项主要原因是在对虚拟纹理进行采样时应用了负mip偏差。系统性地对更高分辨率的mip进行采样会需要更多池内存。负mip偏差通常是由于在材质图表的纹理采样节点中专门设置了mip等级或偏差而产生的。

超额也可能因为意外原因产生,例如对零渐变的纹理进行采样时,三角形或网格体的UV不变而产生超额。以下材质图表片段就是一个例子。对运行时虚拟纹理采样节点的"忽略输入世界位置"设置应用Mip值就能解决这个问题。

虚拟纹理池超额材质示例

使用控制台命令 r.VT.DumpPoolUsage,就能协助定位由于mip偏差或其他问题而占用过多池空间的纹理。该命令会转储每个内存池中虚拟纹理资产当前分配的页数。转储文件会根据页数排序,因此需要检查第一条输入,确定其是否合理。

需要注意的是,在以下转储文件中,第一条输出明显高出其他输入。因此必须找到引用了 T_Ground_Sand_F_basecolor_CANYON 的材质,检查是否存在mip偏差问题。

PhysicaPool: [0] DXT1 (136x136):
    T_Ground_Sand_F_basecolor_CANYON 1912
    T_Rock_Quarry_Y_RAOD 418
    ubulehofw_8K_Albedo 324
    pcciQ_4K_Albedo 248
    T_Rock_Cliff_D_RAOD 187
    noise_directional_3 115
    T_column_260_B_W 97
    T_column_260_B_goldA_RMAOO 97
    T_column_260_B_goldA_C 96
本文基于此前的虚幻引擎版本编写,未针对当前的虚幻引擎5.0版本更新过。