14

Imagination 网站上的文章中,我阅读了以下段落:

例如,glUniform*()Vulkan 中没有等效的入口点;相反,写入 GPU 内存是将数据传递给着色器的唯一方法。

当您调用glUniform*()时,OpenGL ES 驱动程序通常需要分配一个驱动程序管理的缓冲区并将数据复制到其中,其管理会产生 CPU 开销。在 Vulkan 中,您只需映射内存地址并直接写入该内存位置。

那和使用统一缓冲区有什么区别吗?它们也被明确分配并且可以携带任意数据。由于统一缓冲区的大小非常有限,因此着色器存储缓冲区可能是一个更好的类比。

4

1 回答 1

12

据我了解,这并不glUniform*()具体:glUniform*()仅是文章作者用来说明 Vulkan 在主机和 GPU 之间通信方面的工作方式的示例。

当您调用glUniform*()时,OpenGL ES 驱动程序通常需要分配一个驱动程序管理的缓冲区并将数据复制到其中,其管理会产生 CPU 开销。

在这种情况下,当用户调用glUniform*()一些数据时,该数据首先被复制到 OpenGL 实现所拥有的缓冲区中。这个缓冲区可能是固定的,然后驱动程序可以使用它通过 DMA 将数据传输到设备。这是两个步骤:

  1. 将用户数据复制到驱动缓冲区;
  2. 通过 DMA 将缓冲区内容传输到 GPU。

在 Vulkan 中,您只需映射内存地址并直接写入该内存位置。

在这种情况下,没有用户数据的中间副本。您要求 Vulkan 将一个区域映射到您直接写入的主机的虚拟地址空间。数据通过 DMA 以对用户完全透明的方式到达设备。

从性能的角度来看,好处是显而易见的:零拷贝。这也意味着 Vulkan 实现可以更简单,因为它不需要管理中间缓冲区。

由于规格尚未发布,这是一个虚构的示例,说明它的外观:

// Assume Lights is some kind of handle to your buffer/data
float4* lights = vkMap(Lights);

for (int i = 0; i < light_count; ++i) {
    // Goes directly to the device
    lights[i] = make_light(/* stuff */);
}

vkUnmap(lights);
于 2015-03-03T16:02:37.717 回答