初始Vulkun(7):交换链
08/02/2020,03/22/2021
文章目录
- 交换链
- 显卡是否支持交换链(VK_KHR_swapchain)
- 逻辑设备需要扩展交换链
- 配置交换链环境
- 获取surface的设置细节
- 保持与surface一致或为交换链选择正确的设置
- chooseSwapSurfaceFormat
- chooseSwapPresentMode
- chooseSwapExtent
- 创建交换链
- 知识补充
- 总结
交换链
产生的VkSurfaceKHR句柄都指代窗口的Vulkan视图,为了在该表面上展示任何东西,需要创建一个特殊的图像,它可以用于在一个窗口中存储数据并且由窗口系统创建。
交换链来管理一个或者多个由窗口表面创建的图像对象,而不是创建一个普通的Vulkan图像对象。
交换链对象是用来请求窗口系统创建一个或者多个可用来代表Vulkan表面的图像。通过VK_KHR_swapchain扩展来提供至各功能。
每一个交换链对象管理一个图像集,通常以环状缓冲区的形式。交换链的本质是一个图像队列。
应用程序作为生产者或获取图像进行绘制,然后将其返还给减缓年图像队列,等待屏幕消费。
交换链的具体配置信息决定了应用程序提交绘制图像到队列的条件以及图像队列的表现的效果,但交换链的通常使用目的是使绘制图像的最终呈现与屏幕的刷新频率同步。
显卡是否支持交换链(VK_KHR_swapchain)
//required device extensions
const std::vector<const char*> deviceExtensions =
{VK_KHR_SWAPCHAIN_EXTENSION_NAME //VK_KHR_swapchain 的别名
};
/*
搜索算法,检索所有支持的扩展,并在必要扩展容器中尝试删除它们,如果必要扩展容器为空表示支持所有必要扩展*/
bool checkDeviceExtensionSupport(VkPhysicalDevice device)
{uint32_t extensionCount;vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);std::vector<VkExtensionProperties> availableExtensions(extensionCount);vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());//Find or search way to use erase waystd::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());for (const auto& extension : availableExtensions) {requiredExtensions.erase(extension.extensionName);}return requiredExtensions.empty();
}
逻辑设备需要扩展交换链
逻辑设备的扩展一开始为空,现在需要扩展交换链,设备扩展
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
createInfo.ppEnabledExtensionNames = deviceExtensions.data();
配置交换链环境
交换链需要保证与窗体surface兼容,或者在某些属性上保持一致。
一共需要确认三个方面:
- 基础窗口表面容量,比如图像最小最大数量,和最大最小尺寸
- 窗口表面的格式,比如像素格式,色彩空间
- 决定颜色通道和类型
- 有效的展示模式
获取surface的设置细节
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device)
{SwapChainSupportDetails details;//basic surface capablities 基础surface功能设备部分vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device,surface,&details.capabilities);//query the supported surface formats 查询支持的surface格式uint32_t formatCount;vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);if (formatCount != 0) {details.formats.resize(formatCount);vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());}//query the supported presentation modes work 查询支持的presentation模式uint32_t presentModeCount;vkGetPhysicalDeviceSurfacePresentModesKHR(device,surface,&presentModeCount,nullptr);if (presentModeCount != 0) {details.presentModes.resize(presentModeCount);vkGetPhysicalDeviceSurfacePresentModesKHR(device,surface,&presentModeCount,details.presentModes.data());}return details;
}
保持与surface一致或为交换链选择正确的设置
一共三个方面:
- 表面格式,比如颜色深度
- 展示模式
- 交换范围,图像的分辨率
chooseSwapSurfaceFormat
选择表面的格式:
- format: 色彩通道和类型
- colorSpace: SRGB颜色空间
VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats)
{//VkSurfaceFormatKHR contains a format and a colorSpace member//format: color channels and types//colorSpace: SRGP -- accurate colorfor (const auto& availableFormat : availableFormats) {if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {return availableFormat;}}return availableFormats[0];
}
chooseSwapPresentMode
代表了在屏幕呈现图像的条件,会引起撕裂效果
//Important! Set presentation mode
//actual condition for showing images to the screen
//4 modes
// VK_PRESENTMODE_IMMEDIATE_KHR
//FIFO
//FIFO_RELAXED
//MAILBOX
VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentMode)
{for (const auto& availablePresentMode : availablePresentMode) {//选择三重缓冲区if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {return availablePresentMode;}}//不然就是双重缓冲区return VK_PRESENT_MODE_FIFO_KHR;
}
4个模式:
- 立即传输
- 先进先出FIFO: 类似于垂直同步,当显示内容需要刷新的时候,显示设备从队列的前面获取图像,并却程序将渲染完成的图像插入队列的后面
- FIFO_RELAXED
- MAILBOX: 通常用来实现三重缓冲区,当交换链队列满了,选择新的替换旧的图像,从而代替阻塞应用程序的情形
chooseSwapExtent
交换范围:交换链图像的分辨率,几乎总是等于我们绘制窗体的分辨率。
//resolution of the window that we're drawing to
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities)
{if (capabilities.currentExtent.width != UINT32_MAX) {return capabilities.currentExtent;}else {VkExtent2D actualExtent = { WIDTH,HEIGHT };actualExtent.width = std::max(capabilities.minImageExtent.width,std::min(capabilities.maxImageExtent.width, actualExtent.width));actualExtent.height = std::max(capabilities.minImageExtent.height,std::min(capabilities.maxImageExtent.height, actualExtent.height));return actualExtent;}}
创建交换链
- surface:指定窗口表面
- minImageCount: 交换链中的图像个数,双缓冲或者三缓冲,分别用2或者3
注意:设置minImageCount为2表示你仅有一个前端缓冲区和一个后端缓冲区。出发了展示已完成的后端缓冲区之后,你无法开始渲染到另一个缓冲区,知道展示完成,为了获得最佳的性能,可能以延迟为代价,如果设备支持,建议至少为3.
- 处理跨多个队列族的交换链图像,如果graphics和presentation队列族不同,我们将从graphics队列汇总绘制交换链的图像,然后在另一个presentation队列中提交它们。
void createSwapChain()
{SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);//number of images in swap chain, 交换链中有3张图像uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;//cannot exceed maximum numbers of imagesif (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {imageCount = swapChainSupport.capabilities.maxImageCount;}VkSwapchainCreateInfoKHR createInfo{};createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;createInfo.surface = surface; //窗口表面与交换链的联系createInfo.minImageCount = imageCount; //双缓冲还是三缓冲等等createInfo.imageFormat = surfaceFormat.format; //图像格式与窗口保持一致createInfo.imageColorSpace = surfaceFormat.colorSpace; //图像的颜色位域//try remove the next line to see consolecreateInfo.imageExtent = extent; //图像大小createInfo.imageArrayLayers = 1; //the amount of layers each image consists of, always 1 unless you are developing a stereoscopic 3D applicationcreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;// what kind of operations we'll use the images in the swap chain for//how to handle swap chain images that will be used across multiple queue families//draw on graphics queue then submitt them on the presentation queueQueueFamilyIndices indices = findQueueFamilies(physicalDevice);uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(),indices.presentFamily.value() };if (indices.graphicsFamily != indices.presentFamily) {createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; //multiple queuecreateInfo.queueFamilyIndexCount = 2;createInfo.pQueueFamilyIndices = queueFamilyIndices;}else {createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; //only one queue used page.87createInfo.queueFamilyIndexCount = 0; //OptionalcreateInfo.pQueueFamilyIndices = nullptr; //Optional}createInfo.preTransform = swapChainSupport.capabilities.currentTransform; //90 degree clockwish ...createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; //alpha channel should be used for blending with other windowscreateInfo.presentMode = presentMode;createInfo.clipped = VK_TRUE; // donot care about the color of pixels that are obscuredcreateInfo.oldSwapchain = VK_NULL_HANDLE; //resize the window, may need to recreate swap Chainif (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {throw std::runtime_error("failed to create swap chain");}//retrieve VkImage, 交换链设置图像,这里可以获得交换链的图像。uint32_t imagesCount;vkGetSwapchainImagesKHR(device, swapChain, &imagesCount, nullptr);swapChainImages.resize(imageCount);vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());swapChainImageFormat = surfaceFormat.format;swapChainExtent = extent;
}
- 交换链中应该有多少图像,图像过多按照最大值处理
- 每个图像组成的层数
- 图像在不同队列家族中的分享模式
- 转换模式
- alpha通道
- 展示模式
- 交换链重建由于窗口大小改变
- 创建完交换链之后可以获取VkImage,它们跟着交换链自动销毁
知识补充
typedef struct VkSwapchainCreateInfoKHR
{sType,pNext,flags,surface, //将展示的平面通过surface指定//交换链自动创建的图像,及它的属性imageFormat,image,ColorSpace,imageExtent,imageArrayLayers,imageUsage, //必须是从交换链支持的用法中选取imageSharingMode,presentMode, //控制了与窗口系统的同步,以及图像展示到表面上的速率
}VkSwapchainCreateInfoKHR;
总结
- 交换链中的参数必须和表面的能力相匹配,所以需要先创建表面,并通过vkGetPhysicalDeviceSurfaceCapabilitiesKHR查询
- 每个交换链对象管理一个图像集。但交换链和窗口表面匹配完,也意味着设置完生成图像VkImage的格式,大小和颜色,所以可以从交换链中获取图像VkImage
初始Vulkun(7):交换链相关推荐
- [译]Vulkan教程(20)重建交换链
[译]Vulkan教程(20)重建交换链 Swap chain recreation 重建交换链 Introduction 入门 The application we have now success ...
- [Vulkan教程]绘制一个三角形/呈现/交换链(Swip chain)
文章目录 检查交换链支持 启用设备扩展 查询交换链支持详情 为交换链选择正确的设置 表面格式 呈现模式 交换范围 创建交换链 检索交换链中的图像 Vulkan没有默认缓冲区的概念,因此需要一个东西提供 ...
- Vulkan迷惑问题-交换链中获取图片vkAcquireNextImageKHR的ImageIndex 与 currentFrame之间的关系
奇林教育:Vulkan全系列教程,由浅入深,铸造职场不败神话! 课程链接:点击链接,跳转课程 在vulkan当中,我们遇到了drawFrame函数,但是其中有inFlight的概念,那么如何理解这个概 ...
- Vulkan填坑学习Day06—交换链
Vulkan 交换链 Vulkan 交换链,在这一章节,我们了解一下将渲染图像提交到屏幕的基本机制.这种机制称为交换链,并且需要在Vulkan上下文中被明确创建.从屏幕的角度观察,交换链本质上是一个图 ...
- DirectX12交换链、深度缓冲
DirectX12交换链 用IDXGISwapChain接口表示交换链 这个接口不仅存储了前台缓冲区和后台缓冲区两种纹理,而且还提供了修改缓冲区大小(IDXGISwapChain::ResizeBuf ...
- Vulkan 交换链详解
大家好,接下来将为大家介绍Vulkan 交换链详解. 在这一章节,我们了解一下将渲染图像提交到屏幕的基本机制.这种机制称为交换链,并且需要在Vulkan上下文中被明确创建.从屏幕的角度观察,交换链本质 ...
- Vulkan教程 - 06 交换链
Swap chain(交换链) 现在到了Vulkan教程第十章了,学习交换链.Vulkan没有默认帧缓冲的概念,因此它需要一个基础设施,能够在我们通过屏幕看到内容之前,持有我们想要渲染的东西的缓冲.该 ...
- Vulkan【6】创建一个交换链
创建一个交换链 本节的代码是 05-init_swapchain.cpp 本节描述如何创建交换链,它是最终显示给用户的图像缓冲区列表.这是建立呈现所需的所有缓冲区所需的第一个步骤之一. 这是一个关于交 ...
- Vulkan入门(四)-Surface和交换链.md
文章目录 参考资料 简述 一. Window Surface 1.1 创建窗口Surface 二. Swap Chain-交换链 2.1 检查GPU是否支持交换链 2.2 使能设备扩展 2.3 获取关 ...
最新文章
- LeetCode简单题之两数之和
- 同一服务器上多个版本的 sqlserver ,如何连接,改变某一实例的端口号
- java集合学生信息_java 使用 集合 制作学生管理系统
- Candy Box (easy version)
- Nginx(二):反向代理原理 与 配置文件详解
- Jaxb对xml报文头的小修小改
- ASP.NET Core MVC请求超时设置解决方案
- 2021计算机科学调剂,2021北京科技大学计算机科学与技术专业接收调剂研究生的通知...
- iOS “项目名” has conflicting provisioning settings.
- lol走砍e源码_【精选】某LOL走砍E盾+VMP卡登陆解决办法
- 计算机应用基础与操作,计算机应用基础与操作
- 0ctf-2016 pwn-warmup writeup
- AlphaGo已然独孤求败,通过人工智能解放鉴黄劳动力还会有多久?
- pip‘s dependency resolver does not currently take into account 解决办法
- cp: omitting directory”错误的解释和解决办法
- http 阮一峰_JavaScript 标准参考教程(alpha) 阮一峰
- 安卓手机刷linux超频内核,内核超频教程
- cortex A73/A53/A57
- acm题库c语言,C语言acm竞赛习题集锦.doc
- 三层交换机实现vlan间通信