Jump to content
  • Advertisement
Sign in to follow this  
alectora

Vulkan Vulkan Swapchain Unable To Create

This topic is 737 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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);
		}
	}
Edited by Alectora

Share this post


Link to post
Share on other sites
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;
...
Edited by Alectora

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!