#include "vulkan_engine/vulkan/graphics.h" #include #include "precomp.h" namespace veng { void Graphics::CreateSurface() { VkResult result = glfwCreateWindowSurface(instance_, window->GetHandle(), nullptr, &surface_); if (result != VK_SUCCESS) std::exit(EXIT_FAILURE); } bool IsRgbaTypeFormat(const VkSurfaceFormatKHR& format_properties) { return format_properties.format == VK_FORMAT_R8G8B8A8_SRGB || format_properties.format == VK_FORMAT_B8G8R8A8_SRGB; } bool IsSrgbColorSpace(const VkSurfaceFormatKHR& format_properties) { return format_properties.colorSpace == VK_COLORSPACE_SRGB_NONLINEAR_KHR; } bool IsCorrectFormat(const VkSurfaceFormatKHR& format_properties) { return IsSrgbColorSpace(format_properties) && IsRgbaTypeFormat(format_properties); } VkSurfaceFormatKHR Graphics::ChooseSwapSurfaceFormat( gsl::span formats) { if (formats.size() == 1 && formats[0].format == VK_FORMAT_UNDEFINED) { return {VkFormat::VK_FORMAT_R8G8B8A8_SRGB, VkColorSpaceKHR::VK_COLORSPACE_SRGB_NONLINEAR_KHR}; } auto it = std::find_if(formats.begin(), formats.end(), IsCorrectFormat); if (it != formats.end()) return *it; for (const VkSurfaceFormatKHR& format : formats) { if (format.format == VK_FORMAT_R8G8B8A8_SRGB && format.colorSpace == VK_COLORSPACE_SRGB_NONLINEAR_KHR) { return format; } } return formats[0]; } VkPresentModeKHR Graphics::ChooseSwapPresentMode( gsl::span present_modes) { constexpr std::array preferred_modes = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR}; for (const auto& preferred : preferred_modes) if (std::find(present_modes.begin(), present_modes.end(), preferred) != present_modes.end()) return preferred; return VK_PRESENT_MODE_FIFO_KHR; } VkExtent2D Graphics::ChooseSwapExtent( const VkSurfaceCapabilitiesKHR& capabilities) { constexpr std::uint32_t kInvalidSize = std::numeric_limits::max(); if (capabilities.currentExtent.width != kInvalidSize) { return capabilities.currentExtent; } else { glm::ivec2 size = window->GetFramebufferSize(); VkExtent2D actual_extent = {static_cast(size.x), static_cast(size.y)}; actual_extent.width = std::clamp(actual_extent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width); actual_extent.height = std::clamp(actual_extent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height); return actual_extent; } } std::uint32_t Graphics::ChooseSwapImageCount( const VkSurfaceCapabilitiesKHR& capabilities) { std::uint32_t image_count = capabilities.minImageCount + 1; if (capabilities.maxImageCount > 0 && capabilities.maxImageCount < image_count) image_count = capabilities.maxImageCount; return image_count; } void Graphics::CreateSwapChain() { SwapChainProperties properties = GetSwapChainProperties(physical_device_); surface_format_ = ChooseSwapSurfaceFormat(properties.formats); present_mode_ = ChooseSwapPresentMode(properties.present_modes); extent_ = ChooseSwapExtent(properties.capabilities); std::uint32_t image_count = ChooseSwapImageCount(properties.capabilities); VkSwapchainCreateInfoKHR info = {}; info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; info.surface = surface_; info.minImageCount = image_count; info.imageFormat = surface_format_.format; info.imageColorSpace = surface_format_.colorSpace; info.imageExtent = extent_; info.imageArrayLayers = 1; info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; info.presentMode = present_mode_; info.preTransform = properties.capabilities.currentTransform; info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; info.clipped = VK_TRUE; info.oldSwapchain = VK_NULL_HANDLE; QueueFamilyIndices indices = FindQueueFamilies(physical_device_); if (indices.graphics_family != indices.presentation_family) { std::array family_indices = { indices.graphics_family.value(), indices.presentation_family.value()}; info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; info.queueFamilyIndexCount = family_indices.size(); info.pQueueFamilyIndices = family_indices.data(); } else { info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; } VkResult result = vkCreateSwapchainKHR(logical_device_, &info, nullptr, &swap_chain_); if (result != VK_SUCCESS) std::exit(EXIT_FAILURE); std::uint32_t actual_image_count; vkGetSwapchainImagesKHR(logical_device_, swap_chain_, &actual_image_count, nullptr); swap_chain_images_.resize(actual_image_count); vkGetSwapchainImagesKHR(logical_device_, swap_chain_, &actual_image_count, swap_chain_images_.data()); } VkImageView Graphics::CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspect_flag) { VkImageViewCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; info.image = image; info.viewType = VK_IMAGE_VIEW_TYPE_2D; info.format = format; info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; info.subresourceRange.aspectMask = aspect_flag; info.subresourceRange.baseMipLevel = 0; info.subresourceRange.levelCount = 1; info.subresourceRange.baseArrayLayer = 0; info.subresourceRange.layerCount = 1; VkImageView view; VkResult result = vkCreateImageView(logical_device_, &info, nullptr, &view); if (result != VK_SUCCESS) std::exit(EXIT_FAILURE); return view; } void Graphics::CreateImageViews() { swap_chain_image_views_.resize(swap_chain_images_.size()); auto image_view_it = swap_chain_image_views_.begin(); for (VkImage image : swap_chain_images_) { *image_view_it = CreateImageView(image, surface_format_.format, VK_IMAGE_ASPECT_COLOR_BIT); std::advance(image_view_it, 1); } } } // namespace veng