正如我的问题标题所说,我希望每帧都有更新纹理.
我有一个想法:VkImage使用波纹管配置创建一个纹理缓冲区:
initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED
usage= VK_IMAGE_USAGE_SAMPLED_BIT
它的内存类型是 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
VkImage(使用vkMapMemory). VkImage布局从更改VK_IMAGE_LAYOUT_PREINITIALIZED为VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL. 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渲染循环
VkImage的UNDEFINED第1帧到第N帧(又名渲染循环)
GENERALVkFence)这是一个天真的实现,但应该足够普通的业余爱好者使用.
可以实现双缓冲访问 - 例如VkBuffer用于CPU访问,以及VkImage用于GPU访问的访问.并且VkCmdCopy*必须为数据切换完成.
它并不比上述方法复杂得多,并且可以带来一些性能优势(如果您需要在项目阶段使用它们).您通常希望将资源放在设备本地内存中,这通常也不是主机可见的.
它会像:
berfore渲染循环
VkBuffer b使用内存UNDEFINED支持创建HOST_VISIBLE并映射它VkImage i与UNDEFINED后盾DEVICE_LOCAL内存i和之间准备同步原语b:例如,如果传输在同一队列中,则可以使用两个信号量或事件或障碍第1帧到第N帧(又名渲染循环)
操作上b和i可以非常分离(甚至可以在不同的队列上),因此:
用于b:
b到GENERALVkFence或vkQueueIdle)b到TRANSFERi不使用(可能在等待VkSemaphore)i到TRANSFERvkCmdCopy*从b到ii(可能发出信号VkSemaphore)(第2帧的栅栏和第6帧的信号量必须预先发信号或跳过第一帧才能工作)
用于i:
i可以免费使用(可能等待a VkSemaphore)i到任何需要i(可能发出信号VkSemaphore)你这里有很多问题。
第一的:
创建一个 VkImage 作为纹理缓冲区
没有这样的事。OpenGL 缓冲区纹理的等价物是 Vulkan缓冲区视图。这不使用VkImage任何类型的。VkBufferView没有图像布局。
其次,假设您正在使用VkImage某种类型的工具,您已经认识到布局问题。除非纹理位于布局中GENERAL(除其他外),否则您无法修改纹理背后的内存。因此,您必须强制转换到该状态,等待转换命令实际完成执行,然后进行修改。
第三,Vulkan 的执行是异步的,与 OpenGL 不同,它不会向您隐藏这一点。当您想要更改相关图像时,着色器仍可以访问该图像。所以通常,你需要对这些东西进行双缓冲。
在第 1 帧上,设置图像 1 的数据,然后用它进行渲染。在第 2 帧上,您设置图像 2 的数据,然后用它进行渲染。在第 3 帧上,您覆盖图像 1 的数据(使用事件确保 GPU 实际上已完成第 1 帧)。
或者,您可以通过使用暂存缓冲区来使用双缓冲,而无需 CPU 等待。也就是说,您不是直接写入图像,而是写入主机可见内存。然后,您使用vkCmdCopyBufferToImage命令将该数据复制到图像中。这样,CPU 就不必在发送数据之前等待事件或栅栏来确保图像位于布局中GENERAL。
顺便说一句,Vulkan 不是 OpenGL。内存映射始终是持久的;如果您要每帧都映射一块内存,则没有理由取消映射它。
| 归档时间: |
|
| 查看次数: |
3185 次 |
| 最近记录: |