From e12ca33626bdadedc3158cb69f2a4d2f9bbeeeb0 Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Fri, 6 Sep 2024 01:50:30 -0700 Subject: setup swapchain --- src/vulkan_swapchain.cpp | 279 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 src/vulkan_swapchain.cpp (limited to 'src/vulkan_swapchain.cpp') diff --git a/src/vulkan_swapchain.cpp b/src/vulkan_swapchain.cpp new file mode 100644 index 0000000..651b558 --- /dev/null +++ b/src/vulkan_swapchain.cpp @@ -0,0 +1,279 @@ +#include "vulkan_swapchain.h" + +#include "GLFW/glfw3.h" +#include "imgui_impl_glfw.h" +#include "imgui_impl_vulkan.h" +#include "vulkan/vulkan_core.h" + +#include +#include +#include +#include +#include + +std::vector get_glfw_instance_extensions() { + uint32_t extension_count = 0; + const char **extensions = glfwGetRequiredInstanceExtensions(&extension_count); + + std::vector result; + result.reserve(extension_count); + for (uint32_t i = 0; i < extension_count; i++) { + result.push_back(extensions[i]); + } + return result; +} + +namespace iris { + +Swapchain::Swapchain( + GLFWwindow *window, + iris::Device device) : device(device), window(window) +{ + if (!glfwVulkanSupported()) { + std::cerr << "GLFW failed to find Vulkan support" << std::endl; + // TODO throw an exception + abort(); + } + + // Create the surface + CHECK_VULKAN(glfwCreateWindowSurface( + device.instance, + window, + VK_NULL_HANDLE, + &surface)); + + // Optionally check surface capabilities + { + VkBool32 supported = VK_FALSE; + CHECK_VULKAN(vkGetPhysicalDeviceSurfaceSupportKHR( + device.physical_device, + device.main_queue_family_index, + surface, + &supported)); + if (supported != VK_TRUE) { + // TODO throw an exception + std::cerr << "Surface does not support presentation" << std::endl; + abort(); + } + + VkSurfaceCapabilitiesKHR surface_capabilities; + CHECK_VULKAN(vkGetPhysicalDeviceSurfaceCapabilitiesKHR( + device.physical_device, + surface, + &surface_capabilities)); + + if (surface_capabilities.maxImageCount < SWAPCHAIN_IMAGE_COUNT) { + // TODO throw an exception + std::cerr << "Surface does not support enough images" << std::endl; + abort(); + } + } + + // Create render pass + VkAttachmentDescription2 attachment = { + .sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, + .format = VK_FORMAT_B8G8R8A8_UNORM, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + }; + VkAttachmentReference2 color_attachment = { + .sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }; + VkSubpassDescription2 subpass = { + .sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2, + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .colorAttachmentCount = 1, + .pColorAttachments = &color_attachment, + }; + VkSubpassDependency2 dependencies[2] = { + { + .sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2, + .srcSubpass = VK_SUBPASS_EXTERNAL, + .dstSubpass = 0, + .srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, + .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, + }, + { + .sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2, + .srcSubpass = 0, + .dstSubpass = VK_SUBPASS_EXTERNAL, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, + .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, + }, + }; + + VkRenderPassCreateInfo2 render_pass_create_info = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2, + .attachmentCount = 1, + .pAttachments = &attachment, + .subpassCount = 1, + .pSubpasses = &subpass, + .dependencyCount = 2, + .pDependencies = dependencies, + }; + CHECK_VULKAN(vkCreateRenderPass2( + device.device, + &render_pass_create_info, + nullptr, + &render_pass)); + + // Create swapchain and image/imageview/framebuffers + // TODO: move this into `resize` to support resizing + { + // swapchain + int i_width, i_height; + glfwGetFramebufferSize(window, &i_width, &i_height); + width = (uint32_t) i_width; + height = (uint32_t) i_height; + + VkSwapchainCreateInfoKHR swapchain_create_info = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .surface = surface, + .minImageCount = SWAPCHAIN_IMAGE_COUNT, + .imageFormat = VK_FORMAT_B8G8R8A8_UNORM, + .imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, + .imageExtent = {width, height}, + .imageArrayLayers = 1, + .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, + .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, + .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR, + .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR, + .clipped = VK_TRUE, + .oldSwapchain = VK_NULL_HANDLE, + }; + CHECK_VULKAN(vkCreateSwapchainKHR( + device.device, + &swapchain_create_info, + nullptr, + &swapchain)); + + // images + uint32_t image_count = 0; + CHECK_VULKAN(vkGetSwapchainImagesKHR( + device.device, + swapchain, + &image_count, + nullptr)); + if (image_count > SWAPCHAIN_IMAGE_COUNT) { + // TODO throw an exception + std::cerr << "Swapchain image count is greater than expected" << std::endl; + abort(); + } + CHECK_VULKAN(vkGetSwapchainImagesKHR( + device.device, + swapchain, + &image_count, + swapchain_images)); + + // image views + for (uint32_t i = 0; i < image_count; i++) { + VkImageViewCreateInfo image_view_create_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = swapchain_images[i], + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = VK_FORMAT_B8G8R8A8_UNORM, + .components = { + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .a = VK_COMPONENT_SWIZZLE_IDENTITY, + }, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + + CHECK_VULKAN(vkCreateImageView( + device.device, + &image_view_create_info, + nullptr, + &swapchain_image_views[i])); + } + + // framebuffers + for (uint32_t i = 0; i < image_count; i++) { + VkFramebufferCreateInfo frame_buffer_create_info = { + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .renderPass = render_pass, + .attachmentCount = 1, + .pAttachments = &swapchain_image_views[i], + .width = width, + .height = height, + .layers = 1, + }; + CHECK_VULKAN(vkCreateFramebuffer( + device.device, + &frame_buffer_create_info, + nullptr, + &framebuffers[i])); + } + } + + + // Create descriptor pool + VkDescriptorPoolSize pool_size = { + .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .descriptorCount = 1, + }; + VkDescriptorPoolCreateInfo pool_info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .maxSets = 1, + .poolSizeCount = 1, + .pPoolSizes = &pool_size, + }; + CHECK_VULKAN(vkCreateDescriptorPool( + device.device, + &pool_info, + nullptr, + &descriptor_pool)); + + // initialize ImGui + ImGui_ImplGlfw_InitForVulkan(window, true); + ImGui_ImplVulkan_InitInfo init_info = { + .Instance = device.instance, + .PhysicalDevice = device.physical_device, + .Device = device.device, + .QueueFamily = device.main_queue_family_index, + .Queue = device.graphics_queue, + .DescriptorPool = descriptor_pool, + .MinImageCount = SWAPCHAIN_IMAGE_COUNT, + .ImageCount = SWAPCHAIN_IMAGE_COUNT, + .MSAASamples = VK_SAMPLE_COUNT_1_BIT, + + // optional + .CheckVkResultFn = [](const VkResult err) { CHECK_VULKAN(err); }, + }; + ImGui_ImplVulkan_Init(&init_info); +} + +Swapchain::~Swapchain() { + ImGui_ImplVulkan_Shutdown(); + + for (uint32_t i = 0; i < SWAPCHAIN_IMAGE_COUNT; i++) { + vkDestroyFramebuffer(device.device, framebuffers[i], nullptr); + vkDestroyImageView(device.device, swapchain_image_views[i], nullptr); + } + + vkDestroyDescriptorPool(device.device, descriptor_pool, nullptr); + vkDestroySwapchainKHR(device.device, swapchain, nullptr); + vkDestroyRenderPass(device.device, render_pass, nullptr); + vkDestroySurfaceKHR(device.instance, surface, nullptr); +} + +} // namespace iris \ No newline at end of file -- cgit v1.2.3-70-g09d2