我目前正在研究受全局内存带宽限制的 HLSL 着色器。我需要在每个内存事务中合并尽可能多的内存。根据 NVIDIA 对 CUDA 和 OpenCL 的指导(DirectCompute 文档非常缺乏),计算能力 2.0 的最大内存事务大小为 128 字节,而可访问的最大字为 16 字节。当 warp 中的线程访问的数据落入相同的 128 字节段时,可以合并全局内存访问。考虑到这一点,如果结构大于 16 字节,结构化缓冲区不会对内存合并有害吗?
假设您有两个 float4 的结构,分别称为 A 和 B。您可以访问 A 或 B,但不能在单个内存事务中同时访问在非发散扭曲中发出的指令。内存的布局看起来像 ABABABAB。如果您尝试将连续结构读入共享内存,以这种方式存储数据不会浪费内存带宽吗?例如,您只能访问 A 元素,但硬件会合并内存事务,因此它会读取 128 字节的连续数据,其中一半是 B 元素。从本质上讲,您浪费了一半的内存带宽。像 AAAABBBB 这样存储数据不是更好吗,它是缓冲区结构而不是结构缓冲区?或者这是由 L1 缓存处理的,B 元素被缓存在哪里,以便在下一条指令读取 B 元素时可以更快地访问它们?唯一的其他解决方案是让偶数线程访问 A 元素,而奇数线程访问 B 元素。
如果确实浪费了内存带宽,我不明白为什么有人会使用结构化缓冲区而不是为了方便。希望我解释得足够好,以便有人能理解。我会在 NVIDIA 开发者论坛上问这个问题,但我认为他们仍然失败。当我尝试运行 NVIDIA Nsight 帧分析器时,Visual Studio 不断崩溃,因此很难看出内存带宽如何受到数据存储方式变化的影响。PS,有没有人能够成功运行 NVIDIA Nsight 帧分析器?