Hi guys,
I'm currently having a problem with creating a swapchain. I've followed the 101 tutorial by jhenriques (it's posted in this forum), and apparently the swapchain is created just fine. Then I tried to redo the tutorial by Intel, and it triggers me an error when creating a swapchain. The app closes right away with validation layer enabled. I assume it's validation layer problem or whatev, so I tried to disable it. Now it throws an access violation error if I turned it off. It doesn't even have a chance to return a result for both situations. The only feedback I have from debugreportcallback is, it only says "Swapchain" given from pLayerPrefix, lol. So I assume it's related to one of the properties in the swapchainCreateInfo.
I have also visited Reddit for the almost same case. His case was he did not enable the VK_KHR_swapchain in device extensions (he did it on instance extensions instead), and therefore throws the same problem as I am. I checked mine, but I have the swapchain extension enabled during device creation. I've checked the format, the image usage, surface formats, everything is there, nothing seems to be missing.
So I really have no idea what to look anymore. Does any of you have any case with swapchain that I may need to look for?
Thanks!
---
Swapchain creation:
void _createSwapchain()
{
VkResult result;
if (_device != VK_NULL_HANDLE)
{
vkDeviceWaitIdle(_device);
}
// Get surface capabilities.
VkSurfaceCapabilitiesKHR surfaceCapabilities;
result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(_physicalDevice, _surface, &surfaceCapabilities);
KMA_VULKAN_CHECK_RESULT(result, "Unable to get physical device capabilities.");
// Get surface formats.
uint32_t surfaceFormatCount;
result = vkGetPhysicalDeviceSurfaceFormatsKHR(_physicalDevice, _surface, &surfaceFormatCount, nullptr);
KMA_VULKAN_CHECK_RESULT(result, "Unable to get physical device surface formats.");
std::vector<VkSurfaceFormatKHR> surfaceFormats(surfaceFormatCount);
result = vkGetPhysicalDeviceSurfaceFormatsKHR(_physicalDevice, _surface, &surfaceFormatCount, surfaceFormats.data());
KMA_VULKAN_CHECK_RESULT(result, "Unable to get physical device surface formats.");
// Get present modes.
uint32_t presentModeCount;
result = vkGetPhysicalDeviceSurfacePresentModesKHR(_physicalDevice, _surface, &presentModeCount, nullptr);
KMA_VULKAN_CHECK_RESULT(result, "Unable to get physical device present modes.");
std::vector<VkPresentModeKHR> presentModes(presentModeCount);
result = vkGetPhysicalDeviceSurfacePresentModesKHR(_physicalDevice, _surface, &presentModeCount, presentModes.data());
KMA_VULKAN_CHECK_RESULT(result, "Unable to get physical device present modes.");
// Get image count. 2 = double buffering, 3 triple buffering.
uint32_t imageCount = 2;
// Check if the surface is able to handle the image count we desire.
if (surfaceCapabilities.maxImageCount > 0 && imageCount > surfaceCapabilities.maxImageCount)
{
imageCount = surfaceCapabilities.maxImageCount;
}
// Get surface format.
VkSurfaceFormatKHR surfaceFormat = surfaceFormats[0];
// If there is no preferred format, we can put anything.
if (surfaceFormats.size() == 1 && surfaceFormat.format == VK_FORMAT_UNDEFINED)
{
surfaceFormat.format = VK_FORMAT_R8G8B8A8_UNORM;
surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
}
// Get our preferred format.
for (int i = 0, size = surfaceFormats.size(); i < size; ++i)
{
if (surfaceFormats[i].format == VK_FORMAT_R8G8B8A8_UNORM)
{
surfaceFormat = surfaceFormats[i];
}
}
// Set swapchain extent. If surface capabilities has no width,
// just set it like our window size, as long as it fits the surface capabilities.
Window* window = Global::stage->getWindow();
VkExtent2D extent = {};
extent.width = window->width;
extent.height = window->height;
if (surfaceCapabilities.currentExtent.width == -1)
{
if (extent.width < surfaceCapabilities.minImageExtent.width)
{
extent.width = surfaceCapabilities.minImageExtent.width;
}
if (extent.height < surfaceCapabilities.minImageExtent.height)
{
extent.height = surfaceCapabilities.minImageExtent.height;
}
if (extent.width > surfaceCapabilities.maxImageExtent.width)
{
extent.width = surfaceCapabilities.maxImageExtent.width;
}
if (extent.height > surfaceCapabilities.maxImageExtent.height)
{
extent.height = surfaceCapabilities.maxImageExtent.height;
}
}
// Set image usage; how the image is used by Vulkan.
VkImageUsageFlags imageUsage;
// Just checking a bit, but color attachment is always supported.
if (surfaceCapabilities.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
{
imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
}
else
{
KMA_ERROR("No image usage supported by the surface.");
}
// Select the pre-transformations. This is useful on phones/tablets to determine the default orientation.
VkSurfaceTransformFlagBitsKHR preTransform;
if (surfaceCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
{
preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
}
else
{
preTransform = surfaceCapabilities.currentTransform;
}
// Select the present modes. By default we use FIFO method, but we prefer mailbox if it's supported.
VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
for (int i = 0, size = presentModes.size(); i < size; ++i)
{
if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
{
presentMode = presentModes[i];
}
}
// If the window is minimized, we may want not want to recreate swapchain as there's nothing to render.
// Desktop only case.
if ((extent.width == 0) || (extent.height == 0))
{
return;
}
// Refer the current swapchain as old swapchain.
VkSwapchainKHR oldSwapchain = _swapchain;
// Finally create the swapchain.
VkSwapchainCreateInfoKHR swapchainCreateInfo = {};
swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swapchainCreateInfo.pNext = nullptr;
swapchainCreateInfo.flags = 0;
swapchainCreateInfo.surface = _surface;
swapchainCreateInfo.minImageCount = imageCount;
swapchainCreateInfo.imageFormat = surfaceFormat.format;
swapchainCreateInfo.imageColorSpace = surfaceFormat.colorSpace;
swapchainCreateInfo.imageExtent = extent;
swapchainCreateInfo.imageArrayLayers = 1;
swapchainCreateInfo.imageUsage = imageUsage;
swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swapchainCreateInfo.queueFamilyIndexCount = 0;
swapchainCreateInfo.pQueueFamilyIndices = nullptr;
swapchainCreateInfo.preTransform = preTransform;
swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
swapchainCreateInfo.presentMode = presentMode;
swapchainCreateInfo.clipped = VK_TRUE;
swapchainCreateInfo.oldSwapchain = oldSwapchain;
result = vkCreateSwapchainKHR(_device, &swapchainCreateInfo, nullptr, &_swapchain); // <-- WHERE THE ERROR HAPPENS.
KMA_VULKAN_CHECK_RESULT(result, "Unable to create swapchain.");
// Destroy the old swapchain.
if (oldSwapchain != VK_NULL_HANDLE)
{
vkDestroySwapchainKHR(_device, oldSwapchain, nullptr);
}
}