关注专栏 写文章
第 7 章. 缓冲区资源,渲染通道,帧缓冲区以及使用 SPIR-V 的着色器

第 7 章. 缓冲区资源,渲染通道,帧缓冲区以及使用 SPIR-V 的着色器

1 人 赞同了该文章

在前一章中,我们了解了 Vulkan 资源类型;我们了解图像资源(VkImage)是什么,以及如何在交换链图像中实现它们。 在本章中,我们将讨论第二种 Vulkan 资源,称为缓冲区资源(VkBuffer),并使用它们来准备一个简单的几何图形缓冲区。

本章还将介绍并实现一个渲染通道 Render Pass 和帧缓冲区 framebuffer。 渲染通道有助于组装一个工作单元。 它定义了附件以及与其关联的子通道(影响一个渲染作业)。 帧缓冲区消费创建的渲染通道并为每个对应的交换链图像创建单帧信息。 帧缓冲区将一组图像视图与 Render Pass 中描述的一组附件相关联。

另外,我们将使用 SPIR-V 在 Vulkan 中实现一个着色器,SPIR-V 是一种用于着色器和内核的二进制中间语言。

因此,我们将涵盖以下主题:

  • 了解 Vulkan 缓冲区资源类型
  • 使用缓冲区资源创建几何图形
  • 了解渲染通道 Render Pass
  • 使用渲染通道 Render Pass 并创建帧缓冲区 framebuffer
  • 清除背景颜色
  • 在 Vulkan 中使用着色器

了解 Vulkan 缓冲区资源类型

缓冲区资源以线性方式表示连续的数据阵列。 缓冲区资源通常用来存储属性数据信息,如顶点坐标,纹理坐标,关联颜色等。 Vulkan 中的缓冲区资源由 VkBuffer 对象表示,与视图形式(图像视图,VkImageView)表示的图像资源(VkImage)不同,缓冲区资源可以直接用作顶点数据的源,或者可以通过着色器利用描述符进行访问。 需要把它们显式转换为缓冲区视图(VkBufferView)以允许着色器以格式化的格式使用缓冲区数据的内容。 在本节中,我们将直接通过 API 命令来使用缓冲区资源。

首先,本节将讨论涉及 API 规范的缓冲区资源概念,以便在实现中使用它们。 接下来,我们会使用这些 API 并实现缓冲区资源来存储一个简单的三角形几何图形数据。 这个三角形会用在后续的章节中,用于把几何图形渲染到应用程序中进行演示。

创建缓冲区资源类型

缓冲区资源(VkBuffer)是使用 vkCreateBuffer API 创建的。 以下是语法:

VkResult vkCreateBuffer(
VkDevice    device,
const VkBufferCreateInfo*       pCreateInfo, 
const VkAllocationCallbacks*   pAllocator, 
VkBuffer*           buffer);

此表描述了 vkCreateBuffer()API 的各个参数:

device :这是负责创建缓冲区资源的逻辑设备。

pCreateInfo:这指的是一个 VkBufferCreateInfo 指针;请查看以下部分以获取更多信息。

pAllocator :这控制着主机内存的分配过程。

buffer :当 VkBuffer 被创建后,返回它的指针。

这里定义了 VkBufferCreateInfo 语法:

typedef struct VkBufferCreateInfo { 
VkStructureType type;
const void* pNext;
VkBufferCreateFlags flags;
VkDeviceSize    size;
VkBufferUsageFlags  usage;
VkSharingMode   sharingMode;
uint32_t    queueFamilyIndexCount;
const uint32_t* pQueueFamilyIndices;
} VkBufferCreateInfo;

下表介绍了 VkBufferCreateInfo 的各个字段:

type :这指定了该结构的类型;这必须是 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO 类型。

pNext :这是一个扩展特定的结构。 它也可以是 NULL。

flags : 这些是 VkBufferCreateFlagBits 位域标志。 有关标志的更多信息,请参阅以下各节中的 VkBufferCreateFlagBits。

size :这是指要创建的缓冲区的总大小;大小以字节为单位指定。

