继续在QtVulkan工程中,添加CreateSwapchain。即在SceneWidget.h中添加bool CreateSwapchain()函数,并在cpp文件中实现它。
在函数中,第一件事就是检查物理设备对swapchain的支持。之前在创建逻辑设备时,已经对swapchain进行了检查,但是在这里还要检查一下。之前检查,是系统启动时,用来获取当前窗口的大小(保存在m_capabilities变量里的)。而现在的检查是为了在每一帧开始绘制之前,再进行检查,主要是为了适配窗口的大小发生变化时,重新获取窗口的大小,还有设置swapchain中的图像的大小。所以还是调用函数CheckDeviceSupportSurface,参数为之前保存的物理设备的句柄m_physicalDevice。获取窗口大小、窗口的支持的像素格式和窗口支持的展示模式。
在已获取到窗口支持的像素格式中,选择要使用的像素格式,即:像素为RGBA模式的,且颜色空间为srgb。由于功能独立,所以写成两个函数:VkSurfaceFormatKHR ChooseFormat()返回一个format,记录选择的像素格式和VkPresentModeKHR ChoosePresent()返回一个展示模式。
需要再设置一下swapchain中的图像数,这里可以将swapchain理解成图像列表。一般为最小值+1,当图像数大于最大值时,就使用最大值。
实际上,通过代码调试可以看到m_capabilities中的最小值和最大值是一样的。
然后进行创建swapchain,当然,创建时需要先声明VkSwapchainCreateInfoKHR结构。
声明一个createInfo的变量,并初始化:
VkSwapchainCreateInfoKHR createInfo{};
设置其结构的类型:
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
surface赋值:
createInfo.surface = m_surface;
设置最小图像数:
createInfo.minImageCount = imageCount;
设置使用的像素格式:
createInfo.imageFormat = surfaceFormat.format;
设置颜色空间:
createInfo.imageColorSpace = surfaceFormat.colorSpace;
设置图像的宽高:
createInfo.imageExtent = extent2D;
layer层级,如果不是mipmap,那么这个值就是1。
createInfo.imageArrayLayers = 1;
图像与颜色绑定:
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
设置为独享模式:
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
设置为当前窗口的变换:
createInfo.preTransform = m_capabilities.currentTransform;
设置不透明:
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
使用选择的展示模式:
createInfo.presentMode = presentMode;
支持裁剪:
createInfo.clipped = VK_TRUE;
然后调用vkCreateSwapchainKHR并补全参数:
第一个参数为之前创建好的逻辑设备句柄,第二参数为createInfo的指针,第三个参数为nullptr,第四个参数为创建的swapchain,这里要在SceneWidget.h中补写一个VkSwapchainKHR m_swapchain = VK_NULL_HANDLE,将m_swapchai写在第四个参数的位置,记得传入的是引用。
要对函数的返回值进行检查,当失败时,要打印出提示信息。
在这里创建了swapchain,那就顺便再做几件事:
1)从swapchain中获取其中的Image的信息,通过vkGetSwapchainImagesKHR函数,同样,调用两次,一次是取image的数目,一次是取image的内容。由于绘制时,需要这个image数组,所以在SceneWidget.h中添加std::vector<VkImage> m_swapchainImages;
2)记录一下当前使用的像素格式,和窗口大小。
同样添加两个成员变量,以备后面使用:VkFormat _SwapChainImageFormat;
VkExtent2D _SwapChainExtent;给成员变量赋值:
最后在SceneWidget::Init()中添加调用:
和在SceneWidget::UnInit函数里添加清理:
vkDestroySwapchainKHR(m_device, m_swapchain, nullptr);
运行:
结果,依然没有报错信息:)
没有报错信息,不等于就一定能成功,但至少当前这个阶段,还检查不出错误。