内存管理策略

Direct3D 12 的内存管理器对于 UMA 或离散(非 UMA)适配器的所有不同支持层,以及 GPU 适配器之间的大量体系结构差异,可能会非常复杂。

本部分所述的 Direct3D 12 内存管理的建议策略是“分类、预算和流”。

资源类型

自 Direct3D 9 起,“已提交资源”的基本概念(同时创建托管物理内存中初始化的虚拟地址空间和物理地址空间)一直在周围,尽管 Direct3D 12 中的虚拟寻址和物理寻址可以分离,以允许应用仔细管理物理内存。

除了已提交的资源,Direct3D 12 的堆构造还支持两种类型的资源:“放置”和“保留”。 在 Direct3D 11 中,“保留”资源称为“平铺资源”。

预留资源不同于预留资源中具有其自己的唯一 GPU 虚拟地址空间的资源。 这样就可以提前分配 VA 空间,然后允许将 VA 页映射到堆的某些部分,应用程序会实时重新配置排列。 VA 空间是连续的,可以稀疏地映射到。

可以使用 API 调用(如 UpdateTileMappings)对堆中的区域进行引用,并且可以通过动态更新页表来让应用驻留这些资源。 当 VA 范围映射到 NULL 或非常驻堆时,该部分资源被视为非驻留。 将 VA 范围映射到常驻堆时,该部分资源被视为驻留。 堆是在创建时驻留的。

放置的资源是一个更简单的设计,只是指向堆的特定区域的指针(例如,5Mb 堆中纹理的 1Mb 区域)。 别名屏障允许使用重叠放置的资源(请参阅 CreatePlacedResourceResourceBarrier)。

预留资源在所有 Direct3D 12 硬件上都不可用,放置的资源是合理的回退,但放置的资源必须连续且不能部分驻留。

内存预算

在 Direct3D 12 中,分配堆时,要创建已提交资源的物理内存方面。 Direct3D 12 中提供了更明确的内存段选择(在视频和系统内存之间进行选择)。 UMA 适配器只有一个内存段,即系统内存。

GPU 不支持页面故障,因此开发人员必须意识到,它们不会过度提交,尤其是系统表示只有 1Gb 的系统内存。 如果应用通过提交执行,则 OS 会根据进程对物理内存的需求使用更粗粒度的进程计划。 计划程序将冻结前台进程,并实质上对其中的某些进程进行分页,以便对想要运行的后台进程进行分页。 可用物理内存可能会因用户在后台执行的作(例如运行浏览器或观看视频)而有很大差异。

内存预算 API QueryVideoMemoryInfo。 对于离散适配器“local”是视频内存,“非本地”是系统内存。 对于 UMA 适配器,非本地适配器始终为零。 一个设计问题是引擎是同时管理预算还是只管理本地预算。 仅管理本地预算更简单,但有一些注意事项:例如,有一个最大本地预算为 1Gb,那么所有堆都将来自 UMA 系统中的 1Gb,并且系统内存没有溢出(显然,因为没有)。

由于应用程序的 Direct3D11 托管内存,因此未使用的资源基本上会分页。

选择最合适的资源维度。 考虑资源的大小是否适合应用程序实际运行的情况。 某些用户可能会在窗口中运行应用程序,或者屏幕分辨率为 800x600。

分类策略

若要在内存绑定方案中有效地管理资源,请考虑将资源分类为以下各项:

分类 例子 对象和 API 功能 管理说明
危急 游戏 UI 命令分配器、命令队列、查询堆、资源和资源堆。 这些元素应进入不可分页/始终提交的内存。
缩放/可选 特定于级别的模型和纹理,交换链,天空框,第一人称玩家角色模型 资源和堆。 提交的资源,但也放置和保留的资源可能同样正常工作。 将内存驻留预算集成到呈现算法中。 选择适当的可用详细信息级别,并按帧重新评估少于一次。 技术包括使用可变大小的资源和交换链缩放。
重新使用的资源 阴影缓冲区、延迟呈现资源、后期处理资源、照明数据缓存 资源和堆。 重叠将资源放置在堆和别名屏障上。 重复使用帧内的大型资源或堆区域,以削减整个帧的要求。 使用帧内内存重用的技术。 在 Direct3D 11 中,应用程序只能重复使用具有相同类型和可能足够大的维度的资源。 Direct3D 12 堆允许重叠的资源更易于重复使用。
流式处理资源 地形、开放世界纹理和几何图形 资源和堆。 自由线程创建、后台 CPU 线程和后台复制命令队列和列表。 部分驻留,通常基于可见性(使用视图-frustum 或基于距离的评估),并重新评估驻留需要每个帧。
当 GPU 适配器支持堆中的保留资源时,可以使用每磁贴部分驻留管理和帧间重用的技术。
使用帧间内存重复使用的技术,可以完成部分子资源驻留,但效果较差。 具有堆的放置资源应能够更快地回收,但提交的资源可用作回退。

对于大部分工作,应用程序吸引到流式处理资源越多,它们就越会利用放置和保留的资源,从而最大限度地利用这四种分类之间的内存重用。 应用程序流越多,预算越多,带宽优先级就越高。

通常,使用 Direct3D 12 图形引擎需要遵循更加多样化和动态的预算,并且比过去更严格地执行它。 最佳应用程序会将所有四个类别定位到提供给流程的预算中,将游戏游戏从后台移动应用扩展到全屏离散预算。 但是,许多应用程序可能从过多的关键类别类型资源开始而苦苦挣扎。 已启用 Direct3D 11 的资源可以匿名创建并占用关键状态,而不会影响性能。 但是,对于 Direct3D 12,开发人员必须努力在整个引擎和中间件中搜索随机创建的资源,并将其重新分配给其他类别之一。

其他问题领域包括中间件组件、用户控件和帧内流式处理。 中间件组件可能不会公开到预算中,也不必紧密协作。 中间件组件可能会将功能公开为呈现技术;应用程序可以依赖于公开中间件和引擎设置。 开发人员可以依赖 Direct3D 11 执行分页并实现正确的帧速率。 在某些情况下,Direct3D 11 应用程序可能已分页和传出每个帧的资源内容;并导致用户可接受的帧速率。 大多数引擎仅将资源数据作为后台活动进行流式处理,其中没有正常回退到高优先级帧内流式处理。 要求引擎实现,这将侵蚀他们正在寻求的一些 CPU 开销提升,方法是迁移到 Direct3D 12。 引擎开发人员可以考虑将其帧分阶段,为可重用的资源提供更多机会:并可能与中间件供应商合作,以支持放置的资源和堆以重复使用帧内内存。

CreateCommittedResource

CreateReservedResource

Direct3D 12 编程指南

内存管理

资源绑定