Vulkan笔记(六)--- 交换链

交换链(swapChain)

           Vulkan 没有“默认帧缓冲区”的概念,因此它需要一个基础设施来拥有我们将渲染到的缓冲区,然后再将它们可视化到屏幕上。此基础结构是称为交换链,必须在 Vulkan 中显式创建。交换链本质上是等待呈现给屏幕。我们的应用程序将获取这样的图像以绘制到它,然后将其返回到队列中。队列到底是如何工作的,以及从队列中呈现图像取决于交换链的设置方式,但是交换链的一般目的是同步具有屏幕刷新率的图像。

          并非所有显卡都能够将图像直接呈现到屏幕上。例如为服务器设计的不具有任何显示输出功能。由于图像与呈现是紧密相关的,所以要想显示必须启用设备扩展VK_KHR_swapchain。先检查设备是否支持交换链的扩展。


const std::vector<const char*> deviceExtensionNames = {
    VK_KHR_SWAPCHAIN_EXTENSION_NAME
};

bool CVulkanApp::checkDeviceExtensionSupport(VkPhysicalDevice dev)
{
    uint32_t deviceExtensionCount;
    vkEnumerateDeviceExtensionProperties(dev, nullptr, &deviceExtensionCount, nullptr);
    std::vector<VkExtensionProperties> deviceExtensions(deviceExtensionCount);
    vkEnumerateDeviceExtensionProperties(dev, nullptr, &deviceExtensionCount, deviceExtensions.data());

    std::set<std::string> requiredExtensions(deviceExtensionNames.begin(), deviceExtensionNames.end());
    for ( const auto& extension : deviceExtensions)
    {
        requiredExtensions.erase(extension.extensionName);
    }
    return requiredExtensions.empty();
}

枚举设备扩展的个数,然后再获取具体扩展属性。这里的做了一个清空需要扩展属性的名字的处理。我们要设置的属性名存放在临时容器requiredExtensions中,如果全被删除,说明枚举设备扩展中包含了我们所设置的扩展属性,以此方式来判断是否支持此扩展。


bool CVulkanApp::isDeviceSuitable(VkPhysicalDevice dev)
{
    VkPhysicalDeviceProperties deviceProperties;
    VkPhysicalDeviceFeatures deviceFeatures;

    vkGetPhysicalDeviceProperties(dev, &deviceProperties);
    vkGetPhysicalDeviceFeatures(dev, &deviceFeatures);

    bool deviceSupport =  checkDeviceExtensionSupport(dev);
    QueueFamilyIndices indices = findQueueFamilies(dev);
    return  deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU 
        && deviceFeatures.geometryShader
        && indices.isComplete()
        && deviceSupport;
}

在设备判断是否支持的函数中增加物理设备是否支持交换链的判断。

VkDeviceCreateInfo createInfo{};
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensionNames.size());
createInfo.ppEnabledExtensionNames = deviceExtensionNames.data();

在创建逻辑设备的变量中,设置我们增加索要扩展的属性。仅检查交换链是否可用是不够的,因为它可能不可用。

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

  • 基本表面功能(交换链中的最小/最大图像数,最小/最大值 图像的宽度和高度)

  • 表面格式(像素格式、色彩空间)

  • 可用的演示模式

    struct SwapChainSupportDetails
    {
        VkSurfaceCapabilitiesKHR capabilities;
        std::vector<VkSurfaceFormatKHR> formats;
        std::vector<VkPresentModeKHR> presentModes;
    };
    SwapChainSupportDetails CVulkanApp::querySwapChainSupport(VkPhysicalDevice dev)
    {
        SwapChainSupportDetails details;
        vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, surface_, &details.capabilities);
    
        uint32_t formatCount;
        vkGetPhysicalDeviceSurfaceFormatsKHR(dev, surface_, &formatCount, nullptr);
        if (formatCount != 0)
        {
            details.formats.resize(formatCount);
            vkGetPhysicalDeviceSurfaceFormatsKHR(dev, surface_, &formatCount, details.formats.data());
        }
    
        uint32_t presentModeCount;
        vkGetPhysicalDeviceSurfacePresentModesKHR(dev, surface_, &presentModeCount, nullptr);
        if (presentModeCount != 0)
        {
            details.presentModes.resize(presentModeCount);
            vkGetPhysicalDeviceSurfacePresentModesKHR(dev, surface_, &presentModeCount, details.presentModes.data());
        }
        return details;
    }

    以上代码就是获取三个属性信息用于Vulkan与窗口界面的支持。仅支持还不够,我们要从中选择合适的属性支持。

    VkSurfaceFormatKHR CVulkanApp::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& formats)
    {
        for (const auto& format : formats)
        {
            if (format.format == VK_FORMAT_B8G8R8_SRGB &&
                format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
            {
                return format;
            }
        }
        return formats[0];
    }

    选取一种符合的标准颜色深度以及色彩空间SRGB非线性设置。

    VkPresentModeKHR CVulkanApp::chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& presentModes)
    {
        for (const auto& mode : presentModes)
        {
            if (mode == VK_PRESENT_MODE_MAILBOX_KHR)
            {
                return mode;
            }
        }
        return VK_PRESENT_MODE_FIFO_KHR;
    }

    选择一种图片绘制到界面的模式 三缓冲 或 双缓冲处理。

    VkExtent2D  CVulkanApp::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities)
    {
        if (capabilities.currentExtent.width != UINT32_MAX)
        {
            return capabilities.currentExtent;
        }
    
        int width, height;
        glfwGetFramebufferSize(window_, &width, &height);
    
        VkExtent2D actualExtent = {
        static_cast<uint32_t>(width),
        static_cast<uint32_t>(height)
        };
    
        actualExtent.width = glm::clamp(actualExtent.width,
            capabilities.minImageExtent.width,
            capabilities.maxImageExtent.width);
        actualExtent.height = glm::clamp(actualExtent.height,
            capabilities.minImageExtent.height,
            capabilities.maxImageExtent.height);
    
        return actualExtent;
    }

