如何更新vulkan中每一帧的纹理?

lib*_*bei 5 vulkan

正如我的问题标题所说,我希望每帧都有更新纹理.

我有一个想法:VkImage使用波纹管配置创建一个纹理缓冲区:
initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED
usage= VK_IMAGE_USAGE_SAMPLED_BIT

它的内存类型是 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT

在绘制循环中:

第一帧:

  1. 将texure数据映射到VkImage(使用vkMapMemory).
  2. VkImage布局从更改VK_IMAGE_LAYOUT_PREINITIALIZEDVK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL.
  3. 用它VkImage作为纹理缓冲区.

第二帧:

布局将VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL在第一帧之后,我可以VkImage直接将下一个纹理数据映射到此而不更改它的布局吗?如果我不能这样做,我可以将这个布局更改VkImage为?

在vkspec 11.4中它说:

转换中使用的新布局不得为VK_IMAGE_LAYOUT_UNDEFINED或VK_IMAGE_LAYOUT_PREINITIALIZED

所以,我无法改变布局_PREINITIALIZED.
任何帮助将不胜感激.

krO*_*oze 10

对于您的情况,您不需要LAYOUT_PREINITIALIZED.这只会使你的代码复杂化(迫使你为第一帧提供单独的代码).

LAYOUT_PREINITIALIZED确实是一个非常特殊的布局,仅用于图像生命的开始.它对静态纹理更有用.

从需要从CPU端写入映像时开始LAYOUT_UNDEFINED并使用LAYOUT_GENERAL.

我提议这个方案:

berfore渲染循环

  1. 创建你VkImageUNDEFINED

第1帧到第N帧(又名渲染循环)

  1. 过渡图像到 GENERAL
  2. 同步(可能与VkFence)
  3. 映射图像,写入,取消映射(weell,映射和解映射可能在渲染循环之外)
  4. 同步(可能隐式完成)
  5. 将图像转换为您接下来需要的任何布局
  6. 做你的渲染和诸如此类的东西
  7. 从1开始.

这是一个天真的实现,但应该足够普通的业余爱好者使用.

可以实现双缓冲访问 - 例如VkBuffer用于CPU访问,以及VkImage用于GPU访问的访问.并且VkCmdCopy*必须为数据切换完成.

它并不比上述方法复杂得多,并且可以带来一些性能优势(如果您需要在项目阶段使用它们).您通常希望将资源放在设备本地内存中,这通常也不是主机可见的.

它会像:

berfore渲染循环

  1. VkBuffer b使用内存UNDEFINED支持创建HOST_VISIBLE并映射它
  2. 创建VkImage iUNDEFINED后盾DEVICE_LOCAL内存
  3. i和之间准备同步原语b:例如,如果传输在同一队列中,则可以使用两个信号量或事件或障碍

第1帧到第N帧(又名渲染循环)

操作上bi可以非常分离(甚至可以在不同的队列上),因此:

用于b:

  1. 过渡bGENERAL
  2. 与CPU同步(可能等待VkFencevkQueueIdle)
  3. 无效(如果不相干),写入,刷新(如果不相干)
  4. 与GPU同步(如果在队列提交之前,则隐式完成)
  5. 过渡bTRANSFER
  6. 同步以确保i不使用(可能在等待VkSemaphore)
  7. 过渡iTRANSFER
  8. 不要vkCmdCopy*bi
  9. 同步以使我知道我已完成i(可能发出信号VkSemaphore)
  10. 从1开始.

(第2帧的栅栏和第6帧的信号量必须预先发信号或跳过第一帧才能工作)

用于i:

  1. 同步以确保i可以免费使用(可能等待a VkSemaphore)
  2. 过渡i到任何需要
  3. 做你的渲染
  4. 同步以使我知道我已完成i(可能发出信号VkSemaphore)
  5. 从1开始.


Nic*_*las 5

你这里有很多问题。

第一的:

创建一个 VkImage 作为纹理缓冲区

没有这样的事。OpenGL 缓冲区纹理的等价物是 Vulkan缓冲区视图。这不使用VkImage任何类型的。VkBufferView没有图像布局。

其次,假设您正在使用VkImage某种类型的工具,您已经认识到布局问题。除非纹理位于布局中GENERAL(除其他外),否则您无法修改纹理背后的内存。因此,您必须强制转换到该状态,等待转换命令实际完成执行,然后进行修改。

第三,Vulkan 的执行是异步的,与 OpenGL 不同,它不会向您隐藏这一点。当您想要更改相关图像时,着色器仍可以访问该图像。所以通常,你需要对这些东西进行双缓冲。

在第 1 帧上,设置图像 1 的数据,然后用它进行渲染。在第 2 帧上,您设置图像 2 的数据,然后用它进行渲染。在第 3 帧上,您覆盖图像 1 的数据(使用事件确保 GPU 实际上已完成第 1 帧)。

或者,您可以通过使用暂存缓冲区来使用双缓冲,而无需 CPU 等待。也就是说,您不是直接写入图像,而是写入主机可见内存。然后,您使用vkCmdCopyBufferToImage命令将该数据复制到图像中。这样,CPU 就不必在发送数据之前等待事件或栅栏来确保图像位于布局中GENERAL

顺便说一句,Vulkan 不是 OpenGL。内存映射始终是持久的;如果您要每帧都映射一块内存,则没有理由取消映射它。