Example #1
0
void SwapChain::InitProcs()
{
	GET_INSTANCE_PROC_ADDR(RHIRoot::GetInstance(), GetPhysicalDeviceSurfaceSupportKHR);
	GET_INSTANCE_PROC_ADDR(RHIRoot::GetInstance(), GetPhysicalDeviceSurfaceCapabilitiesKHR);
	GET_INSTANCE_PROC_ADDR(RHIRoot::GetInstance(), GetPhysicalDeviceSurfaceFormatsKHR);
	GET_INSTANCE_PROC_ADDR(RHIRoot::GetInstance(), GetPhysicalDeviceSurfacePresentModesKHR);
	GET_DEVICE_PROC_ADDR(GetRawDevice(), CreateSwapchainKHR);
	GET_DEVICE_PROC_ADDR(GetRawDevice(), DestroySwapchainKHR);
	GET_DEVICE_PROC_ADDR(GetRawDevice(), GetSwapchainImagesKHR);
	GET_DEVICE_PROC_ADDR(GetRawDevice(), AcquireNextImageKHR);
	GET_DEVICE_PROC_ADDR(GetRawDevice(), QueuePresentKHR);
}
Example #2
0
VkBool32 VKTS_APIENTRY debugInitInstanceExtensions(const VkInstance instance)
{
    if (!instance)
    {
        return VK_FALSE;
    }

    GET_INSTANCE_PROC_ADDR(instance, CreateDebugReportCallbackEXT);
    GET_INSTANCE_PROC_ADDR(instance, DestroyDebugReportCallbackEXT);
    GET_INSTANCE_PROC_ADDR(instance, DebugReportMessageEXT);

    return VK_TRUE;
}
Example #3
0
bool create_instance(const char *app_name) {
    uint32_t extensions_count = 0;
    VK_VERIFY (vkEnumerateInstanceExtensionProperties(nullptr, &extensions_count, nullptr));
    VERIFY_LOG (extensions_count > 0, LOG_TYPE, "Error occurred during instance extensions enumeration!", "");

    std::vector<VkExtensionProperties> available_extensions(extensions_count);
    VK_VERIFY (vkEnumerateInstanceExtensionProperties(nullptr, &extensions_count, &available_extensions[0]));

    std::vector<const char *> extensions = {
        VK_KHR_SURFACE_EXTENSION_NAME,
#ifdef PLATFORM_WINDOWS
        VK_KHR_WIN32_SURFACE_EXTENSION_NAME
#elif PLATFORM_LINUX
        VK_KHR_XCB_SURFACE_EXTENSION_NAME
#endif
    };

    for (size_t i = 0; i < extensions.size(); ++i) {
        VERIFY_LOG(utils::check_extension(extensions[i], available_extensions), LOG_TYPE,
                   "Could not find instance extension named \"%s\"!", extensions[i]);
    }

    VkApplicationInfo application_info = {
        VK_STRUCTURE_TYPE_APPLICATION_INFO,             // VkStructureType            sType
        nullptr,                                        // const void                *pNext
        app_name,                                       // const char                *pApplicationName
        VK_MAKE_VERSION(0, 0, 1),                       // uint32_t                   applicationVersion
        "gladius",                                      // const char                *pEngineName
        VK_MAKE_VERSION(0, 0, 1),                       // uint32_t                   engineVersion
        VK_MAKE_VERSION(1, 0, 21)                       // uint32_t                   apiVersion
    };

    VkInstanceCreateInfo instance_create_info = {
        VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,         // VkStructureType            sType
        nullptr,                                        // const void                *pNext
        0,                                              // VkInstanceCreateFlags      flags
        &application_info,                              // const VkApplicationInfo   *pApplicationInfo
        0,                                              // uint32_t                   enabledLayerCount
        nullptr,                                        // const char * const        *ppEnabledLayerNames
        static_cast<uint32_t>(extensions.size()),      // uint32_t                   enabledExtensionCount
        &extensions[0]                                  // const char * const        *ppEnabledExtensionNames
    };

    VK_VERIFY(vkCreateInstance(&instance_create_info, nullptr, &(vk_globals::instance)));

    GET_INSTANCE_PROC_ADDR(vk_globals::instance, GetPhysicalDeviceSurfaceSupportKHR);
    GET_INSTANCE_PROC_ADDR(vk_globals::instance, GetPhysicalDeviceSurfaceFormatsKHR);

    return true;
}
	int XdevLSwapChainVulkan::init(VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device) {
		m_instance = instance;
		m_physicalDevice = physicalDevice;
		m_device = device;

		GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceSupportKHR);
		GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceCapabilitiesKHR);
		GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceFormatsKHR);
		GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfacePresentModesKHR);
		GET_DEVICE_PROC_ADDR(device, CreateSwapchainKHR);
		GET_DEVICE_PROC_ADDR(device, DestroySwapchainKHR);
		GET_DEVICE_PROC_ADDR(device, GetSwapchainImagesKHR);
		GET_DEVICE_PROC_ADDR(device, AcquireNextImageKHR);
		GET_DEVICE_PROC_ADDR(device, QueuePresentKHR);
		return 0;
	}
  void init(VkInstance instance, VkPhysicalDevice physicalDevice,
            VkDevice device) {
    this->instance = instance;
    this->physicalDevice = physicalDevice;
    this->device = device;

    GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceSupportKHR);
    GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceCapabilitiesKHR);
    GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceFormatsKHR);
    GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfacePresentModesKHR);
    GET_DEVICE_PROC_ADDR(device, CreateSwapchainKHR);
    GET_DEVICE_PROC_ADDR(device, DestroySwapchainKHR);
    GET_DEVICE_PROC_ADDR(device, GetSwapchainImagesKHR);
    GET_DEVICE_PROC_ADDR(device, AcquireNextImageKHR);
    GET_DEVICE_PROC_ADDR(device, QueuePresentKHR);
  }