这个就是选择设备支持的与屏幕设置的尺寸大小的分辨率。比如(800 * 600)。高分屏就要设置设备相匹配的分辨率。

void CVulkanApp::createSwapChain()
{
    assert(logicDevice_ != VK_NULL_HANDLE);
    assert(surface_ != VK_NULL_HANDLE);

    SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice_);

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


    uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
    if (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;
    createInfo.imageExtent = extent;
    createInfo.imageArrayLayers = 1;
    createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;

    QueueFamilyIndices indices = findQueueFamilies(physicalDevice_);
    qFamily_.graphicsFamily = indices.graphicsFamily.value();
    qFamily_.presentFamily = indices.presentFamily.value();

    std::vector<uint32_t> uniqueQueueFamilies = {
      indices.graphicsFamily.value(),
      indices.presentFamily.value()
    };

    if (indices.graphicsFamily != indices.presentFamily)
    {//并发模式
        createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
        createInfo.queueFamilyIndexCount = static_cast<uint32_t>(uniqueQueueFamilies.size());
        createInfo.pQueueFamilyIndices = uniqueQueueFamilies.data();
    }
    else
    {//独占模式
        createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
        createInfo.queueFamilyIndexCount = 0;
        createInfo.pQueueFamilyIndices = nullptr;
    }

    createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
    createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
    createInfo.presentMode = presentMode;
    createInfo.clipped = VK_TRUE;

    createInfo.oldSwapchain = VK_NULL_HANDLE;

    if (vkCreateSwapchainKHR(logicDevice_, &createInfo, nullptr, &swapChain_) != VK_SUCCESS)
    {
        throw std::runtime_error("failed to crate swap chain!");
    }

    vkGetSwapchainImagesKHR(logicDevice_, swapChain_, &imageCount, nullptr);
    swapChainImages_.resize(imageCount);
    vkGetSwapchainImagesKHR(logicDevice_, swapChain_, &imageCount, swapChainImages_.data());

    swapChainImageFormat_ = surfaceFormat.format;
    swapChainExtent_ = extent;
}

交换链设置的完整流程。

realesrgan-ncnn-vulkan-20211212-windows是一个基于ncnn框架和Vulkan图形API开发的图像超分辨率增强模型。它是由GitHub用户realsrgan开发的最新版本,最新发布日期为2021年12月12日,专为Windows操作系统而设计。 该模型的主要应用是图像超分辨率增强,通过提高图像的分辨率和细节,使图像看起来更加清晰和真实。它采用深度学习和卷积神经网络等先进的技术,能够将低分辨率的图像转换成高分辨率的图像,从而提升图像的质量和视觉效果。 realesrgan-ncnn-vulkan-20211212-windows的开发使用了ncnn框架和Vulkan图形API,这使得它能够在Windows系统上实现快速且高效的图像处理。ncnn是一个轻量级的深度学习框架,专注于在移动平台和嵌入式设备上实现高性能和低延迟的推理。而Vulkan图形API是一种跨平台的图形渲染和计算API,可以充分利用计算设备的性能,提供高效的图像处理和渲染能力。 realesrgan-ncnn-vulkan-20211212-windows的使用可以通过命令行或者图形界面进行,用户可以根据自己的需求和偏好选择适合的方式。该模型提供了训练好的权重参数,用户可以直接加载这些参数并进行图像超分辨率增强。此外,该模型还支持批量处理和视频处理,方便用户对多个图像进行处理。 总之,realesrgan-ncnn-vulkan-20211212-windows是一个高效、快速且易于使用的图像超分辨率增强模型,适用于Windows系统,并利用了ncnn框架和Vulkan图形API的优势,为用户提供了出色的图像处理效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值