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

Vulkan 学习(10)---- Vulkan SwapChain 创建

目录

      • 交换链(SwapChain)概述
      • 交换链(SwapChain)的作用
      • 交换链的创建
      • 参考代码

交换链(SwapChain)概述

Vulkan 交换链(Swapchain)是 Vulkan 应用程序和窗口系统的一座桥梁,负责将渲染结果呈现给用户
换个说法,交换链机制是一种图元绘制结果呈现的机制,它可以将绘制的结果渲染到平台相关的展示窗口/展示层当中
交换链包含一组图像(一般作为渲染目标),这些图像被用于在屏幕上显示渲染的帧
交换链中的图像个数和驱动层的实现是密切相关的。如果交换链中有两幅图像,那么称为双缓存,如果有三幅图像,称为三缓存
SwapChain

这些图像中,如果有一幅图像在后台完成了绘制过程,那么它会被交换到前台的展示窗口,为了充分利用 GPU 的性能,此时的另一幅图像会交换作为后台缓存来执行下一帧的绘制过程
这个过程往复执行,图像的交换就可以持续进行,使用多幅图像就可以保持GPU始终处于渲染一帧图像的忙碌状态,从而降低总体的等待时间,改善输出帧速率

交换链(SwapChain)的作用

  1. 图像管理:交换链维护了一组用于显示的图像,称为交换链图像(Swapchain Images), 交换链图像通常至少有两个,这样就可以实现双缓冲或者或缓冲,从而避免屏幕闪烁

  2. 同步:管理CPUGPU之间的同步,确保渲染操作不会在显示更新之前完成,这有助于防止(tearing) 现象, 避免同一帧内看到图像的不同部分

  3. 图像呈现:

  • 应用程序首先在一个缓冲区上进行渲染,完成渲染后,该缓冲区会被提交给交换链,然后交换链将这个缓冲区的内容显示到屏幕上

  • 当一个缓冲区正在显示的时候,另一个缓冲区可以进行下一轮的渲染,这样就形成了一个循环

交换链的创建

交换链创建需要比较多的参数,需要通过其他的API获取,下面是vkCreateSwapchainKHR的函数原型:

VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR(
    VkDevice                                    device,
    const VkSwapchainCreateInfoKHR*             pCreateInfo,
    const VkAllocationCallbacks*                pAllocator, // 自定义内存分配器回调函数指针
    VkSwapchainKHR*                             pSwapchain); // 指向 VkSwapchainKHR 句柄的指针,函数成功返回时,包含创建的交换链

VkSwapchainCreateInfoKHR 主要包含的结构如下:

typedef struct VkSwapchainCreateInfoKHR {
    VkStructureType                  sType;  // 必须是 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR
    const void*                      pNext;  // 指向扩展结构的指针,通常为 nullptr
    VkSwapchainCreateFlagsKHR        flags; // 交换链创建标志,当前版本 Vulkan 中未使用,设置为 0
    VkSurfaceKHR                     surface;  // 渲染表面(窗口或显示设备)
    uint32_t                         minImageCount; // 交换链中图像的最小数量
    VkFormat                         imageFormat; // 交换链中的图像格式(颜色格式)
    VkColorSpaceKHR                  imageColorSpace; // 交换链中图像的颜色空间
    VkExtent2D                       imageExtent; // 交换链中图像的高度和宽度
    uint32_t                         imageArrayLayers;// 交换链中的数组层数,通常为1
    VkImageUsageFlags                imageUsage; // 交换链中图像的用用途标志(如颜色附件)
    VkSharingMode                    imageSharingMode;// 图像共享模式(独占模式或者并发模式) 
    uint32_t                         queueFamilyIndexCount;// 队列家族索引数量(imageSharingMode 为 VK_SHARING_MODE_CONCURRENT 时使用)
    const uint32_t*                  pQueueFamilyIndices; // 指向队列家族索引数组的指针(imageSharingMode 为 VK_SHARING_MODE_CONCURRENT 时使用)
    VkSurfaceTransformFlagBitsKHR    preTransform; // 表面变换(比如旋转或者翻转)
    VkCompositeAlphaFlagBitsKHR      compositeAlpha; // 复合 Alpha 混合模式
    VkPresentModeKHR                 presentMode; // 交换链的呈现模式(比如 FIFO 或者 MailBox)
    VkBool32                         clipped; // 指定裁剪窗口外的像素(VK_TRUE 为裁剪)
    VkSwapchainKHR                   oldSwapchain;  // 旧的交换链(用于重新创建交换链时),否则为 VK_NULL_HANDLE
} VkSwapchainCreateInfoKHR;

VkSwapchainCreateInfoKHR 结构体的属性比较多,绝大多数都是固定写死的,只需要简单了解下就行
其中 VkColorSpaceKHRVkImageUsageFlagsVkSurfaceTransformFlagBitsKHRVkPresentModeKHR 的含义如下:
VkColorSpaceKHR 用于定义Image的 色域和校正信息:

