Vulkan 描述符绑定
Vulkan descriptor binding
在我的 vulkan 应用程序中,当所有网格都使用相同的纹理时,我曾经像这样绘制网格
Updatedescriptorsets(texture)
Command buffer record
{
For each mesh
Bind transformubo
Draw mesh
}
但现在我希望每个网格都有独特的纹理,所以我尝试了这个
Command buffer record
{
For each mesh
Bind transformubo
Updatedescriptorsets (textures[meshindex])
Draw mesh
}
但是它给出了一个错误,说 descriptorset 被销毁或更新。我查看了 vulkan 文档,发现我无法在命令缓冲区记录期间更新描述符集。那么我怎样才能让每个网格都有一个独特的纹理呢?
vkUpdateDescriptorSets
未与任何内容同步。因此,您无法更新正在使用的描述符集。您必须确保所有使用相关描述符集的渲染操作都已完成,并且没有任何命令被放置在使用相关描述符集的命令缓冲区中。
它基本上就像一个全局变量;你不能让人们在没有某种同步的情况下从多个线程访问全局变量。并且 Vulkan 不同步对描述符集的访问。
有几种方法可以解决这个问题。您可以为每个对象提供自己的描述符集。这通常是通过使频繁更改的描述符集数据具有比不频繁更改的数据更高的索引来完成的。这样,您就不会更改每个对象的每个描述符,而只会更改每个对象的描述符。
您可以使用推送常量数据来索引大型 tables/array 纹理。所以描述符集将有一个纹理数组或一个纹理数组(如果你有纹理数组的动态索引)。推送常量将提供一个索引,着色器使用该索引从纹理数组 texture/array 中获取特定对象的纹理。这使得频繁的更改相当便宜,并且相同的索引也可用于为每个对象提供自己的转换矩阵(通过提取到矩阵数组中)。
如果您有可用的扩展 VK_KHR_push_descriptor,那么您可以将对描述符的更改直接集成到命令缓冲区中。这比推送常量机制好多少当然取决于实现。
如果您更新描述符集,则该描述符集绑定到的所有命令缓冲区都将失效。 GPU 无法提交或执行无效的命令缓冲区。
您基本上需要做的是在绑定之前更新描述符集。
之所以存在这种奇怪的行为,是因为在 vkCmdBindDescriptorSets
中,一些实现采用 vulkan 描述符集,将其转换为本机描述符表,然后将其存储在命令缓冲区中。因此,如果您在 vkCmdBindDescriptorSets
之后更新描述符集,命令缓冲区将看到陈旧数据。 VK_EXT_descriptor_indexing
扩展在某些情况下放宽了此行为。
在我的 vulkan 应用程序中,当所有网格都使用相同的纹理时,我曾经像这样绘制网格
Updatedescriptorsets(texture)
Command buffer record
{
For each mesh
Bind transformubo
Draw mesh
}
但现在我希望每个网格都有独特的纹理,所以我尝试了这个
Command buffer record
{
For each mesh
Bind transformubo
Updatedescriptorsets (textures[meshindex])
Draw mesh
}
但是它给出了一个错误,说 descriptorset 被销毁或更新。我查看了 vulkan 文档,发现我无法在命令缓冲区记录期间更新描述符集。那么我怎样才能让每个网格都有一个独特的纹理呢?
vkUpdateDescriptorSets
未与任何内容同步。因此,您无法更新正在使用的描述符集。您必须确保所有使用相关描述符集的渲染操作都已完成,并且没有任何命令被放置在使用相关描述符集的命令缓冲区中。
它基本上就像一个全局变量;你不能让人们在没有某种同步的情况下从多个线程访问全局变量。并且 Vulkan 不同步对描述符集的访问。
有几种方法可以解决这个问题。您可以为每个对象提供自己的描述符集。这通常是通过使频繁更改的描述符集数据具有比不频繁更改的数据更高的索引来完成的。这样,您就不会更改每个对象的每个描述符,而只会更改每个对象的描述符。
您可以使用推送常量数据来索引大型 tables/array 纹理。所以描述符集将有一个纹理数组或一个纹理数组(如果你有纹理数组的动态索引)。推送常量将提供一个索引,着色器使用该索引从纹理数组 texture/array 中获取特定对象的纹理。这使得频繁的更改相当便宜,并且相同的索引也可用于为每个对象提供自己的转换矩阵(通过提取到矩阵数组中)。
如果您有可用的扩展 VK_KHR_push_descriptor,那么您可以将对描述符的更改直接集成到命令缓冲区中。这比推送常量机制好多少当然取决于实现。
如果您更新描述符集,则该描述符集绑定到的所有命令缓冲区都将失效。 GPU 无法提交或执行无效的命令缓冲区。
您基本上需要做的是在绑定之前更新描述符集。
之所以存在这种奇怪的行为,是因为在 vkCmdBindDescriptorSets
中,一些实现采用 vulkan 描述符集,将其转换为本机描述符表,然后将其存储在命令缓冲区中。因此,如果您在 vkCmdBindDescriptorSets
之后更新描述符集,命令缓冲区将看到陈旧数据。 VK_EXT_descriptor_indexing
扩展在某些情况下放宽了此行为。