vulkan从小白到专家——VulkanSwapChain

Vulkan没有默认帧缓冲区的概念,在送显上屏之前,需要一个基础结构来持有一些缓冲区。Vulkan引入了交换链的概念。
交换链本质上就是一个(用于送显上屏)图像的等待队列。应用程序获取一个图像,绘制内容,然后返回到队列。队列如何工作,队列中图像如何送显上屏 取决于交换链的配置参数。
交换链的作用就是同步图像的上屏和屏幕的刷新。

0 Surface的校验

验证GPU是否支持surface的显示,vulkan标准内没有窗体surface的概念,外在的因素不可控所以要校验,

    // Section1: check
    VkBool32 vk_queue_family_supports_present = false;
    auto hr = vkGetPhysicalDeviceSurfaceSupportKHR(device.gpuDevice_, device.queueFamilyIndex_, device.surface_, &vk_queue_family_supports_present);
    if (hr != VK_SUCCESS || !vk_queue_family_supports_present) {
   
   
        LOGE("surface not founded...");
        exit(1);
    }

这个接口第二个参数是queue的索引,多个队列需要循环遍历,手机上一般1个队列有效。

1 Surface Format相关

同样手段,先取长度 再填充vector。

    // Query the list of supported surface format and choose one we like
    uint32_t formatCount = 0;
    hr = vkGetPhysicalDeviceSurfaceFormatsKHR(device.gpuDevice_, device.surface_,
                                         &formatCount, nullptr);
    if (hr != VK_SUCCESS || formatCount == 0) {
   
   
        LOGE("could not get number of physical device formats for device");
        exit(1);
    }

    std::vector<VkSurfaceFormatKHR> formats; formats.resize(formatCount);
    vkGetPhysicalDeviceSurfaceFormatsKHR(device.gpuDevice_, device.surface_,
                                         &formatCount, formats);
    LOGI("Got %d formats", formatCount);

    // 至少必须有RGBA8888啊,
    uint32_t chosenFormat;
    for (chosenFormat = 0; chosenFormat < formatCount; chosenFormat++) {
   
   
        if (formats[chosenFormat].format == VK_FORMAT_R8G8B8A8_UNORM) break;
    }
    assert(chosenFormat < formatCount);

surfaceFormat结构里有两个字段,pixelFormat和colorSpace:

  • 格式主要sRGB最常见的,SCRGB是FP16表示每个通道,R16G16B16A16。RGB也有两种:最普通的UNORM,和非线性的,后者非常少见。
  • 颜色空间,分线性和非线性的。

关于线性&非线性&HDR的vkSurface format的设置,参考下openharmony中graphics3d模块的代码:

VkFormat GetColorFormat(const uint32_t flags, const vector<VkSurfaceFormatKHR>& surfaceFormats)
{
    constexpr uint32_t preferredFormatCount { 4u };
    constexpr VkFormat srgbFormats[preferredFormatCount] = { VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_B8G8R8A8_SRGB,
        VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM };
    constexpr VkFormat nonSrgbFormats[preferredFormatCount] = { VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM,
        VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_B8G8R8A8_SRGB };
    constexpr VkFormat hdrFormats[] = { VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_FORMAT_A2R10G10B10_UNORM_PACK32,
        VK_FORMAT_R16G16B16A16_SFLOAT };

    // If pSurfaceFormats includes just one entry, whose value for format is VK_FORMAT_UNDEFINED,
    // surface has no preferred format. In this case, the application can use any valid VkFormat value.
    if (surfaceFormats[0].format == VK_FORMAT_UNDEFINED && surfaceFormats.size() == 1) {
        return VK_FORMAT_R8G8B8A8_SRGB;
    }

    if (flags & SwapchainFlagBits::CORE_SWAPCHAIN_HDR_BIT) {
        for (auto format : hdrFormats) {
            for (auto surfaceFormat : surfaceFormats) {
                if (format == surfaceFormat.format) {
                    return surfaceFormat.format;
                }
            }
        }
    }
    const bool preferSrgbFormat = (flags & SwapchainFlagBits::CORE_SWAPCHAIN_SRGB_BIT);
    const array_view<const VkFormat> formats =
        (preferSrgbFormat) ? array_view<const VkFormat> { srgbFormats } : array_view<const VkFormat> { nonSrgbFormats };

    for (auto format : formats) {
        for (auto surfaceFormat : surfaceFormats) {
            if (format == surfaceFormat.format) {
                return surfaceFormat.format;
            }
        }
    }
    return VK_FORMAT_UNDEFINED;
}

关于这两个概念补充一段:

Vulkan 本身与色彩空间无关。不过,在数字电信号转换为光信号之前的某个阶段,色彩空间必须明确。这就是在交换链创建过程中需要指定色彩空间的原因。

  • imageFormat指定图像格式是什么(与vkCreateImage()中的作用相同)。
  • imageColorSpace则表示在图像呈现时,交换链 / 显示器对这些数值的解释方式。
    所以,如果使用UNORM,这意味着色彩空间未指定,数据只是普通的原始数据位。或者更确切地说,这意味着由你来负责色彩空间(前提是图像确实存储颜色信息,而不是完全其他类型的数据)。
    如果你将VK_COLOR_SPACE_SRGB_NONLINEAR_KHR与_UNORM搭配使用,这意味着交换链获取你的数据位,并在呈现时假定这些数据已经是sRGB 格式。
    如果使用的是_SRGB,那么对于交换链本身来说没有区别,但实际情况是创建的VkImages是_SRGB格式,这意味着当你使用它们时,颜色会为你进行线性化处理(与创建非交换链的VkImage时的情况相同)。

扩展一下,谈谈色域。显示器的能力,依赖于硬件是否支持,最广泛和古老的格式是sRGB,P3(广色域),BT2020,HDR10,杜比,后面几种在HDR渲染中经常遇到,目前旗舰手机都支持hdr,iphone12是第一款集采集、处理、显示的终端设备。

要正常渲染,至少得有一种格式,R8G8B8A8_UNORM,否则就退出。P40Pro手机查询到支持5种格式,

(VkSurfaceFormatKHR)  (format = VK_FORMAT_R8G8B8A8_UNORM, colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
(VkSurfaceFormatKHR)  (format = VK_FORMAT_R8G8B8A8_SRGB, colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
(VkSurfaceFormatKHR)  (format = VK_FORMAT_R5G6B5_UNORM_PACK16, colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
(VkSurfaceFormatKHR)  (format = VK_FORMAT_R16G16B16A16_SFLOAT, colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
(</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值