typedef enum VkColorSpaceKHR {
    VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0, // SRGB 色域,带有非线性的色彩校准,常用于标准显示器
    VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001, // Display-P3 色域,带非线性伽马校正。用于支持 P3 色域显示器
    VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002, // 扩展 sRGB 颜色空间,线性校正
    VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT = 1000104003, // Display-P3 色域,线性校正
    VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104004, // DCI-P3 色域,带非线性伽马校正
    VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104005, // BT.709 颜色空间,线性校正
    VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104006, // BT.709 颜色空间,非线性校正
    VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104007,// BT.2020 颜色空间,线性校正
    VK_COLOR_SPACE_HDR10_ST2084_EXT = 1000104008, // HDR10,使用 SMPTE ST 2084 EOTF
    VK_COLOR_SPACE_DOLBYVISION_EXT = 1000104009, // Dolby Vision
    VK_COLOR_SPACE_HDR10_HLG_EXT = 1000104010,// HDR10,使用 Hybrid Log-Gamma
    VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011,// Adobe RGB 颜色空间,线性校正
    VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,// Adobe RGB 颜色空间,非线性校正
    VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,// 颜色空间通过,不做任何校正
    VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014,// 扩展 sRGB 颜色空间,非线性校正
    VK_COLOR_SPACE_DISPLAY_NATIVE_AMD = 1000213000, // 原生显示颜色空间,AMD 扩展
    VK_COLORSPACE_SRGB_NONLINEAR_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
    VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT,
    VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF
} VkColorSpaceKHR;

VkImageUsageFlags 用于交换链中的图像用途标志:

