#include "vulkan_swapchain.h" #include #include #include #include "src/graphics_context.h" #include "utilities/commons.h" #include "utilities/errors_common.h" #include "vulkan/vulkan_core.h" #include "vulkan_commons.h" #include "vulkan_image.h" /** * @brief Create a Swapchain * * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: * VULKAN_ERROR_SWAPCHAIN_CREATION_FAILED */ static rse_err_t create_swapchain(struct graphics_context_t* context) { VkSwapchainCreateInfoKHR create_info; VkSurfaceCapabilitiesKHR physical_device_surface_capabilities; rse_err_t status = RSE_ERROR_NO_ERROR; VkBool32 surfaceSupported; VkExtent2D extent = {0}; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(context->vulkan_handles.physical_device, context->vulkan_handles.surface, &physical_device_surface_capabilities); STATUS_CHECK(image_get_extent(context, &extent)); /* Store extent in global variable, for later use */ context->swapchain_data.swapchain_extent = extent; /* Check if device supports surface for presentation */ vkGetPhysicalDeviceSurfaceSupportKHR(context->vulkan_handles.physical_device, context->queue_family_indices[0], context->vulkan_handles.surface, &surfaceSupported); create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; create_info.pNext = NULL; create_info.flags = 0U; create_info.surface = context->vulkan_handles.surface; create_info.minImageCount = SWAP_BUFFER_COUNT; create_info.imageFormat = IMAGE_FORMAT; create_info.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; create_info.imageExtent = context->swapchain_data.swapchain_extent; create_info.imageArrayLayers = 1U; /* For non-stereoscopic-3D applications, this value is 1. */ create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; /* Using only one queue family, so this is ok */ create_info.queueFamilyIndexCount = 1U; create_info.pQueueFamilyIndices = context->queue_family_indices; create_info.preTransform = physical_device_surface_capabilities.currentTransform; create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; create_info.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; create_info.clipped = VK_TRUE; create_info.oldSwapchain = VK_NULL_HANDLE; if (VK_SUCCESS != vkCreateSwapchainKHR(context->vulkan_handles.device, &create_info, NULL, &context->swapchain_data.swapchain)) { SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Failed to create swapchain"); return RSE_ERROR_INTERNAL_ERROR; } /* Obtain swapchain images */ vkGetSwapchainImagesKHR(context->vulkan_handles.device, context->swapchain_data.swapchain, &context->swapchain_images_count, NULL); vkGetSwapchainImagesKHR(context->vulkan_handles.device, context->swapchain_data.swapchain, &context->swapchain_images_count, context->swapchain_data.swapchain_images); return RSE_ERROR_NO_ERROR; } /** * @brief Create a Swapchain Image Views * * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: */ static rse_err_t create_swapchain_image_views(struct graphics_context_t* context) { for (size_t i = 0; i < SWAPCHAIN_IMAGE_COUNT; i++) { VkImageViewCreateInfo create_info; create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; create_info.pNext = NULL; create_info.flags = 0U; create_info.image = context->swapchain_data.swapchain_images[i]; create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; /* 2D Texture */ create_info.format = VK_FORMAT_B8G8R8A8_SRGB; create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; create_info.subresourceRange.baseMipLevel = 0U; create_info.subresourceRange.levelCount = 1U; create_info.subresourceRange.baseArrayLayer = 0U; create_info.subresourceRange.layerCount = 1U; if (VK_SUCCESS != vkCreateImageView(context->vulkan_handles.device, &create_info, NULL, &context->swapchain_data.swapchain_image_views[i])) { SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Failed to create swapchain image view"); return RSE_ERROR_INTERNAL_ERROR; } } return RSE_ERROR_NO_ERROR; } /** * @brief Create Frambuffers * * @return rse_err_t RSE_ERROR_NO_ERROR on success. Possible errors: */ static rse_err_t create_framebuffers(struct graphics_context_t* context) { for (size_t i = 0; i < context->swapchain_images_count; i++) { VkImageView attachments[] = {context->color_image.image_view, context->depth_image.image_view, context->swapchain_data.swapchain_image_views[i]}; VkFramebufferCreateInfo framebufferInfo = {0}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.renderPass = context->vulkan_handles.render_pass; framebufferInfo.attachmentCount = 3; framebufferInfo.pAttachments = attachments; framebufferInfo.width = context->swapchain_data.swapchain_extent.width; framebufferInfo.height = context->swapchain_data.swapchain_extent.height; framebufferInfo.layers = 1; if (vkCreateFramebuffer(context->vulkan_handles.device, &framebufferInfo, NULL, &context->swapchain_data.swapchain_framebuffers[i]) != VK_SUCCESS) { SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Failed to create framebuffer"); return RSE_ERROR_INTERNAL_ERROR; } } return RSE_ERROR_NO_ERROR; } /** * @brief Recreate swapchain * */ void recreate_swapchain(struct graphics_context_t* context) { SDL_Event event; int width = 0; int height = 0; SDL_GetWindowSizeInPixels(context->window_handle, &width, &height); while (width == 0 || height == 0) { SDL_GetWindowSizeInPixels(context->window_handle, &width, &height); SDL_WaitEvent(&event); } vkDeviceWaitIdle(context->vulkan_handles.device); cleanup_swapchain(context); create_swapchain(context); create_swapchain_image_views(context); create_color_resource(context); create_depth_resources(context); create_framebuffers(context); } /** * @brief Cleanup swapchain * */ void cleanup_swapchain(struct graphics_context_t* context) { size_t i; destroy_color_resource(context); destroy_depth_resource(context); for (i = 0; i < context->swapchain_images_count; i++) { vkDestroyFramebuffer(context->vulkan_handles.device, context->swapchain_data.swapchain_framebuffers[i], NULL); } for (i = 0; i < context->swapchain_images_count; i++) { vkDestroyImageView(context->vulkan_handles.device, context->swapchain_data.swapchain_image_views[i], NULL); } vkDestroySwapchainKHR(context->vulkan_handles.device, context->swapchain_data.swapchain, NULL); } rse_err_t create_swapchain_and_framebuffers(struct graphics_context_t* context) { rse_err_t status = RSE_ERROR_NO_ERROR; STATUS_CHECK(create_swapchain(context)); STATUS_CHECK(create_swapchain_image_views(context)); STATUS_CHECK(create_framebuffers(context)); return status; }