当前位置: 首页 > news >正文

VulkanTutorial(6·VkSwapChainKHR)

VkSwapChainKHR

Vulkan 没有像opengl的“默认帧缓冲区”的概念,因此它需要一个SwapChain,该SwapChain将包含我们将渲染到的缓冲区,然后我们在屏幕上可视化它们。

交换链本质上是等待呈现在屏幕上的图像队列,我们的应用程序将获取这样一个图像并绘制给它,然后将其返回给队列

队列中显示图像的条件取决于交换链的设置方式,但交换链的一般图像的显示与屏幕的刷新率同步

并非所有的显卡(physicalservice)都能够将图像显示到屏幕上,例如如果是面向servers服务器的,那么不会有任何显示输出,并且它并非vulkan的核心部分,你需要启用VK_KHR_swapchain

启用扩展

首先声明VK_KHR_SWAPCHAIN_EXTENSION_NAME的字符数组,就像validation layer那样

依然类似于validation layer,我们根据这个字符数组,检查所有的扩展中,是否有这个扩展名

我们检查了支持VK_KHR_SWAPCHAIN_EXTENSION_NAME扩展的physicalservice,现在仅需要在device creation struct结构体中,启用它

查询SwapChain支持的信息

仅仅查询是否支持KHR扩展是不够的,因为它可能不与我们window surface兼容,因此要检查更多的内容

我们需要检查3种基本属性:

  • 基本表面功能(交换链中图像的最小/最大数量、最小/最大 图像的宽度和高度)
  • 表面格式(像素格式、色彩空间)
  • 可用的演示模式

类似于QueueFamilies,我们也使用struct传递需要的详细信息

vkGetPhysicalDeviceSurfaceCapabilitiesKHR返回VkSurfaceCapabilitiesKHR物理设备表面功能

vkGetPhysicalDeviceSurfaceFormatsKHR获取表面格式

vkGetPhysicalDeviceSurfacePresentModesKHR查找可用的演示模式

SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) {//填充交换链信息SwapChainSupportDetails details;vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);uint32_t formatCount;vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);if (formatCount != 0) {details.formats.resize(formatCount);vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());}uint32_t presentModeCount;vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);if (presentModeCount != 0) {details.presentModes.resize(presentModeCount);vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());}return details;
}

更新isDeviceSuitable设备选择函数 

现在所有细节都在结构体中,我们应该更新isDeviceSuitable()函数,以确保 查询到的设备有swapchain信息存在:!swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();

选择最好的交换链信息

如果满足条件,那么支持肯定是 足够了,但可能仍有许多不同的最优性模式,以便我们在createSwapChain时使用

  • 表面格式(颜色深度)
  • 演示模式(将图像“交换”到屏幕的条件)
  • 交换范围(交换链中图像的分辨率)

对于format格式和恶presentmode来说它们都是数组,我们要在其中选出满足条件的,通过for循环,否则返回第一个

VkSurfaceFormatKHR
  • 每个VkSurfaceFormatKHR条目包含一个format和一个colorSpace成员。format成员指定颜色通道和类型。例如,VK_FORMAT_B8G8R8A8_SRGB意味着我们以8位无符号整数的顺序存储B、G、R和alpha通道,每像素总共32位。
  • colorSpace成员使用VK_COLOR_SPACE_SRGB_NONLINEAR_KHR标志指示是否支持SRGB颜色空间。,因为它会产生更准确的感知颜色
VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) {for (const auto& availableFormat : availableFormats) {if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {return availableFormat;}}return availableFormats[0];
}
Presentation mode 演示模式
  • VK_PRESENT_MODE_IMMEDIATE_KHR:您的应用程序提交的图像立即转移到屏幕上,这可能导致撕裂。
  • VK_PRESENT_MODE_FIFO_KHR:交换链是一个队列,当刷新显示时,显示从队列的前面获取图像,程序在队列的后面插入呈现的图像。如果队列已满,则程序必须等待。这与现代游戏中的垂直同步最为相似。屏幕被刷新的那一刻被称为“垂直空白”。
  • VK_PRESENT_MODE_FIFO_RELAXED_KHR:只有当应用程序延迟并且队列在最后一个垂直空白处为空时,此模式才与前一个模式不同。而不是等待下一个垂直空白,图像是立即传输,当它最终到达。这可能导致明显的撕裂。
  • VK_PRESENT_MODE_MAILBOX_KHR:这是第二种模式的另一种变体。当队列已满时,不会阻塞应用程序,而是将已经排队的图像替换为新图像。这种模式可以用来尽可能快地渲染帧,同时仍然避免撕裂,导致比标准垂直同步更少的延迟问题。这通常被称为“三重缓冲”,尽管单独存在三个缓冲区并不一定意味着帧率被解锁。
VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) {for (const auto& availablePresentMode : availablePresentModes) {if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {return availablePresentMode;}}return VK_PRESENT_MODE_FIFO_KHR;
}
Swap extent交换范围

交换范围:交换链图像的分辨率

VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {return capabilities.currentExtent;}else {int width, height;glfwGetFramebufferSize(window, &width, &height);VkExtent2D actualExtent = {static_cast<uint32_t>(width),static_cast<uint32_t>(height)};actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);return actualExtent;}
}

创建交换链

有了所有这些辅助函数来帮助我们进行选择 

SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);

还需要指定minImageCount交换链中拥有多少图像,

最小值意味着我们有时可能必须等待驱动程序完成内部操作,然后才能获取另一个图像进行渲染。因此,建议请求至少比最小值多一张图像,还应该确保在执行此操作时不超过最大图像数

uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;//设置最小数量为交换链支持的最小数量 + 1
if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {//不超过最大数量imageCount = swapChainSupport.capabilities.maxImageCount;
}

创建交换链对象和往常一样,就是创建一个struct,VkSwapchainCreateInfoKHR并填充信息

指定每个图像包含的层数

createInfo.imageArrayLayers = 1;

如果要直接渲染作为 颜色附件,或者也有可能将图像渲染到单独的图像中

createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;

我们需要指定如何处理交换链的QueueFamily

有两种方法可以处理图像,即 从多个队列访问:

  • VK_SHARING_MODE_EXCLUSIVE专用:一个图像一次由一个QueueFamily拥有 并且所有权必须明确转移,然后才能在另一个队列中使用 家庭。此选项可提供最佳性能。
  • VK_SHARING_MODE_CONCURRENT并发:图像可以跨多个QueueFamily使用 没有明确所有权转移的族。

http://www.mrgr.cn/news/59268.html

相关文章:

  • 【gRPC】什么是RPC——介绍一下RPC
  • 安全知识见闻-网络安全热门证书
  • AIGC:开启智能创造的璀璨新篇章
  • 【MySQL】表的约束、基本查询、内置函数
  • Spring Boot框架中小企业设备监控系统开发
  • django5入门【02】创建新的django程序
  • RV1126音视频学习(二)-----VI模块
  • 【C++开篇】
  • Java中为什么要私有化构造方法
  • linux快速升级cmake(非源码编译)
  • codimd更改登录超时时限
  • Linux的makefile与进度条小程序实践
  • 刚面完字节!问了大模型微调SFT,估计凉了
  • 国考报名别忘了确认缴费(需传照片)
  • 【ShuQiHere】Linux 桌面环境:选择与定制指南 ️✨
  • <网络> 网络套接字编程(二)
  • 大型项目必备搜索神器,搜索引擎ElasticSearch详细教程
  • Redis 集群 问题
  • Java一些基础代码带你轻松入门
  • #PCIE#基础知识分解之 CC/SRNS/SRIS 时钟架构
  • 基于SSM的网上购物系统的设计与实现
  • 高级 SQL 技巧全面教程:提升你的数据库操作能力
  • [Python学习日记-56] Python 中的包与代码的跨模块代码调用
  • C++ 模板专题 - 表达式模板
  • RabbitMQ 发布确认高级部分
  • 大模型多模态应用深化,AI Agent 如何为应用普及提速(科普一键收藏版)