优化视频内存和系统内存之间的传输

Optimizing transfer between video memory and system memory

前段时间,我正在尝试使用 GLSL 在 GPU 上创建重型声音合成器。合成器能够在超过 256 个同步语音上生成非常复杂的声音。 在CPU上,我做梦都不敢想得到这样的表现。

(简化解释)为了生成声音,我有一个 NxV 大小的浮点纹理。 N = 样本数,V = 声音数。合成着色器为每个纹素生成值。

然后第二个着色器会将所有声音混合在一个 16 位有符号整数 1D 纹理(或声卡需要的任何格式)中。使用像素缓冲区将最终纹理尽快复制到系统内存,然后将其发送到声卡。

对于声音,我使用超低延迟 Windows Core Audio。

我编写了一个 MIDI 接口,可以在连接到 PC 的 midi 键盘上播放,并且在使用 Intel GPU 时完美运行,延迟仅为 3ms(N = 132 个样本,比所需的 15-20ms N=600-900 个样本)。但是当使用 NVidia GPU 能够支持更繁重的计算时,延迟要大得多(>35ms N=>1500 个样本)。

我了解原因是使用Intel GPU时,渲染是直接在系统内存上完成的,复制纹理非常快,但是当使用NVidia GPU时,渲染是在显存中完成并复制从视频内存到系统内存是一个瓶颈,即使它应该传输大约 4KB 的音频数据(这甚至不接近硬件应该能够达到的 6GB/s)。

有什么办法可以改善吗?例如,是否可以让 NVidia GPU 直接渲染系统内存(以可接受的速度),或者他们在 OpenCL 中谈论的那些著名的共享内存是什么? OpenCL 会改善这个吗? (我没有使用 OpenCL 的经验)

有时 GPU 写入主内存比 CPU 读取 VRAM 更快。你这样做的方法是使用 PBO,看看 here。您必须提示 PBO 存储在主内存中。这可能有帮助,也可能没有帮助,具体取决于硬件架构。

OpenCL 并非天生就更快。如果您在 OpenGL 中有一个干净的实现,您很可能不会通过 OpenCL 实现获得速度提升。但是有些事情您可以在 OpenCL 中完成,而在 OpenGL 中无法完成。

如果您仍然发现带宽是您的瓶颈,还有一些其他建议:

  1. 您是否尽可能避免阻塞?当您在一个线程中使用 GL 调用读取纹理时,您是否也在另一个线程中处理最后读取的纹理,诸如此类。请注意,对 glGetTexImage 的调用是异步的,不会阻塞。只有在调用 glMapBuffer 之前,您才会阻塞并知道传输已完成。

  2. 您是否正在尽可能少地转移,转移次数最少。

  3. 有些压缩纹理格式是有损的,但也许适合您的需要?