Example #6
0
/**
 * Initialize instance and device related functions
 */
void WSI::init(){
//
     g_gdpa = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr(instance, "vkGetDeviceProcAddr");

     pfnGetPhysicalDeviceSurfaceSupportKHR = (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)
                 vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceSupportKHR");

    GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceSupportKHR);
    GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceCapabilitiesKHR);
    GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceFormatsKHR);
    GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfacePresentModesKHR);
    GET_INSTANCE_PROC_ADDR(instance, GetSwapchainImagesKHR);


    GET_DEVICE_PROC_ADDR(device, CreateSwapchainKHR);
    GET_DEVICE_PROC_ADDR(device, DestroySwapchainKHR);
    GET_DEVICE_PROC_ADDR(device, GetSwapchainImagesKHR);
    GET_DEVICE_PROC_ADDR(device, AcquireNextImageKHR);
    GET_DEVICE_PROC_ADDR(device, QueuePresentKHR);
}
Example #7
0
VkBool32 VKTS_APIENTRY _wsiInitInstanceExtensions(const VkInstance instance)
{
    if (!instance || !g_hasAndroid)
    {
        return VK_FALSE;
    }

    GET_INSTANCE_PROC_ADDR(instance, CreateAndroidSurfaceKHR);

    return VK_TRUE;
}
Example #8
0
int main(int argc, char** argv) {
	
	g_validationLayers = std::vector<const char*> {
		"VK_LAYER_LUNARG_mem_tracker",
		"VK_LAYER_GOOGLE_unique_objects",
	};

	// Init GLFW
	{
		// Handle GLFW errors
		glfwSetErrorCallback([](int error, const char* description) {
			std::cout << "GLFW error: " << error << " - " << description << std::endl;
		});
		
		// Initialize GLFW
		if (!glfwInit())
			error("Cannot initialize GLFW.");

		// Check Vulkan support
		if (!glfwVulkanSupported())
			error("Cannot find compatible Vulkan client driver.");
	}

	// Get Validation layers
	{
		uint32_t numInstanceLayers = 0;

		// Get numInstanceLayers
		if (vkEnumerateInstanceLayerProperties(&numInstanceLayers, nullptr))
			error("Vulkan: Could not enumerate instance layer properties.");

		if (numInstanceLayers > 0) {
			std::vector<VkLayerProperties> instanceLayers(numInstanceLayers);
			if (vkEnumerateInstanceLayerProperties(&numInstanceLayers, instanceLayers.data()))
				error("Vulkan: Could not enumerate instance layer properties.");

			// Print layers:
			std::cout << "Validation layers: " << std::endl;
			for (int i = 0; i < numInstanceLayers; ++i) {
				std::cout << "\t" << instanceLayers[i].layerName << std::endl;
				std::cout << "\t\t" << instanceLayers[i].description << std::endl;
				std::cout << std::endl;
			}
			std::cout << std::endl;
		}
		else
			std::cout << "No validation layers found!" << std::endl;

		// TODO: Check Layers
	}

	// Check instance extensions
	{
		int numRequiredExtensions;
		const char** requiredExtensions;

		// Get required extensions from GLFW
		{
			requiredExtensions = glfwGetRequiredInstanceExtensions((int*)&numRequiredExtensions);

			if (numRequiredExtensions > 0) {
				// Write to global g_extensions
				for (int i = 0; i < numRequiredExtensions; ++i)
					g_extensions.push_back(requiredExtensions[i]);

				// Print
				std::cout << "Required Instance Extensions(GLFW):" << std::endl;
				for (int i = 0; i < numRequiredExtensions; ++i) {
					std::cout << "\t" << requiredExtensions[i] << std::endl;
				}
				std::cout << std::endl;
			}
			// TODO: Check extensions
		}

		// Get Instance extensions
		{
			VkResult err;
			uint32_t numInstanceExtensions;
			err = vkEnumerateInstanceExtensionProperties(nullptr, &numInstanceExtensions, nullptr);

			if (numInstanceExtensions > 0) {
				std::vector<VkExtensionProperties> instanceExtensions(numInstanceExtensions);
				err = vkEnumerateInstanceExtensionProperties(NULL, &numInstanceExtensions, instanceExtensions.data());

				// Print
				std::cout << "Instance Extensions: " << std::endl;
				for (int i = 0; i < numInstanceExtensions; ++i) {
					std::cout << "\t" <<instanceExtensions[i].extensionName << std::endl;
					std::cout << "\t\t" << instanceExtensions[i].specVersion << std::endl;
					std::cout << std::endl;
				}
				std::cout << std::endl;
			}
			// TODO: Check instance extensions(with required instance extensions)
		}
	}

	// Create Vulkan Instance
	{
		VkApplicationInfo app;
		{
			app.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
			app.pNext = nullptr;
			app.pApplicationName = "Vulkan test 1";
			app.applicationVersion = 0;
			app.pEngineName = "Vulkan test 1";
			app.engineVersion = 0;
			app.apiVersion = VK_API_VERSION;
		}

		VkInstanceCreateInfo instanceInfo;
		{
			instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
			instanceInfo.pNext = nullptr;
			instanceInfo.pApplicationInfo = &app;
			instanceInfo.enabledLayerCount = g_validationLayers.size();
			instanceInfo.ppEnabledLayerNames = g_validationLayers.data();
			instanceInfo.enabledExtensionCount = g_extensions.size();
			instanceInfo.ppEnabledExtensionNames = g_extensions.data();
		}

		// TODO: Aligned allocators
		VkAllocationCallbacks allocator;
		{
			allocator.pUserData = nullptr;
			allocator.pfnAllocation = [](void* pUserData, size_t size, size_t alignment, VkSystemAllocationScope allocationScope)->void* {
				return malloc(size);
			};
			allocator.pfnFree = [](void* pUserData, void* pMemory) {
				free(pMemory);
			};
			allocator.pfnReallocation = [](void* pUserData, void *pOriginal, size_t size, size_t alignment, VkSystemAllocationScope allocationScope) {
				free(pOriginal);
				return malloc(size);
			};
			allocator.pfnInternalAllocation = nullptr;
			allocator.pfnInternalFree = nullptr;
			allocator.pfnReallocation = nullptr;
		}
		
		// Create vulkan instance
		VkResult vkError = vkCreateInstance(&instanceInfo, &allocator, &g_vkInstance);

		// Handle errors
		switch (vkError) {
		case VK_ERROR_INCOMPATIBLE_DRIVER:
			error("Drivers do not support vulkan. Drivers could be outdated.");
			break;
		case VK_ERROR_EXTENSION_NOT_PRESENT:
			error("Cannot find specified extension.");
			break;
		case VK_SUCCESS:
			// Succes! (prevent default from catching success as error)
			std::cout << "Vulkan instance created!" << std::endl;
			break;
		default:
			error("Could not create vulkan Instance. Drivers could be outdated.");
			break;
		}

	}

	// Look for GPU device
	{
		uint32_t numGPUs;
		VkResult vkError = vkEnumeratePhysicalDevices(g_vkInstance, &numGPUs, nullptr);
		
		if (numGPUs < 0)
			error("vkEnumeratePhysicalDevices could not find any GPU devices.");

		if (vkError)
			error("vkEnumeratePhysicalDevices could not enumerate GPU devices.");

		if (numGPUs > 0) {
			std::vector<VkPhysicalDevice> physicalDevices(numGPUs);
			if (vkEnumeratePhysicalDevices(g_vkInstance, &numGPUs, physicalDevices.data()))
				error("vkEnumeratePhysicalDevices could not enumerate GPU devices.");

			g_vkGPU = physicalDevices[0];

			std::cout << numGPUs << " GPUs found!" << std::endl;
		}
	}

	// Get queue properties
	{
		uint32_t numQueues;
		vkGetPhysicalDeviceProperties(g_vkGPU, &g_vkGPUProperties);

		vkGetPhysicalDeviceQueueFamilyProperties(g_vkGPU, &numQueues, nullptr);
		if (numQueues == 0)
			error("vkGetPhysicalDeviceQueueFamilyProperties could not find any queues.");

		g_vkQueueProperties = std::vector<VkQueueFamilyProperties>(numQueues);
		vkGetPhysicalDeviceQueueFamilyProperties(g_vkGPU, &numQueues, g_vkQueueProperties.data());
	}

	// Look for device layers (Unecessary code that does nothing)
	{
		uint32_t numDeviceLayers;

		if (vkEnumerateDeviceLayerProperties(g_vkGPU, &numDeviceLayers, nullptr))
			error("vkEnumerateDeviceLayerProperties failed!");

		if (numDeviceLayers > 0) {
			std::vector<VkLayerProperties> deviceLayers(numDeviceLayers);

			if (vkEnumerateDeviceLayerProperties(g_vkGPU, &numDeviceLayers, deviceLayers.data()))
				error("vkEnumerateDeviceLayerProperties failed!");

			// TODO: Check device layers.
		}
	}

	// Look for device extensions (swapchain extension)
	{
		uint32_t numDeviceExtensions;
		bool extensionSwapChainFound = false;

		if (vkEnumerateDeviceExtensionProperties(g_vkGPU, nullptr, &numDeviceExtensions, nullptr))
			error("vkEnumerateDeviceExtensionProperties failed!");

		if (numDeviceExtensions > 0) {
			std::vector<VkExtensionProperties> deviceExtensions(numDeviceExtensions);
			
			if (vkEnumerateDeviceExtensionProperties(g_vkGPU, nullptr, &numDeviceExtensions, deviceExtensions.data()))
				error("vkEnumerateDeviceExtensionProperties failed!");

			// Search for swapchain extension
			for (VkExtensionProperties extension : deviceExtensions) {
				if (!strcmp(extension.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME))
					extensionSwapChainFound = true;
			}
			
			// Print
			std::cout << std::endl << "Extensions:" << std::endl;
			for (VkExtensionProperties extension : deviceExtensions) {
				std::cout << extension.extensionName << "(" << extension.specVersion << ")" << std::endl;
			}
			std::cout << std::endl;
		}

		if (!extensionSwapChainFound)
			error("Failed to find the " VK_KHR_SWAPCHAIN_EXTENSION_NAME " extension!");
	}

	// TODO: Validate

	// Get instance function adresses
	{
		GET_INSTANCE_PROC_ADDR(g_vkInstance, GetPhysicalDeviceSurfaceCapabilitiesKHR);
		GET_INSTANCE_PROC_ADDR(g_vkInstance, GetPhysicalDeviceSurfaceFormatsKHR);
		GET_INSTANCE_PROC_ADDR(g_vkInstance, GetPhysicalDeviceSurfacePresentModesKHR);
		GET_INSTANCE_PROC_ADDR(g_vkInstance, GetPhysicalDeviceSurfaceSupportKHR);
		GET_INSTANCE_PROC_ADDR(g_vkInstance, CreateSwapchainKHR);
		GET_INSTANCE_PROC_ADDR(g_vkInstance, DestroySwapchainKHR);
		GET_INSTANCE_PROC_ADDR(g_vkInstance, GetSwapchainImagesKHR);
		GET_INSTANCE_PROC_ADDR(g_vkInstance, AcquireNextImageKHR);
		GET_INSTANCE_PROC_ADDR(g_vkInstance, QueuePresentKHR);
	}

	// Create window
	{
		glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);

		g_window = glfwCreateWindow(g_width, g_height, "Vulkan test", NULL, NULL);

		if (!g_window)
			error("Could not create window!");

		glfwSetWindowRefreshCallback(g_window, [](GLFWwindow* window) {
			// TODO: draw();
		});
		glfwSetFramebufferSizeCallback(g_window, [](GLFWwindow* window, int width, int height) {
			g_width = width;
			g_height = height;
			// TODO: resize();
		});


	}

	// Init swapchain
	{
		glfwCreateWindowSurface(g_vkInstance, g_window, nullptr, &g_vkSurface);

		std::vector<VkBool32> supportsPresent(g_vkQueueProperties.size());

		for (uint32_t i = 0; i < g_vkQueueProperties.size(); ++i)
			g_vkFPGetPhysicalDeviceSurfaceSupportKHR(g_vkGPU, i, g_vkSurface, &supportsPresent[i]);

		uint32_t graphicsQueueNodeIndex = UINT32_MAX;
		uint32_t presentQueueNodeIndex = UINT32_MAX;

		for (uint32_t i = 0; i < g_vkQueueProperties.size(); ++i) {
			if (graphicsQueueNodeIndex == UINT32_MAX) {
				graphicsQueueNodeIndex = i;
			}

			if (supportsPresent[i] == VK_TRUE) {
				graphicsQueueNodeIndex = i;
				presentQueueNodeIndex = i;
				break;
			}
		}

		//if (presentQueueNodeIndex == UINT32_MAX) {
		//	for (uint32_t i = 0; i < g_vkQueueProperties.size(); ++i) {
		//		if (supportsPresent[i] == VK_TRUE) {
		//			presentQueueNodeIndex = i;
		//		}
		//	}
		//}

		if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX)
			error("Could not find a graphics and a present queue.");

		if (graphicsQueueNodeIndex != presentQueueNodeIndex)
			error("Could not find a common graphics and present queue.");

		g_vkGraphicsQueueNodeIndex = graphicsQueueNodeIndex;

		//TODO: init device
		{
			float queuePriotities = 0.f;
			VkDeviceQueueCreateInfo queue;
			{
				queue.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
				queue.pNext = NULL;
				queue.queueFamilyIndex = g_vkGraphicsQueueNodeIndex;
				queue.queueCount = 1;
				queue.pQueuePriorities = &queuePriotities;
			}

		}

		//vkGetDeviceQueue(g_vkDevice, g_vkGraphicsQueueNodeIndex, 0, g_vkQueue);

	}

	std::cin.get();

	return 0;
}
int sample_main(int argc, char *argv[]) {
    VkResult U_ASSERT_ONLY res;
    struct sample_info info = {};
    char sample_title[] = "Swapchain Initialization Sample";

    /*
     * Set up swapchain:
     * - Get supported uses for all queues
     * - Try to find a queue that supports both graphics and present
     * - If no queue supports both, find a present queue and make sure we have a
     *   graphics queue
     * - Get a list of supported formats and use the first one
     * - Get surface properties and present modes and use them to create a swap
     *   chain
     * - Create swap chain buffers
     * - For each buffer, create a color attachment view and set its layout to
     *   color attachment
     */

    init_global_layer_properties(info);
    init_instance_extension_names(info);
    init_device_extension_names(info);
    init_instance(info, sample_title);
    init_enumerate_device(info);
    init_connection(info);
    init_window_size(info, 50, 50);
    init_window(info);

/* VULKAN_KEY_START */
// Construct the surface description:
#ifdef _WIN32
    VkWin32SurfaceCreateInfoKHR createInfo = {};
    createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
    createInfo.pNext = NULL;
    createInfo.hinstance = info.connection;
    createInfo.hwnd = info.window;
    res = vkCreateWin32SurfaceKHR(info.inst, &createInfo,
                                  NULL, &info.surface);
#elif defined(__ANDROID__)
    GET_INSTANCE_PROC_ADDR(info.inst, CreateAndroidSurfaceKHR);

    VkAndroidSurfaceCreateInfoKHR createInfo;
    createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
    createInfo.pNext = nullptr;
    createInfo.flags = 0;
    createInfo.window = AndroidGetApplicationWindow();
    res = info.fpCreateAndroidSurfaceKHR(info.inst, &createInfo, nullptr, &info.surface);
#else  // !__ANDROID__ && !_WIN32
    VkXcbSurfaceCreateInfoKHR createInfo = {};
    createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
    createInfo.pNext = NULL;
    createInfo.connection = info.connection;
    createInfo.window = info.window;
    res = vkCreateXcbSurfaceKHR(info.inst, &createInfo, NULL, &info.surface);
#endif // _WIN32
    assert(res == VK_SUCCESS);

    // Iterate over each queue to learn whether it supports presenting:
    VkBool32 *supportsPresent =
        (VkBool32 *)malloc(info.queue_count * sizeof(VkBool32));
    for (uint32_t i = 0; i < info.queue_count; i++) {
        vkGetPhysicalDeviceSurfaceSupportKHR(info.gpus[0], i, info.surface,
                                             &supportsPresent[i]);
    }

    // Search for a graphics queue and a present queue in the array of queue
    // families, try to find one that supports both
    uint32_t graphicsQueueNodeIndex = UINT32_MAX;
    for (uint32_t i = 0; i < info.queue_count; i++) {
        if ((info.queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
            if (supportsPresent[i] == VK_TRUE) {
                graphicsQueueNodeIndex = i;
                break;
            }
        }
    }
    free(supportsPresent);

    // Generate error if could not find a queue that supports both a graphics
    // and present
    if (graphicsQueueNodeIndex == UINT32_MAX) {
        std::cout << "Could not find a queue that supports both graphics and "
                     "present\n";
        exit(-1);
    }

    info.graphics_queue_family_index = graphicsQueueNodeIndex;

    init_device(info);

    // Get the list of VkFormats that are supported:
    uint32_t formatCount;
    res = vkGetPhysicalDeviceSurfaceFormatsKHR(info.gpus[0], info.surface,
                                               &formatCount, NULL);
    assert(res == VK_SUCCESS);
    VkSurfaceFormatKHR *surfFormats =
        (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
    res = vkGetPhysicalDeviceSurfaceFormatsKHR(info.gpus[0], info.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.
    if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) {
        info.format = VK_FORMAT_B8G8R8A8_UNORM;
    } else {
        assert(formatCount >= 1);
        info.format = surfFormats[0].format;
    }

    VkSurfaceCapabilitiesKHR surfCapabilities;

    res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(info.gpus[0], info.surface,
                                                    &surfCapabilities);
    assert(res == VK_SUCCESS);

    uint32_t presentModeCount;
    res = vkGetPhysicalDeviceSurfacePresentModesKHR(info.gpus[0], info.surface,
                                                    &presentModeCount, NULL);
    assert(res == VK_SUCCESS);
    VkPresentModeKHR *presentModes =
        (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR));

    res = vkGetPhysicalDeviceSurfacePresentModesKHR(
        info.gpus[0], info.surface, &presentModeCount, presentModes);
    assert(res == VK_SUCCESS);

    VkExtent2D swapChainExtent;
    // width and height are either both -1, or both not -1.
    if (surfCapabilities.currentExtent.width == (uint32_t)-1) {
        // If the surface size is undefined, the size is set to
        // the size of the images requested.
        swapChainExtent.width = info.width;
        swapChainExtent.height = info.height;
    } else {
        // If the surface size is defined, the swap chain size must match
        swapChainExtent = surfCapabilities.currentExtent;
    }

    // If mailbox mode is available, use it, as is the lowest-latency non-
    // tearing mode.  If not, try IMMEDIATE which will usually be available,
    // and is fastest (though it tears).  If not, fall back to FIFO which is
    // always available.
    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;
        }
    }

    // Determine the number of VkImage's to use in the swap chain (we desire to
    // own only 1 image at a time, besides the images being displayed and
    // queued for display):
    uint32_t desiredNumberOfSwapChainImages =
        surfCapabilities.minImageCount + 1;
    if ((surfCapabilities.maxImageCount > 0) &&
        (desiredNumberOfSwapChainImages > surfCapabilities.maxImageCount)) {
        // Application must settle for fewer images than desired:
        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 = info.surface;
    swap_chain.minImageCount = desiredNumberOfSwapChainImages;
    swap_chain.imageFormat = info.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 = VK_NULL_HANDLE;
    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(info.device, &swap_chain, NULL, &info.swap_chain);
    assert(res == VK_SUCCESS);

    res = vkGetSwapchainImagesKHR(info.device, info.swap_chain,
                                  &info.swapchainImageCount, NULL);
    assert(res == VK_SUCCESS);

    VkImage *swapchainImages =
        (VkImage *)malloc(info.swapchainImageCount * sizeof(VkImage));
    assert(swapchainImages);
    res = vkGetSwapchainImagesKHR(info.device, info.swap_chain,
                                  &info.swapchainImageCount, swapchainImages);
    assert(res == VK_SUCCESS);

    info.buffers.resize(info.swapchainImageCount);

    // Going to need a command buffer to send the memory barriers in
    // set_image_layout but we couldn't have created one before we knew
    // what our graphics_queue_family_index is, but now that we have it,
    // create the command buffer

    init_command_pool(info);
    init_command_buffer(info);
    execute_begin_command_buffer(info);
    vkGetDeviceQueue(info.device, info.graphics_queue_family_index, 0,
                     &info.queue);

    for (uint32_t i = 0; i < info.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 = info.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;

        info.buffers[i].image = swapchainImages[i];

        set_image_layout(info, info.buffers[i].image, VK_IMAGE_ASPECT_COLOR_BIT,
                         VK_IMAGE_LAYOUT_UNDEFINED,
                         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);

        color_image_view.image = info.buffers[i].image;

        res = vkCreateImageView(info.device, &color_image_view, NULL,
                                &info.buffers[i].view);
        assert(res == VK_SUCCESS);
    }
    free(swapchainImages);
    execute_end_command_buffer(info);
    execute_queue_command_buffer(info);
    /* VULKAN_KEY_END */

    /* Clean Up */
    VkCommandBuffer cmd_bufs[1] = {info.cmd};
    vkFreeCommandBuffers(info.device, info.cmd_pool, 1, cmd_bufs);
    vkDestroyCommandPool(info.device, info.cmd_pool, NULL);
    for (uint32_t i = 0; i < info.swapchainImageCount; i++) {
        vkDestroyImageView(info.device, info.buffers[i].view, NULL);
    }
    vkDestroySwapchainKHR(info.device, info.swap_chain, NULL);
    destroy_device(info);
    destroy_window(info);
    destroy_instance(info);

    return 0;
}