Huh!
It is not easy to post a reasonable amount of code when you code using Vulkan... I didn't expected that it needs about a thousand lines of code just to initialize...
Well, here is a code "fragment" that initializes swap chain:
char* APP_SHORT_NAME = "VkRenderer";
instance_extension_names.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
instance_extension_names.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
VkApplicationInfo app_info = {};
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
app_info.pNext = NULL;
app_info.pApplicationName = APP_SHORT_NAME;
app_info.applicationVersion = 1;
app_info.pEngineName = APP_SHORT_NAME;
app_info.engineVersion = 1;
app_info.apiVersion = VK_API_VERSION;
VkInstanceCreateInfo inst_info = {};
inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
inst_info.pNext = NULL;
inst_info.flags = 0;
inst_info.pApplicationInfo = &app_info;
inst_info.enabledExtensionCount = instance_extension_names.size();
inst_info.ppEnabledExtensionNames = inst_info.enabledExtensionCount ? instance_extension_names.data() : NULL;
inst_info.enabledLayerCount = 0;
inst_info.ppEnabledLayerNames = NULL;
VkResult res;
res = vkCreateInstance(&inst_info, NULL, &m_vkInst);
//...
VkWin32SurfaceCreateInfoKHR createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
createInfo.pNext = NULL;
createInfo.hinstance = GetModuleHandle(NULL); //info.connection;
createInfo.hwnd = wnd;
VkResult res = vkCreateWin32SurfaceKHR(m_vkInst, &createInfo, NULL, &m_surface);
VkBool32 *supportsPresent = (VkBool32 *)malloc(queue_count * sizeof(VkBool32));
for (uint32_t i = 0; i < queue_count; i++) {
vkGetPhysicalDeviceSurfaceSupportKHR(m_vGPU[0], i, m_surface, &supportsPresent[i]);
}
uint32_t graphicsQueueNodeIndex = UINT32_MAX;
for (uint32_t i = 0; i < queue_count; i++) {
if ((m_queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
if (supportsPresent[i] == VK_TRUE) {
graphicsQueueNodeIndex = i;
break;
}
}
}
//...
float queue_priorities[1] = { 0.0 };
device_extension_names.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
VkDeviceQueueCreateInfo queue_info = {};
queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_info.pNext = NULL;
queue_info.queueCount = 1;
queue_info.pQueuePriorities = queue_priorities;
VkDeviceCreateInfo device_info = {};
device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device_info.pNext = NULL;
device_info.queueCreateInfoCount = 1;
device_info.pQueueCreateInfos = &queue_info;
device_info.enabledExtensionCount = device_extension_names.size();
device_info.ppEnabledExtensionNames = device_info.enabledExtensionCount ? device_extension_names.data() : NULL;
device_info.enabledLayerCount = 0;
device_info.ppEnabledLayerNames = NULL;
device_info.pEnabledFeatures = NULL;
res = vkCreateDevice(m_vGPU[0], &device_info, NULL, &m_vkDevice);
//...
uint32_t formatCount;
VkResult res = vkGetPhysicalDeviceSurfaceFormatsKHR(m_vGPU[0], m_surface, &formatCount, NULL);
assert(res == VK_SUCCESS);
VkSurfaceFormatKHR *surfFormats = (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
res = vkGetPhysicalDeviceSurfaceFormatsKHR(m_vGPU[0], m_surface, &formatCount, surfFormats);
assert(res == VK_SUCCESS);
// If the format list includes just one entry of VK_FORMAT_UNDEFINED,
// the surface has no preferred format. Otherwise, at least one
// supported format will be returned.
VkFormat format;
if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) {
format = VK_FORMAT_B8G8R8A8_UNORM;
}
else {
assert(formatCount >= 1);
format = surfFormats[0].format;
}
VkSurfaceCapabilitiesKHR surfCapabilities;
res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_vGPU[0], m_surface, &surfCapabilities);
uint32_t presentModeCount;
res = vkGetPhysicalDeviceSurfacePresentModesKHR(m_vGPU[0], m_surface, &presentModeCount, NULL);
VkPresentModeKHR *presentModes = (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR));
res = vkGetPhysicalDeviceSurfacePresentModesKHR(m_vGPU[0], m_surface, &presentModeCount, presentModes);
VkExtent2D swapChainExtent;
if (surfCapabilities.currentExtent.width == (uint32_t)-1) {
swapChainExtent.width = width;
swapChainExtent.height = height;
}
else {
swapChainExtent = surfCapabilities.currentExtent;
}
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
for (size_t i = 0; i < presentModeCount; i++) {
if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
break;
}
if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) &&
(presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) {
swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
}
}
uint32_t desiredNumberOfSwapChainImages =
surfCapabilities.minImageCount + 1;
if ((surfCapabilities.maxImageCount > 0) &&
(desiredNumberOfSwapChainImages > surfCapabilities.maxImageCount)) {
desiredNumberOfSwapChainImages = surfCapabilities.maxImageCount;
}
VkSurfaceTransformFlagBitsKHR preTransform;
if (surfCapabilities.supportedTransforms &
VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
}
else {
preTransform = surfCapabilities.currentTransform;
}
VkSwapchainCreateInfoKHR swap_chain = {};
swap_chain.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swap_chain.pNext = NULL;
swap_chain.surface = m_surface;
swap_chain.minImageCount = desiredNumberOfSwapChainImages;
swap_chain.imageFormat = format;
swap_chain.imageExtent.width = swapChainExtent.width;
swap_chain.imageExtent.height = swapChainExtent.height;
swap_chain.preTransform = preTransform;
swap_chain.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
swap_chain.imageArrayLayers = 1;
swap_chain.presentMode = swapchainPresentMode;
swap_chain.oldSwapchain = NULL;
swap_chain.clipped = true;
swap_chain.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
swap_chain.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
swap_chain.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swap_chain.queueFamilyIndexCount = 0;
swap_chain.pQueueFamilyIndices = NULL;
res = vkCreateSwapchainKHR(m_vkDevice, &swap_chain, NULL, &m_swap_chain);
res = vkGetSwapchainImagesKHR(m_vkDevice, m_swap_chain, &m_swapchainImageCount, NULL);
VkImage *swapchainImages = (VkImage *)malloc(m_swapchainImageCount * sizeof(VkImage));
res = vkGetSwapchainImagesKHR(m_vkDevice, m_swap_chain, &m_swapchainImageCount, swapchainImages);
m_buffers.resize(m_swapchainImageCount);
CreateCommandBuffer();
ExecuteBeginCommandBuffer();
vkGetDeviceQueue(m_vkDevice, m_graphicsQueueFamilyIndex, 0, &m_queue);
for (uint32_t i = 0; i < m_swapchainImageCount; i++) {
VkImageViewCreateInfo color_image_view = {};
color_image_view.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
color_image_view.pNext = NULL;
color_image_view.format = format;
color_image_view.components.r = VK_COMPONENT_SWIZZLE_R;
color_image_view.components.g = VK_COMPONENT_SWIZZLE_G;
color_image_view.components.b = VK_COMPONENT_SWIZZLE_B;
color_image_view.components.a = VK_COMPONENT_SWIZZLE_A;
color_image_view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
color_image_view.subresourceRange.baseMipLevel = 0;
color_image_view.subresourceRange.levelCount = 1;
color_image_view.subresourceRange.baseArrayLayer = 0;
color_image_view.subresourceRange.layerCount = 1;
color_image_view.viewType = VK_IMAGE_VIEW_TYPE_2D;
color_image_view.flags = 0;
m_buffers[i].image = swapchainImages[i];
SetImageLayout(m_buffers[i].image, VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
color_image_view.image = m_buffers[i].image;
res = vkCreateImageView(m_vkDevice, &color_image_view, NULL, &m_buffers[i].view);
}
ExecuteEndCommandBuffer();
ExecuteQueueCommandBuffer();
This is not the whole code. All handles are valid and functions always return VK_SUCCESS. The dealocation code is like following:
for (uint32_t i = 0; i < m_swapchainImageCount; i++) {
vkDestroyImageView(m_vkDevice, m_buffers[i].view, NULL);
}
vkDestroySwapchainKHR(m_vkDevice, m_swap_chain, NULL);
I'm sorry for so much code, but that is Vulkan!