usage :这是 VkBufferUsageFlagBits,用于指定描述缓冲区资源预期用法的位字段。 有关 VkBufferUsageFlagBits 的用法的更多信息,请参阅以下各节。

sharingMode : 这指定了缓冲区被多个队列族访问时的共享模式。 这必须是以下值之一:来自 VkSharingMode 的 VK_SHARING_MODE_EXCLUSIVE 或 VK_SHARING_MODE_CONCURRENT。

queueFamilyIndexCount :这表示 queueFamilyIndices 数组中的条目数。

pQueueFamilyIndices :这是一组要访问缓冲区的队列族数组。 共享模式必须是 VK_SHARING_MODE_CONCURRENT; 否则,就忽略。

销毁缓冲区

当不再需要缓冲区时,可以使用 vkDestroyBuffer()将其销毁:

void vkDestroyBuffer(
VkDevice   device,
VkBuffer    buffer,
const VkAllocationCallbacks*    allocator);

该 API 接受三个参数,如下表所述:

device :这是销毁缓冲区对象的逻辑设备。

buffer :这是指需要销毁的 VkBuffer 对象。

pAllocator :这个参数控制着主机内存的释放过程;请参阅第 5 章“Vulkan 中的命令缓冲区以及内存管理”中的“主机内存”部分。

创建缓冲区视图

使用 vkCreateBufferView()创建缓冲区视图。 以下是此 API 的语法:

VkResult vkCreateBufferView(
VkDevice    device,
const VkBufferViewCreateInfo* pCreateInfo, 
const VkAllocationCallbacks* pAllocator, 
VkBufferView*       pView);

此表描述了 vkCreateBufferView 的各个参数:

device :这是创建图像缓冲区的逻辑设备的句柄。

pCreateInfo : 这是一个指向 VkCreateBufferViewInfo 的指针;控制着 VkBufferView 的创建。

pAllocator :这个参数控制着主机内存的分配过程;有关更多信息,请参阅第 5 章“Vulkan 中命令缓冲区以及内存管理”中的“主机内存”部分。

pView :这会返回创建的 VkBufferView 对象的句柄。

缓冲区视图是使用 vkCreateBufferView()API 创建的。 以下是语法信息:

typedef struct VkBufferViewCreateInfo { 
VkStructureType type;
const void*      pNext; 
VkBufferViewCreateFlags  flags; 
VkBuffer         buffer;
VkFormat         format;
VkDeviceSize     offset; 
VkDeviceSize     range;
} VkBufferViewCreateInfo;

该表描述了 VkBufferViewCreateInfo 的各个字段:

type :这是指结构的类型信息;它必须是类型 VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO

next :这是一个扩展特定的结构。 该参数也可以为 NULL。

flags :该参数保留供将来使用。

buffer :这是 VkBuffer 的句柄。

format :这指定了缓冲区数据元素的格式(VkFormat)。

offset :这用于在颜色 / 深度 / 模板被转换为颜色 color 分量后重新映射 color/depth/stencil。

range :这用于选择 mipmap levels 和 array layers 的范围,使其对该视图可以访问。

销毁缓冲区视图

使用 vkDestroBufferView()API 可以销毁缓冲区视图。 这个 API 使用了三个参数。 第一个指定负责销毁第二个参数指定的缓冲区视图的逻辑设备。 这是它的语法:

void vkDestroyBufferView(
VkDevice   device,
VkBufferView    bufferView,
VkAllocationCallbacks* pAllocator);

使用缓冲区资源创建几何图形

在本节中,我们将创建一个简单的几何形状 ----- 三角形。 它会在缓冲区资源的帮助下存储在 GPU 内存中。 大多数应用程序会通过 Uniformuniform 或存储 storage 块消耗缓冲区。 缓冲区资源的实现与图像资源非常相似,除了在此处不需要我们创建缓冲区视图(VkBufferView)。

准备几何图形数据

创建 MeshData.h 并定义其中的几何数据。 声明以下结构:

/*--------------------- MeshData.h  */