vulkan游戏引擎的核心交换链swapchain实现

发布于:2025-05-28 ⋅ 阅读:(28) ⋅ 点赞:(0)

1.swapchain.h

#pragma once

#include "vulkan_types.inl"

void vulkan_swapchain_create(

    vulkan_context* context,

    u32 width,

    u32 height,

    vulkan_swapchain* out_swapchain);

void vulkan_swapchain_recreate(

    vulkan_context* context,

    u32 width,

    u32 height,

    vulkan_swapchain* swapchain);

b8 vulkan_swapchain_acquire_next_image_index(

    vulkan_context* context,

    vulkan_swapchain* swapchain,

    u64 timeout_ns,

    VkSemaphore image_available_semaphore,

    VkFence fence,

    u32* out_image_index

);

void vulkan_swapchain_present(

    vulkan_context* context,

    vulkan_swapchain* swapchain,

    VkQueue graphics_queue,

    VkQueue present_queue,

    VkSemaphore render_complete_semaphore,

    u32 present_image_index

    );


 

   

void vulkan_swapchain_destroy(

    vulkan_context* context,

    vulkan_swapchain* swapchain

);

2.swapchain.c

#include "vulkan_swapchain.h"

#include "defines.h"

#include "vulkan_image.h"


 

#include "core/logger.h"

#include "core/kmemory.h"

#include "vulkan_device.h"

b8 create(vulkan_context* context,u32 width,u32 height,vulkan_swapchain* swapchain);

void destroy(vulkan_context* context,vulkan_swapchain* swapchain);



 

void vulkan_swapchain_create(

    vulkan_context* context,

    u32 width,

    u32 height,

    vulkan_swapchain* out_swapchain

)

{

    create(context,width,height,out_swapchain);

}


 

void vulkan_swapchain_recreate(

    vulkan_context* context,

    u32 width,

    u32 height,

    vulkan_swapchain* swapchain

)

{

    destroy(context,swapchain);

    create(context,width,height,swapchain);

}

void vulkan_swapchain_destroy(

    vulkan_context* context,

    vulkan_swapchain* swapchain

)

{

    destroy(context,swapchain);

}


 

b8 vulkan_swapchain_acquire_next_image_index(

    vulkan_context* context,

    vulkan_swapchain* swapchain,

    u64 timeout_ns,

    VkSemaphore image_available_semaphore,

    VkFence fence,

    u32* out_image_index

)

{


 

    VkResult result = vkAcquireNextImageKHR(

        context->device.logical_device,

        swapchain->handle,

        timeout_ns,

        image_available_semaphore,

        fence,

        out_image_index

    );


 

    if(result == VK_ERROR_OUT_OF_DATE_KHR)

    {

        vulkan_swapchain_recreate(context,context->framebuffer_width,context->framebuffer_height,swapchain);

        return false;

    }else if(result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)

    {

        KFATAL("Fatal to acquire swapchain image!");

        return false;

    }


 

    return true;


 

}


 

void vulkan_swapchain_present(

    vulkan_context* context,

    vulkan_swapchain* swapchain,

    VkQueue graphics_queue,

    VkQueue present_queue,

    VkSemaphore render_complete_semaphore,

    u32 present_image_index)

{

    //Reture the image to the swapchain for presentation.

    VkPresentInfoKHR present_info = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR};

    present_info.waitSemaphoreCount = 1;

    present_info.pWaitSemaphores = &render_complete_semaphore;

    present_info.swapchainCount = 1;

    present_info.pSwapchains = &swapchain->handle;

    present_info.pImageIndices = &present_image_index;

    present_info.pResults = 0;

    VkResult result = vkQueuePresentKHR(present_queue,&present_info);

    if(result == VK_ERROR_OUT_OF_DATE_KHR || result==VK_SUBOPTIMAL_KHR)

    {

         vulkan_swapchain_recreate(context,context->framebuffer_width,context->framebuffer_height,swapchain);


 

    }else if(result != VK_SUCCESS)

    {

        KFATAL("Failed to present swap chain image!");


 

    }

    //Increment the index

    context->current_frame = (context->current_frame+1) % swapchain->max_frames_in_flight;

}


 

b8 create(vulkan_context* context,u32 width,u32 height,vulkan_swapchain* swapchain)

