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

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);

}

相关推荐
汤姆yu几秒前
基于springboot的民间文化艺术品销售系统
java·spring boot·后端
掘金酱4 分钟前
创作者训练营:老友带新+新人冲榜,全员参与,双倍快乐!
前端·人工智能·后端
NoneCoder9 分钟前
React Hooks 与异步数据管理
前端·react.js·面试·前端框架
KenXu10 分钟前
🔥 前端开发三大神器助你快速进入"傻瓜"时代
前端·mcp
二进制小甜豆14 分钟前
Spring MVC
java·后端·spring·mvc
孟陬15 分钟前
组件库自动化脚本:监听构建成功并打开浏览器
前端·node.js
前端设计诗20 分钟前
Cursor Figma MCP 完整使用教程
前端·javascript·cursor
Yvonne97821 分钟前
定时任务:springboot集成xxl-job-core(一)
java·spring boot·xxl-job
Mike_jia22 分钟前
ImHex:开源十六进制编辑器的终极指南——逆向工程师的“夜视仪
前端
Mike_jia25 分钟前
用 Linux Wifi Hotspot 开启无线共享革命:从极简部署到企业级实战
前端