Add createSwapChain for GEVulkanDriver

This commit is contained in:
Benau 2021-12-28 13:51:03 +08:00
parent 3f99d279a7
commit f0f498d53f
2 changed files with 182 additions and 2 deletions

View File

@ -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<u32>& size) {}
virtual void OnResize(const core::dimension2d<u32>& 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<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> 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<VkImage> swap_chain_images;
std::vector<VkImageView> 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<const char*> m_device_extensions;
VkSurfaceCapabilitiesKHR m_surface_capabilities;
@ -339,6 +359,7 @@ namespace GE
std::vector<VkSurfaceFormatKHR>* surface_formats,
std::vector<VkPresentModeKHR>* present_modes);
void createDevice();
void createSwapChain();
std::string getVulkanVersionString() const;
std::string getDriverVersionString() const;
};

View File

@ -2,6 +2,7 @@
#ifdef _IRR_COMPILE_WITH_VULKAN_
#include "SDL_vulkan.h"
#include <limits>
#include <set>
#include <sstream>
#include <stdexcept>
@ -437,7 +438,8 @@ namespace GE
{
GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
io::IFileSystem* io, SDL_Window* window)
: CNullDriver(io, core::dimension2d<u32>(0, 0))
: CNullDriver(io, core::dimension2d<u32>(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<uint32_t>::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<u32>& size)
{
CNullDriver::OnResize(size);
} // OnResize
}
namespace irr