{

    VkExtent2D swapchain_extent = {width,height};

   

     vulkan_device_query_swapchain_support(

        context->device.physical_device,

        context->surface,

        &context->device.swapchain_support


 

    );

    //Choose a swap surface format.

    b8 found = false;

    for(u32 i = 0;i <context->device.swapchain_support.format_count;++i)

    {

        VkSurfaceFormatKHR  format = context->device.swapchain_support.formats[i];

        //Preferred formats

        if(format.format == VK_FORMAT_B8G8R8A8_UNORM &&

            format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)

            {

                swapchain->image_format = format;

                found = true;

                break;




 

            }



 

    }

    if(!found)

    {

        swapchain->image_format = context->device.swapchain_support.formats[0];


 

    }


 

     VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR;

    for(u32 i = 0;i<context->device.swapchain_support.present_mode_count;++i)

    {

        VkPresentModeKHR mode = context->device.swapchain_support.present_modes[i];

        if(mode == VK_PRESENT_MODE_MAILBOX_KHR)

        {

            present_mode = mode;

            break;



 

        }

   

   

}


 

    vulkan_swapchain_support_info* swapchain_support = &context->device.swapchain_support;

    if (swapchain_support->format_count < 1 || swapchain_support->present_mode_count < 1) {

        if (swapchain_support->formats) {

            kfree(swapchain_support->formats, sizeof(VkSurfaceFormatKHR) * swapchain_support->format_count, MEMORY_TAG_RENDERER);

        }

        if (swapchain_support->present_modes) {

            kfree(swapchain_support->present_modes, sizeof(VkPresentModeKHR) * swapchain_support->present_mode_count, MEMORY_TAG_RENDERER);

        }

        KINFO("Required swapchain support not present, skipping device.");

        return false;

    }


 

   

    //Swapchain extent

    if(context->device.swapchain_support.capabilities.currentExtent.width != UINT32_MAX)

    {

        swapchain_extent = context->device.swapchain_support.capabilities.currentExtent;



 

    }

    //to value allowed to gpu

    VkExtent2D min = context->device.swapchain_support.capabilities.minImageExtent;

    VkExtent2D max = context->device.swapchain_support.capabilities.maxImageExtent;

    swapchain_extent.width = KCLAMP(swapchain_extent.width,min.width,max.width);

    swapchain_extent.height = KCLAMP(swapchain_extent.height,min.height,max.height);

    u32 image_count = context->device.swapchain_support.capabilities.minImageCount + 1;

    if(context->device.swapchain_support.capabilities.maxImageCount >0&& image_count > context->device.swapchain_support.capabilities.maxImageCount)

    {

        image_count = context->device.swapchain_support.capabilities.maxImageCount;


 

    }

    swapchain->max_frames_in_flight = image_count - 1;

   

    VkSwapchainCreateInfoKHR swapchain_create_info = {VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR};

    swapchain_create_info.surface =context->surface;

    swapchain_create_info.minImageCount = image_count;

    swapchain_create_info.imageFormat = swapchain->image_format.format;

    swapchain_create_info.imageColorSpace = swapchain->image_format.colorSpace;

    swapchain_create_info.imageExtent = swapchain_extent;

    swapchain_create_info.imageArrayLayers = 1;

    swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;


 

    //Setup the queue family indices

    if(context->device.graphics_queue_index != context->device.present_queue_index)

    {

        u32 queueFamilyIndices[] = {

            (u32)context->device.graphics_queue_index,

            (u32)context->device.present_queue_index



 

        };

        swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;

        swapchain_create_info.queueFamilyIndexCount = 2;

        swapchain_create_info.pQueueFamilyIndices = queueFamilyIndices;

    }else

    {

        swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;

        swapchain_create_info.queueFamilyIndexCount = 0;

        swapchain_create_info.pQueueFamilyIndices = 0;




 

    }

    swapchain_create_info.preTransform = context->device.swapchain_support.capabilities.currentTransform;

    swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;

    swapchain_create_info.presentMode = present_mode;

    swapchain_create_info.clipped = VK_TRUE;

    swapchain_create_info.oldSwapchain = 0;

   

    //VkResult result = vkCreateSwapchainKHR(context->device.logical_device, &swapchain_create_info, context->allocator, &swapchain->handle);

    VK_CHECK(vkCreateSwapchainKHR(context->device.logical_device,&swapchain_create_info,context->allocator,&swapchain->handle));

     // Verify the swapchain creation.

    context->current_frame = 0;

    swapchain->image_count = 0;

    //VkImage swapchain_images[32];

   // result = vkGetSwapchainImagesKHR(context->device.logical_device, swapchain->handle, &swapchain->image_count, 0);

    VK_CHECK(vkGetSwapchainImagesKHR(context->device.logical_device,swapchain->handle,&swapchain->image_count,0));

    if(!swapchain->images)

    {

        swapchain->images = (VkImage*)kallocate(sizeof(VkImage)* swapchain->image_count,MEMORY_TAG_RENDERER);

    }

    if(!swapchain->views)

    {

        swapchain->views = (VkImageView*)kallocate(sizeof(VkImageView) * swapchain->image_count,MEMORY_TAG_RENDERER);



 

    }

    VK_CHECK(vkGetSwapchainImagesKHR(context->device.logical_device,swapchain->handle,&swapchain->image_count,swapchain->images));

    //Views

    for(u32 i=0;i<swapchain->image_count;++i)

    {

        VkImageViewCreateInfo view_info = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};

        view_info.image = swapchain->images[i];

        view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;

        view_info.format = swapchain->image_format.format;

        view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;

        view_info.subresourceRange.baseMipLevel = 0;

        view_info.subresourceRange.levelCount = 1;

        view_info.subresourceRange.baseArrayLayer = 0;

        view_info.subresourceRange.layerCount = 1;

        VK_CHECK(vkCreateImageView(context->device.logical_device,&view_info,context->allocator,&swapchain->views[i]));


 

    }

    //Depth resource

    if(!vulkan_device_detect_depth_format(&context->device))

    {

        context->device.depth_format = VK_FORMAT_UNDEFINED;

        KFATAL("Failed to find a supported format!");


 

    }



 

    vulkan_image_create(

        context,

        VK_IMAGE_TYPE_2D,

        swapchain_extent.width,

        swapchain_extent.height,

        context->device.depth_format,

        VK_IMAGE_TILING_OPTIMAL,

        VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,

        VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,

        true,

        VK_IMAGE_ASPECT_DEPTH_BIT,

        &swapchain->depth_attachment

    );

    KINFO("Swapchain created successfully!");

    return true;

}

void destroy(vulkan_context* context,vulkan_swapchain* swapchain)

{

    vkDeviceWaitIdle(context->device.logical_device);

    vulkan_image_destroy(context,&swapchain->depth_attachment);

    for(u32 i = 0;i <swapchain->image_count;++i)

    {

        vkDestroyImageView(context->device.logical_device,swapchain->views[i],context->allocator);



 

    }


 

    vkDestroySwapchainKHR(context->device.logical_device,swapchain->handle,context->allocator);



 

}


网站公告

今日签到

点亮在社区的每一天
去签到