From f0f498d53ff0f815d0091d3a2aa6428a56fc02ea Mon Sep 17 00:00:00 2001 From: Benau Date: Tue, 28 Dec 2021 13:51:03 +0800 Subject: [PATCH] Add createSwapChain for GEVulkanDriver --- .../include/ge_vulkan_driver.hpp | 23 ++- lib/graphics_engine/src/ge_vulkan_driver.cpp | 161 +++++++++++++++++- 2 files changed, 182 insertions(+), 2 deletions(-) diff --git a/lib/graphics_engine/include/ge_vulkan_driver.hpp b/lib/graphics_engine/include/ge_vulkan_driver.hpp index e1e4ec3dd..94e2e470c 100644 --- a/lib/graphics_engine/include/ge_vulkan_driver.hpp +++ b/lib/graphics_engine/include/ge_vulkan_driver.hpp @@ -199,7 +199,7 @@ namespace GE //! Only used by the internal engine. Used to notify the driver that //! the window was resized. - virtual void OnResize(const core::dimension2d& size) {} + virtual void OnResize(const core::dimension2d& size); //! Returns type of video driver virtual E_DRIVER_TYPE getDriverType() const { return video::EDT_VULKAN; } @@ -263,6 +263,13 @@ namespace GE virtual void disableScissorTest() {} private: + struct SwapChainSupportDetails + { + VkSurfaceCapabilitiesKHR capabilities; + std::vector formats; + std::vector presentModes; + }; + //! returns a device dependent texture from a software surface (IImage) //! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData=0) { return NULL; } @@ -294,29 +301,42 @@ namespace GE s32 userData = 0, E_GPU_SHADING_LANGUAGE shadingLang = EGSL_DEFAULT) { return 0; } + SIrrlichtCreationParameters m_params; // RAII to auto cleanup struct VK { VkInstance instance; VkSurfaceKHR surface; VkDevice device; + VkSwapchainKHR swap_chain; + std::vector swap_chain_images; + std::vector swap_chain_image_views; VK() { instance = VK_NULL_HANDLE; surface = VK_NULL_HANDLE; device = VK_NULL_HANDLE; + swap_chain = VK_NULL_HANDLE; } ~VK() { + for (VkImageView& image_view : swap_chain_image_views) + vkDestroyImageView(device, image_view, NULL); + if (swap_chain != VK_NULL_HANDLE) + vkDestroySwapchainKHR(device, swap_chain, NULL); if (device != VK_NULL_HANDLE) vkDestroyDevice(device, NULL); if (surface != VK_NULL_HANDLE) vkDestroySurfaceKHR(instance, surface, NULL); if (instance != VK_NULL_HANDLE) vkDestroyInstance(instance, NULL); + if (instance != VK_NULL_HANDLE) + vkDestroyInstance(instance, NULL); } }; VK m_vk; + VkFormat m_swap_chain_image_format; + VkExtent2D m_swap_chain_extent; VkPhysicalDevice m_physical_device; std::vector m_device_extensions; VkSurfaceCapabilitiesKHR m_surface_capabilities; @@ -339,6 +359,7 @@ namespace GE std::vector* surface_formats, std::vector* present_modes); void createDevice(); + void createSwapChain(); std::string getVulkanVersionString() const; std::string getDriverVersionString() const; }; diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index 743c5f79c..a9476f85b 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -2,6 +2,7 @@ #ifdef _IRR_COMPILE_WITH_VULKAN_ #include "SDL_vulkan.h" +#include #include #include #include @@ -437,7 +438,8 @@ namespace GE { GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, SDL_Window* window) - : CNullDriver(io, core::dimension2d(0, 0)) + : CNullDriver(io, core::dimension2d(0, 0)), + m_params(params) { m_physical_device = VK_NULL_HANDLE; m_graphics_queue = VK_NULL_HANDLE; @@ -461,6 +463,11 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params, if (SDL_Vulkan_CreateSurface(window, m_vk.instance, &m_vk.surface) == SDL_FALSE) throw std::runtime_error("SDL_Vulkan_CreateSurface failed"); + int w, h = 0; + SDL_Vulkan_GetDrawableSize(window, &w, &h); + ScreenSize.Width = w; + ScreenSize.Height = h; + m_device_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); findPhysicalDevice(); createDevice(); @@ -476,6 +483,7 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params, #endif vkGetPhysicalDeviceProperties(m_physical_device, &m_properties); + createSwapChain(); os::Printer::log("Vulkan version", getVulkanVersionString().c_str()); os::Printer::log("Vulkan vendor", getVendorInfo().c_str()); os::Printer::log("Vulkan renderer", m_properties.deviceName); @@ -742,6 +750,157 @@ std::string GEVulkanDriver::getDriverVersionString() const return driver_version.str(); } // getDriverVersionString +// ---------------------------------------------------------------------------- +void GEVulkanDriver::createSwapChain() +{ + VkSurfaceFormatKHR surface_format = m_surface_formats[0]; + + if (m_surface_formats.size() == 1 && + m_surface_formats[0].format == VK_FORMAT_UNDEFINED) + { + surface_format = + { + VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + }; + } + else + { + for (VkSurfaceFormatKHR& available_format : m_surface_formats) + { + if (available_format.format == VK_FORMAT_B8G8R8A8_UNORM && + available_format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + { + surface_format = available_format; + break; + } + } + } + + VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; + if (m_params.SwapInterval == 0) + { + for (VkPresentModeKHR& available_mode : m_present_modes) + { + if (available_mode == VK_PRESENT_MODE_IMMEDIATE_KHR) + { + present_mode = available_mode; + break; + } + } + } + else + { + for (VkPresentModeKHR& available_mode : m_present_modes) + { + if (available_mode == VK_PRESENT_MODE_MAILBOX_KHR) + { + present_mode = available_mode; + break; + } + } + } + + VkExtent2D image_extent = m_surface_capabilities.currentExtent; + if (m_surface_capabilities.currentExtent.width == std::numeric_limits::max()) + { + VkExtent2D max_extent = m_surface_capabilities.maxImageExtent; + VkExtent2D min_extent = m_surface_capabilities.minImageExtent; + + VkExtent2D actual_extent = + { + std::max( + std::min(ScreenSize.Width, max_extent.width), min_extent.width), + std::max( + std::min(ScreenSize.Height, max_extent.height), min_extent.height) + }; + image_extent = actual_extent; + } + + // Try to get triple buffering by default + // https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Swap_chain + uint32_t swap_chain_images_count = m_surface_capabilities.minImageCount + 1; + if (m_surface_capabilities.maxImageCount > 0 && + swap_chain_images_count > m_surface_capabilities.maxImageCount) + { + swap_chain_images_count = m_surface_capabilities.maxImageCount; + } + + VkSwapchainCreateInfoKHR create_info = {}; + create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + create_info.surface = m_vk.surface; + create_info.minImageCount = swap_chain_images_count; + create_info.imageFormat = surface_format.format; + create_info.imageColorSpace = surface_format.colorSpace; + create_info.imageExtent = image_extent; + create_info.imageArrayLayers = 1; + create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + if (m_graphics_family != m_present_family) + { + uint32_t queueFamilyIndices[] = + { m_graphics_family, m_present_family }; + create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + create_info.queueFamilyIndexCount = 2; + create_info.pQueueFamilyIndices = queueFamilyIndices; + } + else + { + create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + } + + create_info.preTransform = m_surface_capabilities.currentTransform; + create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + create_info.presentMode = present_mode; + create_info.clipped = VK_TRUE; + create_info.oldSwapchain = VK_NULL_HANDLE; + + VkResult result = vkCreateSwapchainKHR(m_vk.device, &create_info, NULL, + &m_vk.swap_chain); + + if (result != VK_SUCCESS) + throw std::runtime_error("vkCreateSwapchainKHR failed"); + + vkGetSwapchainImagesKHR(m_vk.device, m_vk.swap_chain, &swap_chain_images_count, NULL); + m_vk.swap_chain_images.resize(swap_chain_images_count); + vkGetSwapchainImagesKHR(m_vk.device, m_vk.swap_chain, &swap_chain_images_count, + &m_vk.swap_chain_images[0]); + + m_swap_chain_image_format = surface_format.format; + m_swap_chain_extent = image_extent; + + for (unsigned int i = 0; i < m_vk.swap_chain_images.size(); i++) + { + VkImageViewCreateInfo create_info = {}; + create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + create_info.image = m_vk.swap_chain_images[i]; + create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + create_info.format = m_swap_chain_image_format; + 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.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + create_info.subresourceRange.baseMipLevel = 0; + create_info.subresourceRange.levelCount = 1; + create_info.subresourceRange.baseArrayLayer = 0; + create_info.subresourceRange.layerCount = 1; + + VkImageView swap_chain_image_view = VK_NULL_HANDLE; + VkResult result = vkCreateImageView(m_vk.device, &create_info, NULL, + &swap_chain_image_view); + + if (result != VK_SUCCESS) + throw std::runtime_error("vkCreateImageView failed"); + m_vk.swap_chain_image_views.push_back(swap_chain_image_view); + } +} // createSwapChain + +// ---------------------------------------------------------------------------- +void GEVulkanDriver::OnResize(const core::dimension2d& size) +{ + CNullDriver::OnResize(size); +} // OnResize + } namespace irr