typedef enum VkImageUsageFlagBits {
    VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001,// 图像可以作为传输操作的源
    VK_IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002, // 图像可以作为传输操作的目标
    VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004, // 图像可以被采样器访问
    VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008, // 图像可以作为存储图像使用
    VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010, // 图像可以作为颜色附件使用
    VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020,// 图像可以作为深度/模板附件使用
    VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040,// 图像内容是暂时的,并不会在帧之间保留。
    VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080,// 图像可以作为输入附件使用。
    VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR = 0x00000400,
    VK_IMAGE_USAGE_VIDEO_DECODE_SRC_BIT_KHR = 0x00000800,
    VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR = 0x00001000,  
    VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x00000200,
    VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00000100,
    VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT = 0x00400000,
    VK_IMAGE_USAGE_VIDEO_ENCODE_DST_BIT_KHR = 0x00002000,
    VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR = 0x00004000,
    VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR = 0x00008000,
    VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x00080000,
    VK_IMAGE_USAGE_INVOCATION_MASK_BIT_HUAWEI = 0x00040000,
    VK_IMAGE_USAGE_SAMPLE_WEIGHT_BIT_QCOM = 0x00100000,
    VK_IMAGE_USAGE_SAMPLE_BLOCK_MATCH_BIT_QCOM = 0x00200000,
    VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV = VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,// 图像可以作为片段着色率附件使用(KHR 扩展)
    VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkImageUsageFlagBits;

VkSurfaceTransformFlagBitsKHR 定义图像的变换操作信息:

typedef enum VkSurfaceTransformFlagBitsKHR {
    VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001,// 不进行任何变换
    VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002, // 顺时针旋转 90 度
    VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 0x00000004,  // 顺时针旋转 180 度
    VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 0x00000008,  // 顺时针旋转 270 度
    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 0x00000010, // 水平翻转
    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 0x00000020,// 水平翻转后顺时针旋转 90 度
    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040,// 水平翻转后顺时针旋转 180 度
    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080,// 水平翻转后顺时针旋转 270 度
    VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100, // 继承当前变换
    VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
} VkSurfaceTransformFlagBitsKHR;

VkPresentModeKHR 定义图像的显示模式信息:

typedef enum VkPresentModeKHR {
    VK_PRESENT_MODE_IMMEDIATE_KHR = 0,//图像立即提交到显示设备,可能导致撕裂
    VK_PRESENT_MODE_MAILBOX_KHR = 1,//使用邮箱模式,提交图像如果显示队列满了,会覆盖旧的图像
    VK_PRESENT_MODE_FIFO_KHR = 2,// FIFO 模式, 提交的图像进入队列,显示设备按顺序显示
    VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3,// 类似于 FIFO 模式,但如果显示设备空闲,立即显示图像,减少延迟
    VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR = 1000111000,// 共享刷新模式,在显示设备需要时刷新
    VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001,// 持续刷新模式,持续刷新图像
    VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF
} VkPresentModeKHR;

参考代码

    // 获取之前创建的 vkSurface 的 capability
    VkSurfaceCapabilitiesKHR surfaceCapabilities;
    vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfaceCapabilities);
    std::cout << "SurfaceCapabilities: minImageCount: " << surfaceCapabilities.minImageCount << std::endl;
    std::cout << "SurfaceCapabilities: maxImageCount: " << surfaceCapabilities.maxImageCount << std::endl;

    uint32_t formatCount = 0;
    vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr);
    std::cout << "surface support formatCount: " << formatCount << std::endl;

    // 获取窗口表面所支持的格式
    VkSurfaceFormatKHR* formats = new VkSurfaceFormatKHR[formatCount];
    vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, formats);

    // 查找 VK_FORMAT_R8G8B8A8_UNORM 格式
    // all support foramt 44 50 37 33
    // VK_FORMAT_B8G8R8A8_UNORM 44
    // VK_FORMAT_B8G8R8A8_SRGB 50
    // VK_FORMAT_R8G8B8A8_UNORM 37 
    uint32_t targetFormatIdx;
    for (targetFormatIdx = 0; targetFormatIdx < formatCount; targetFormatIdx++) {
        if (formats[targetFormatIdx].format == VK_FORMAT_R8G8B8A8_UNORM) {
            break;
         }
    }

    VkSwapchainCreateInfoKHR swapchainCreateInfo = {};
    swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; // 设置结构体类型
    swapchainCreateInfo.surface = surface; // 设置表面句柄
    swapchainCreateInfo.minImageCount = surfaceCapabilities.minImageCount; // 最小图像数量
    swapchainCreateInfo.imageFormat = formats[targetFormatIdx].format; // 图像格式
    swapchainCreateInfo.imageColorSpace = formats[targetFormatIdx].colorSpace; // 颜色空间
    swapchainCreateInfo.imageExtent = surfaceCapabilities.currentExtent; // 图像范围
    swapchainCreateInfo.imageArrayLayers = 1; // 图像数组层数
    swapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; // 图像用途
    swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; // 图像共享模式
    swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; // 表面变换(比如旋转或者翻转)
    swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; // 复合 alpha 模式
    swapchainCreateInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; // 显示模式(如 FIFO、Mailbox 等)
    swapchainCreateInfo.clipped = VK_FALSE; // 是否剪辑
    swapchainCreateInfo.oldSwapchain = VK_NULL_HANDLE; // 旧交换链句柄

    // 创建交换链
    VkResult result = vkCreateSwapchainKHR(device, &swapchainCreateInfo, nullptr, &swapchain);
    if (result != VK_SUCCESS) {
        // 错误处理
        std::cout << "vkCreateSwapchainKHR failed" << std::endl;
    }

    // 获取交换链中的图像
    uint32_t imageCount;
    vkGetSwapchainImagesKHR(device, swapchain, &imageCount, nullptr);
    std::cout << "vulkan get swap chain images count " << imageCount << std::endl;

    std::vector<VkImage> swapChainImages(imageCount);
    vkGetSwapchainImagesKHR(device, swapchain, &imageCount, swapChainImages.data());

    // 为交换链中的每个图像创建 imageView, 这些图像视图会作为帧缓存的 attachement 
    std::vector<VkImageView> swapChainImageViews(swapChainImages.size());
    for (size_t i = 0; i < swapChainImages.size(); i++) {
            VkImageViewCreateInfo createInfo = {};
            createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; // 设置结构体类型
            createInfo.image = swapChainImages[i]; // 图像句柄
            createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; // 视图类型
            createInfo.format = formats[targetFormatIdx].format; // 图像格式
            createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; // 组件重映射
            createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
            createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
            createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
            createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; // 子资源范围
            createInfo.subresourceRange.baseMipLevel = 0;
            createInfo.subresourceRange.levelCount = 1;
            createInfo.subresourceRange.baseArrayLayer = 0;
            createInfo.subresourceRange.layerCount = 1;
            if (vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS){
                throw std::runtime_error("failed to create image views!"); // 错误处理
        }  
    }

http://www.kler.cn/a/448722.html

相关文章:

  • 实现 React 电子签名功能:从零开始构建一个完整的解决方案
  • Unity全局雾效
  • 深度学习革新音乐转录
  • MQTT实现集群分布式消费
  • 计算机前沿技术-人工智能算法-大语言模型-最新研究进 2024-12-22
  • XRP价格跌破2.20美元 1.94美元是否下一波牛市的关键支撑?
  • 【再谈设计模式】外观模式~复杂系统交互的简化大师
  • 0.gitlab ubuntu20.04 部署问题解决
  • 理解并使用Linux 内核中的 Tracepoint
  • C++ 基本语法
  • jenkins启动脚本,jar包自动化启动脚本
  • 如何解决微信小程序使用webview无法打开
  • Windows系统中使用git常见问题解决方案
  • 【项目实战】redis实现websocket分布式消息推送服务
  • 在 C# 中实现的目录基础操作
  • 【SpringBoot】日志文件
  • SpringBoot 整合 SQLite 数据库
  • 深入解析:Python中的决策树与随机森林
  • vue CSS 自定义宽高 翻页 剥离 效果
  • 解决 Ubuntu 24 连接正点 I.MX6ULL 的 uboot 使用 nfs 出现 Loading: T T T T T T T T