Vulkan Swapchain Unable To Create

Started by
0 comments, last by mychii 7 years, 9 months ago

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);
		}
	}
Advertisement

Oh geez. Apparently I made a mistake on matching the image extent. Since currentExtent already exists, I just need to refer it to the currentExtent by default and it solves the problem.

I can only define the extent when the currentExtent dimension is -1. If I define the dimension myself while the current extent exists (or not -1), it throws that error because they don't match! (Well, as jhenriques' tutorial said)

So this one:


Window* window = Global::stage->getWindow();

VkExtent2D extent = {};

extent.width = window->width;
extent.height = window->height;

if (surfaceCapabilities.currentExtent.width == -1)
{
... 

Should be roughly like this:


VkExtent2D extent = surfaceCapabilities.currentExtent;

if (extent.width == -1)
{
    Window* window = Global::stage->getWindow();

    extent.width = window->width;
    extent.height = window->height;
...

This topic is closed to new replies.

Advertisement