深度缓冲是可选的,如果要绘制3D图形,可使用深度缓冲。即使交换链以后多个图像,也只需要一个深度缓冲,因为深度缓冲在绘制交换链的每个图片时,深度缓冲是可重用的。
与交换链不同,交换链是Vulkan创建内存,深度缓冲必须自己分配图片的内存来作为深度缓冲。
步骤如下:
- 创建深度缓冲图像对象
- 申请深度缓冲设备内存
- 将内存绑定到图像对象
- 创建深度缓冲图像视图
创建深度缓冲图像对象
创建深度缓冲图像对象对象也有一个Info的结构,代码如下:
VkImageCreateInfo image_info = {};
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_info.pNext = NULL;
image_info.imageType = VK_IMAGE_TYPE_2D;
image_info.format = VK_FORMAT_D16_UNORM;
image_info.extent.width = info.width;
image_info.extent.height = info.height;
image_info.extent.depth = 1;
image_info.mipLevels = 1;
image_info.arrayLayers = 1;
image_info.samples = NUM_SAMPLES;
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
image_info.queueFamilyIndexCount = 0;
image_info.pQueueFamilyIndices = NULL;
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_info.flags = 0;
vkCreateImage(info.device, &image_info, NULL, &info.depth.image);
以上代码仅仅是创建了一个图像对象,并没有申请内存。需要注意的是,填入的宽高必须是窗口的宽高。
为深度缓冲申请内存
即使知道宽高信息,也不一定能准确计算具体需要申请多大内存,因为不同的GPU硬件,可能会有不同的对齐方式。所以,需要用Vulkan提供的vkGetImageMemoryRequirements()函数来获取大小:
typedef struct VkMemoryRequirements {
VkDeviceSize size;
VkDeviceSize alignment;
uint32_t memoryTypeBits;
} VkMemoryRequirements;
VkMemoryRequirements mem_reqs;
vkGetImageMemoryRequirements(info.device, info.depth.image, &mem_reqs);
接下来用VkMemoryRequirements来设置VkMemoryAllocateInfo的各个字段,并且申请内存:
bool memory_type_from_properties(struct sample_info &info, uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex) {
// Search memtypes to find first index with those properties
for (uint32_t i = 0; i < info.memory_properties.memoryTypeCount; i++) {
if ((typeBits & 1) == 1) {
// Type is available, does it match user properties?
if ((info.memory_properties.memoryTypes[i].propertyFlags & requirements_mask)
== requirements_mask) {
*typeIndex = i;
return true;
}
}
typeBits >>= 1;
}
// No memory types matched, return failure
return false;
}
VkMemoryAllocateInfo mem_alloc = {};
mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
mem_alloc.pNext = NULL;
mem_alloc.allocationSize = mem_reqs.size;
memory_type_from_properties(info, mem_reqs.memoryTypeBits,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex);
vkAllocateMemory(info.device, &mem_alloc, NULL, &info.depth.mem);
绑定内存到深度缓冲
vkBindImageMemory(info.device, info.depth.image, info.depth.mem, 0);
创建图像视图
与交换链一样,同样需要创建一个图像视图,代码如下:
VkImageViewCreateInfo view_info = {};
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view_info.pNext = NULL;
view_info.image = info.depth.image;
view_info.format = VK_FORMAT_D16_UNORM;
view_info.components.r = VK_COMPONENT_SWIZZLE_R;
view_info.components.g = VK_COMPONENT_SWIZZLE_G;
view_info.components.b = VK_COMPONENT_SWIZZLE_B;
view_info.components.a = VK_COMPONENT_SWIZZLE_A;
view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
view_info.subresourceRange.baseMipLevel = 0;
view_info.subresourceRange.levelCount = 1;
view_info.subresourceRange.baseArrayLayer = 0;
view_info.subresourceRange.layerCount = 1;
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
view_info.flags = 0;
res = vkCreateImageView(info.device, &view_info, NULL, &info.depth.view);