没有任何秘密的 API:Vulkan* 简介第 5 部分

教程 5:分期资源 – 在缓冲区之间复制数据

本部分教程将重点关注如何改进性能。同时,我们将为下一篇教程做准备,下一篇教程将介绍图像与描述符(着色器资源)借助收集的信息,您将更轻松地掌握下一部分,最大限度发挥显卡硬件的性能。

什么是“分期资源”或“临时缓冲区”?它们指的是中间或临时资源,用于将数据从应用 (CPU) 传输到显卡内存 (GPU)。我们需要通过他们提升应用性能

在教程的第 4 部分,我们学习了如何使用缓冲区,将其绑定至主机可见内存,映射该内存,并将数据从 CPU 传输到 GPU。这个方法简单便捷,但是我们需要了解显卡内存的主机可见部分并不是最高效的部分。相比应用无法直接访问的内存(应用无法映射),它们的速度通常缓慢得多。这导致我们的应用以次优的方式执行。

解决该问题的办法是渲染过程中的所有资源始终使用设备本地内存。但是由于应用无法访问设备本地内存,我们不能将数据从 CPU 直接传输到内存。这就是我们需要中间或分期资源的原因。

在本部分教程,我们将借助顶点属性数据将缓冲区绑定至设备本地内存。我们将使用临时缓冲区协调从 CPU 到顶点缓冲区的数据传输。

再次声明,仅介绍本教程和上一教程(第 4 部分)的不同之处。

创建渲染资源

此次,我将渲染资源创建移至代码的开头部分。稍后,我们需要记录与提交一个命令缓冲区,以将数据从分期资源传输至顶点缓冲区。我还重构了渲染资源创建代码,以消除多个循环,将它们替换为单个循环。在这个循环中,我们创建构成虚拟帧的所有资源。

bool Tutorial05::CreateRenderingResources() {
if( !CreateCommandPool( GetGraphicsQueue().FamilyIndex, &Vulkan.CommandPool ) ) {
return false;
}

for( size_t i = 0; i < Vulkan.RenderingResources.size(); ++i ) {
if( !AllocateCommandBuffers( Vulkan.CommandPool, 1, &Vulkan.RenderingResources[i].CommandBuffer ) ) {
return false;
}

if( !CreateSemaphore( &Vulkan.RenderingResources[i].ImageAvailableSemaphore ) ) {
  return false;
}

if( !CreateSemaphore( &Vulkan.RenderingResources[i].FinishedRenderingSemaphore ) ) {
  return false;
}

if( !CreateFence( VK_FENCE_CREATE_SIGNALED_BIT, &Vulkan.RenderingResources[i].Fence ) ) {
  return false;


2.Tutorial05.cpp, function CreateBuffer()

将代码打包至一个 CreateBuffer() 函数,该函数接收缓冲区的使用、大小和所需的内存属性。为了创建缓冲区,需要准备类型变量 VkBufferCreateInfo。该结构包含以下字段:

  • sType – 标准结构类型。此处应等于

  • VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO。

  • pNext – 为扩展功能预留的指示器。
  • flags – 描述缓冲区其他属性的参数。现在,我们只能指定缓冲区可通过稀疏内存备份。
  • size – 缓冲区大小(字节)。
  • usage – 显示缓冲区既定用途的位字段。
  • sharingMode – 队列共享模式。
  • queueFamilyIndexCount – 并发共享模式下访问缓冲区的各类队列家族数量。
  • pQueueFamilyIndices – 使用并发共享模式时,访问缓冲区的所有队列家族的索引阵列。

目前,我们对绑定稀疏内存不感兴趣。我们不希望在不同设备队列之间共享缓冲区,因此,sharingMode、queueFamilyIndexCount 和 pQueueFamilyIndices 参数与本文无关。size 和 usage 是最重要的参数。我们不能将缓冲区用于缓冲器创建期间未指定的目的。最终,我们需要创建一个足够容纳数据的缓冲区。

为了创建缓冲区,需要调用 vkCreateBuffer() 函数,调用成功后,缓冲区句柄被保存在我们提供地址的变量中。但是创建缓冲区远远不够,创建的缓冲区没有存储功能。我们需要将内存对象(或部分内存对象)绑定至缓冲区,以支持存储。如果没有内存对象,需要分配一个内存对象。

每个缓冲区的 usage 可能包含不同的内存要求,当我们想要分配内存对象并将其绑定到缓冲区时,便涉及到这些要求。以下代码示例可将一个内存对象分配至特定缓冲区:

查看原文


了解更多相关内容,请关注CSDN英特尔开发专区!

你可能感兴趣的:(没有任何秘密的 API:Vulkan* 简介第 5 部分)