UBOs/SSBO如何与Vulkan的着色器内存绑定不同?

Bar*_*icz 14 opengl vulkan

Imagination网站上文章中,我读过以下段落:

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

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

它与使用统一缓冲区之间有什么区别吗?它们也是明确分配的,可以携带任意数据.由于Uniform Buffers的大小非常有限,因此Shader Storage Buffers可能是一个更好的类比.

use*_*016 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);
Run Code Online (Sandbox Code Playgroud)

  • @datenwolf:我并没有提到类型安全性的损失和状态验证的损失.如果您尝试在不一致的状态下使用资源,那么在GL中您可以获得即时反馈,而在新的低级API浪潮中并非如此.他们会让你比GL更容易调用未定义的行为.如果你将Vulkan适用于已经实现了自己的验证和命令调度的引擎,Vulkan将会运行良好; 这是重点,不要重复那项工作. (3认同)
  • 在这里作者,将一些内存绑定到插槽是vulkan中的命令:vkCmdBindDescriptorSets().虽然可能是幕后的指针. (2认同)