Sparse resources helped my GPU-driven renderer memory usage
18 hours ago
- GPU驱动的渲染需要高效管理持久化GPU缓冲区,这些缓冲区的大小可能从几KiB到多GiB不等;重新分配策略和子分配至关重要。
- 可增长或收缩的缓冲区会导致内存峰值,需要数据复制,可能使引用地址失效,并遭受外部碎片问题,通常需要进行碎片整理。
- 具有固定最大容量的静态缓冲区对于小型有界数据避免了重新分配和碎片问题,但当峰值使用远超典型使用时会浪费内存。
- 基于块的分配(固定大小的块)减少了峰值内存使用并提供稳定的地址,但失去了连续的地址空间,使访问复杂化;在没有稀疏资源的情况下,这是一个可行的选择。
- 使用类似VirtualAlloc模式的CPU风格虚拟内存在性能上优于静态和块方法:它提供稳定的指针、连续的地址空间,并且只提交所需的物理内存。
- 稀疏资源(D3D12中的保留资源)提供了GPU侧的虚拟内存模型:它们提供带有64 KiB页面的虚拟地址空间,物理内存通过UpdateTileMappings进行映射,支持部分驻留。
- 稀疏资源的映射和取消映射通过队列操作(UpdateTileMappings)完成,这些操作必须与GPU工作同步;需要CPU-only映射,并且现代驱动程序上的性能已显著提高。
- 稀疏资源无需重新分配即可实现持久内存,通过取消提交未使用的页面来降低物理成本,并为流式系统提供稳定的指针,消除了重定位工作。
- 一个实际应用是分箱:可以使用预定义的虚拟地址范围(例如,用于网格类型)结合稀疏映射来控制物理内存使用,同时保持单个缓冲区,尽管需要CPU-GPU协调来计数。
- 对于平均使用和峰值使用之间差距较大的大型持久缓冲区,推荐使用稀疏资源;对于小型缓冲区,更简单的放置式分配更可取。
- 挑战包括页面粒度(64 KiB)、在NVIDIA上使用小页面可能出现的性能问题,以及需要仔细同步和CPU端管理。