Vulkan学习(三):小结

Vulkan程序结构

		 initWindow()  //初始化window
		 initVulkan()  //初始化Vulkan
		 mainLoop()    //渲染循环
		 cleanup()     //释放资源

initWindow

   创建窗体,一般选择创建窗口图形库进行创建。如(GLFW)

		
		glfwInit(); 
		glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
		glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); 
		GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);

initVulkan

   包括:

		createInstance();      //创建Vulkan实例
		createSurface();       //创建Surface
		setupDebugMessenger(); //启动调试信息
		pickPhysicalDevice();  //选择显卡
		createLogicalDevice(); //创建逻辑设备
		createSwapChain();     //创建SwapChain
		createImageViews();    //创建视图

createInstance

		createInstance()
		  -- checkValidationLayerSupport()  //创建实例时检测是否启用验证层
		  		-vkEnumerateInstanceLayerProperties() //查询验证层属性信息
		  -- vkCreateInstance()  //创建实例,包括相关配置信息
		  		-VkApplicationInfo
		  			.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO
		  			.pApplicationName = "Hello Triangle"
		  			.applicationVersion = VK_MAKE_VERSION(1, 0, 0)
		  			.pEngineName = "No Engine"
		  			.engineVersion = VK_MAKE_VERSION(1, 0, 0)
		  			.apiVersion = VK_API_VERSION_1_0
		  		-VkInstanceCreateInfo
		  			.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO
		  			.pApplicationName = "Hello Triangle"
		  			.pApplicationInfo = &VkApplicationInfo
		  			 //指定全局扩展
		  			.enabledExtensionCount = glfwGetRequiredInstanceExtensions   //参数
		  			.ppEnabledExtensionNames = glfwGetRequiredInstanceExtensions //返回值
		  			 //验证层信息
		  			.enabledLayerCount = tatic_cast<uint32_t>(validationLayers.size()) //or 0
		  			.ppEnabledLayerNames = validationLayers.data()    				   //or not
		  			 //额外的调试信息
		  			.VkDebugUtilsMessengerCreateInfoEXT
		  				-sType
		  				-messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
									VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
									VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
		  				-messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
									VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
									VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
		  				-pfnUserCallback = debugCallback
		  			.pNext = &VkDebugUtilsMessengerCreateInfoEXT
		  			 //扩展信息
		  			.enabledExtensionCount = static_cast<uint32_t>(extensions.size())
		  			.ppEnabledExtensionNames = extensions.data()
		  				.getRequiredExtensions() 			 	 //返回值是extensions
		  					 //参数值是glfwExtensionCount,返回值是glfwExtensions
		  					.glfwGetRequiredInstanceExtensions() //指定GLFW扩展,debug messenger 扩展是有条件添加的
	    --vkEnumerateInstanceExtensionProperties()  //支持扩展的数量
	    --vkEnumerateInstanceExtensionProperties()  //支持的扩展详细信息

createSurface

		--Windows的创建方法
			VkWin32SurfaceCreateInfoKHR createInfo = {};
			createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
			createInfo.hwnd = glfwGetWin32Window(window);
			createInfo.hinstance = GetModuleHandle(nullptr);
			if (vkCreateWin32SurfaceKHR(instance, &createInfo, nullptr, &surface) != VK_SUCCESS) {
				throw std::runtime_error("failed to create window surface!");
			}
			
		--Linux的创建方法与上面类似 vkCreateXcbSurfaceKHR
		
		--使用GLFWWindow surface
			if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {
				throw std::runtime_error("failed to create window surface!");
			
			}

setupDebugMessenger

		--VkDebugUtilsMessengerCreateInfoEXT
			-sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT
			-messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
							VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
							VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
			-messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
						VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
						VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
			-pfnUserCallback = debugCallback
			
			-debugCallback
					.VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
					.VkDebugUtilsMessageTypeFlagsEXT messageType,
					.const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData)
			-CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger)

pickPhysicalDevice

		--vkEnumeratePhysicalDevices();
		--rateDeviceSuitability() //使用有序Map,通过分数自动对显卡排序
			-VkPhysicalDeviceProperties
				.deviceType = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
				.limits = maxImageDimension2D
			-vkGetPhysicalDeviceProperties()
			-VkPhysicalDeviceFeatures
				.geometryShader
			-vkGetPhysicalDeviceFeatures()

createLogicalDevice

		--findQueueFamilies();
			-vkGetPhysicalDeviceQueueFamilyProperties()
				.std::vector<VkQueueFamilyProperties>  queueFamilies
				.vkGetPhysicalDeviceSurfaceSupportKHR()
					int i = 0;
					for (const auto& queueFamily : queueFamilies) {
						//寻找一个队列,它能够链接window
						VkBool32 presentSupport = false;
						vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
						if (presentSupport) {
							indices.presentFamily = i;
						}
						if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
							indices.graphicsFamily = i;
							if (indices.isComplete())
								break;
						}
							i++;
					}
		--VkDeviceQueueCreateInfo
			-sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO
			-queueFamilyIndex = indices.graphicsFamily.value() 
			-queueCount = 1
			-queuePriority = 1.0f; //队列分配优先级
			-pQueuePriorities =  &queuePriority
		--std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
			-VkDeviceQueueCreateInfo
				.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO
				.queueFamilyIndex = queueFamily
				.queueCount = 1
				.pQueuePriorities = &queuePriority
		--VkPhysicalDeviceFeatures
			-sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO
			-pQueueCreateInfos = &queueCreateInfo
			-queueCreateInfoCount = 1
			-pEnabledFeatures = &deviceFeatures
			-enabledLayerCount = static_cast<uint32_t>(validationLayers.size())
			-ppEnabledLayerNames = validationLayers.data()
			-queueCreateInfoCount =static_cast<uint32_t>(queueCreateInfos.size())
			-pQueueCreateInfos = queueCreateInfos.data()
			-enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size())
			-ppEnabledExtensionNames = deviceExtensions.data()
		--vkCreateDevice(physicalDevice, &createInfo, nullptr, &device)
		//获取驱动队列 & ]显示队列
		--vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue)
		--vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue)
			

createSwapChain

		--querySwapChainSupport()
			-vkGetPhysicalDeviceSurfaceCapabilitiesKHR()
				.SwapChainSupportDetails
			-vkGetPhysicalDeviceSurfaceFormatsKHR()
			-vkGetPhysicalDeviceSurfacePresentModesKHR()
		--chooseSwapSurfaceFormat()
			for (const auto& availableFormat : availableFormats) {
				if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB 
					&& availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
					return availableFormat;
				}
			}
		--chooseSwapPresentMode()
			for (const auto& availablePresentMode : availablePresentModes) {
				if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
					 return availablePresentMode;
				}
			}
		--chooseSwapExtent()
			VkExtent2D actualExtent = { WIDTH, HEIGHT };
			actualExtent.width = std::max(capabilities.minImageExtent.width,
					std::min(capabilities.maxImageExtent.width, actualExtent.width));
			actualExtent.height = std::max(capabilities.minImageExtent.height,
					std::min(capabilities.maxImageExtent.height, actualExtent.height));
				return actualExtent;
		--VkSwapchainCreateInfoKHR
			-sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR
			-surface = surface
			-minImageCount = imageCount
			-imageFormat = surfaceFormat.format
			-imageColorSpace = surfaceFormat.colorSpace
			-imageExtent = extent
			-imageArrayLayers = 1
			-imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
			-imageSharingMode = VK_SHARING_MODE_CONCURRENT
			-queueFamilyIndexCount = 2
			-pQueueFamilyIndices = queueFamilyIndices
			-preTransform = swapChainSupport.capabilities.currentTransform;
			-compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR
			-presentMode = presentMode
			-clipped = VK_TRUE
			-oldSwapchain = VK_NULL_HANDLE
		--vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain)
		--vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr)
		--vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
		

createSwapChain

		--VkImageViewCreateInfo
			-sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO
			-image = swapChainImages[i]
			-viewType = VK_IMAGE_VIEW_TYPE_2D
			-format = swapChainImageFormat
			-components.r = VK_COMPONENT_SWIZZLE_IDENTITY
			-components.g = VK_COMPONENT_SWIZZLE_IDENTITY
			-components.b = VK_COMPONENT_SWIZZLE_IDENTITY
			-components.a = VK_COMPONENT_SWIZZLE_IDENTITY
			-subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT
			-subresourceRange.baseMipLevel = 0
			-subresourceRange.levelCount = 1
			-subresourceRange.baseArrayLayer = 0
			-subresourceRange.layerCount = 1
		--vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i])

mainLoop

		while (!glfwWindowShouldClose(window)) {
			 glfwPollEvents();
		}

cleanup

		--vkDestroyImageView(device, imageView, nullptr)
		--vkDestroySwapchainKHR(device, swapChain, nullptr)
		--DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr)
			auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)
				vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
			if (func != nullptr) {
				func(instance, debugMessenger, pAllocator);
			}
		--vkDestroyDevice(device, nullptr)
		--vkDestroySurfaceKHR(instance, surface, nullptr)
		--vkDestroyInstance(instance, nullptr)
		--glfwDestroyWindow(window)
		--glfwTerminate()

Code

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>

#include <vulkan/vulkan.h>

#include <iostream>
#include <GLFW/glfw3.h>

#include <vulkan/vulkan.h>

#include <iostream>  //[1]
#include <stdexcept> //[1]异常处理函数
#include <functional>//[1]提供 EXIT_SUCCESS and EXIT_FAILURE 宏指令
#include <cstdlib>
#include <vector>
#include <map>
#include <optional>
#include <set>
#include <cstdint> // Necessary for UINT32_MAX

const int WIDTH = 800;
const int HEIGHT = 600;

//[4]所有有用的标准验证都捆绑到SDK的一个层中,称为VK_LAYER_KHRONOS_validation层。
const std::vector<const char*> validationLayers = {
	"VK_LAYER_KHRONOS_validation"
 };
//[12]检查是否支持SWAPCHAIN
const std::vector<const char*> deviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
//[4]验证层Debug时开启
#ifdef NDEBUG
 const bool enableValidationLayers = false;
#else
 const bool enableValidationLayers = true;
#endif
struct QueueFamilyIndices {
	std::optional<uint32_t> graphicsFamily;
	std::optional<uint32_t> presentFamily;
	//[8]为了方便起见,我们还将向结构本身添加一个泛型检查
	bool isComplete() {
		return graphicsFamily.has_value() && presentFamily.has_value();
	}
};

struct SwapChainSupportDetails {
	VkSurfaceCapabilitiesKHR capabilities;
	std::vector<VkSurfaceFormatKHR> formats;
	std::vector<VkPresentModeKHR> presentModes;
};

class HelloTriangleApplication
{

public:
	void run() 
	{
		initWindow(); //[2]
		initVulkan(); //[1]初始化Vulakn相关
		mainLoop();   //[1]渲染循环(start rendering frames) 
		cleanup();    //[1]释放资源
	}
private:
	void initWindow() {
		glfwInit();   //[2]初始化GLFW库
		//[2]由于glfw原本是用来创建OpenGL Context的,因此需要使用GLFW_NO_API(不进行OpenGL Context创建)
		glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
		glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); //[2]关闭重置窗口
		//[2]创建窗体
		window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
	}
	void initVulkan() 
	{
		//[3]创建Vulkan实例
		createInstance();
		//[10]
		createSurface();
		//[6]
		setupDebugMessenger();
		//[7]
		pickPhysicalDevice();
		//[8]
		createLogicalDevice();
		//[12]
		createSwapChain();
		//[13]
		createImageViews();
	}

	void mainLoop()
	{
		//[2]窗口关门,终止渲染
		while (!glfwWindowShouldClose(window)) {
			 glfwPollEvents();
		}
	}

	void cleanup() 
	{
		//[13]
		for (auto imageView : swapChainImageViews) {
			vkDestroyImageView(device, imageView, nullptr);
		}

		vkDestroySwapchainKHR(device, swapChain, nullptr);
		//[6]销毁代理函数
		if (enableValidationLayers) {
			DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
		}
		//[9]销毁逻辑驱动
		vkDestroyDevice(device, nullptr);
		//[10]销毁
		vkDestroySurfaceKHR(instance, surface, nullptr);
		//[3]销毁实例
		vkDestroyInstance(instance, nullptr);
		//[2]释放资源
		glfwDestroyWindow(window);
		glfwTerminate();
	}
	void createInstance() {

		//[4]创建实例时检测是否启用验证层
		if (enableValidationLayers && !checkValidationLayerSupport()) {
			throw std::runtime_error("validation layers requested, but not available!");
		}

		//[3]well-known graphics engine 
		VkApplicationInfo appInfo = {};
		//[3]结构体必须指明类型,pNext指向拓展信息
		appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
		appInfo.pApplicationName = "Hello Triangle";
		appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
		appInfo.pEngineName = "No Engine";
		appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
		appInfo.apiVersion = VK_API_VERSION_1_0;
		
		//[3]Vulkan驱动程序使用哪些全局扩展和验证,后续后详细说明 
		VkInstanceCreateInfo createInfo = {};
		createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
		createInfo.pApplicationInfo = &appInfo;
		

		//[3]指定全局扩展
		uint32_t glfwExtensionCount = 0;
		const char** glfwExtensions;
		glfwExtensions =
			glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
		createInfo.enabledExtensionCount = glfwExtensionCount;
		createInfo.ppEnabledExtensionNames = glfwExtensions;
		//[3]the global validation layers to enable
		createInfo.enabledLayerCount = 0; //后续有说明
		//[5]验证层信息
		//[5]如果检查成功,那么vkCreateInstance不会返回VK_ERROR_LAYER_NOT_PRESENT错误
		if (enableValidationLayers) {
			createInfo.enabledLayerCount =
				static_cast<uint32_t>(validationLayers.size());
			createInfo.ppEnabledLayerNames = validationLayers.data();
		}
		else {
			createInfo.enabledLayerCount = 0;
		}
		//[5]GLFW
		auto extensions = getRequiredExtensions();
		createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
		createInfo.ppEnabledExtensionNames = extensions.data();

		//[6]重用
		//[6]通过该方式创建一个额外的调试信息,它将在vkCreateInstance和vkDestroyInstance期间自动创建和销毁
		VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;
		if (enableValidationLayers) {
			createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
			createInfo.ppEnabledLayerNames = validationLayers.data();
			populateDebugMessengerCreateInfo(debugCreateInfo);
			createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)&debugCreateInfo;
		}
		else {
			createInfo.enabledLayerCount = 0;
			createInfo.pNext = nullptr;
		}
		//[6]or
		/*if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
			throw std::runtime_error("failed to set up debug messenger!");
		}*/
		//[3]	VK_SUCCESS or Error Code
		//[3]VkResult result = vkCreateInstance(&createInfo, nullptr, &instance);
		//[3]or
		//[3]创建实例
		if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS)
		{
			 throw std::runtime_error("failed to create instance!");
			 /*
			 * //[4]验证层说明,Vulkan每次调用都会进行相应的验证,通过返回值判定函数是否执行成功
			 VkResult vkCreateInstance(
				 const VkInstanceCreateInfo * pCreateInfo,
				 const VkAllocationCallbacks * pAllocator,
				 VkInstance * instance) {

					 if (pCreateInfo == nullptr || instance == nullptr) {
						 log("Null pointer passed to required parameter!");
						 return VK_ERROR_INITIALIZATION_FAILED;

					 }
				 return real_vkCreateInstance(pCreateInfo, pAllocator, instance);
			 }
			 */

		}
		
		//[3]the number of extensions
		//[3]支持扩展的数量
		uint32_t extensionCount = 0;
		vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
		//[3]an array of VkExtensionProperties to store details of the extensions.
		//[3]an array to hold the extension details
		//[3]支持的扩展详细信息
		std::vector<VkExtensionProperties> extensionsProperties(extensionCount);
		vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensionsProperties.data());

		//[3]query the extension details
		//[3]Each VkExtensionProperties struct contains the name and version of an extension.
		//[3]查询扩展的详细信息
		std::cout << "available extensions:" << std::endl;
		for (const auto& extension : extensionsProperties) {
			std::cout << "\t" << extension.extensionName << std::endl;
		}
		
	}
	//[4]list all of the available layers
	//[4]列出所有验证层的信息
	bool checkValidationLayerSupport() {
		
		uint32_t layerCount;
		vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
		
		std::vector<VkLayerProperties> availableLayers(layerCount);
		vkEnumerateInstanceLayerProperties(&layerCount,
		availableLayers.data());
		//[4]查询是否存在验证层信息 layerName = VK_LAYER_KHRONOS_validation
		for (const char* layerName : validationLayers) {
			bool layerFound = false;

			for (const auto& layerProperties : availableLayers) {
				if (strcmp(layerName, layerProperties.layerName) == 0) {
					layerFound = true;
					break;
				}
			}

			if (!layerFound) {
				return false;
			}
		}

		return true;
	}
	//[5]we have to set up a debug messenger with a callback using the VK_EXT_debug_utils extension.
	//[5]我们必须使用VK_EXT_debug_utils扩展,设置一个带有回调的debug messenger。
	std::vector<const char*> getRequiredExtensions() {
		//[5]指定GLFW扩展,但是debug messenger 扩展是有条件添加的
		uint32_t glfwExtensionCount = 0;
		const char** glfwExtensions;
		glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
		std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
		if (enableValidationLayers) {
			//[5]在这里使用VK_EXT_DEBUG_UTILS_EXTENSION_NAME宏,它等于字符串“VK_EXT_debug_utils”。
			//[5]使用此宏可以避免输入错误
			extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);

		}
		return extensions;
	}
	//[5]Add a new static member function called debugCallback with 
	//[5]	the PFN_vkDebugUtilsMessengerCallbackEXT prototype.
	//[5]使用PFN_vkDebugUtilsMessengerCallbackEXT属性添加一个静态函数
	//[5]The VKAPI_ATTR and VKAPI_CALL ensure that the function has the
	//[5]	right signature for Vulkan to call it.
	//[5]使用VKAPI_ATTR和VKAPI_CALL 确保函数具有正确的签名,以便Vulkan调用它
	static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
		//[5]VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT 诊断信息
		//[5]VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT 信息性消息,如资源的创建
		//[5]关于行为的消息,其不一定是错误,但很可能是应用程序中的BUG
		//[5]VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
		//[5]关于无效且可能导致崩溃的行为的消息
		//[5]VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT
		//[5]可以使用比较操作来检查消息是否与某个严重性级别相等或更差,例如:
		//[5]if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
		//[5]	// Message is important enough to show
		//[5]}
		VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
		//[6]VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT 发生了一些与规范或性能无关的事件
		//[6]VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT 发生了违反规范或一些可能显示的错误
		//[6]VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT 非最优的方式使用Vulkan
		VkDebugUtilsMessageTypeFlagsEXT messageType,
		//[6]消息本身的详细信息, 包括其重要成员:
		//[6]pMessage 以null结尾的调试消息字符串
		//[6]pObjects 与消息相关的Vulkan对象句柄数组
		//[6]objectCount 数组中的对象数
		//[6]pUserData 包含回调指定的指针,允许将自己设置的数据传递给它。
		const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
		void* pUserData) {
		std::cerr << "validation layer: " << pCallbackData->pMessage <<
			std::endl;

		return VK_FALSE;
		

	}

	void setupDebugMessenger() {
		if (!enableValidationLayers) return;

		VkDebugUtilsMessengerCreateInfoEXT createInfo = {};
		populateDebugMessengerCreateInfo(createInfo);
		//[6] messenger创建信息的填充提取到单独的函数中
		if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr,
			&debugMessenger) != VK_SUCCESS) {
			throw std::runtime_error("failed to set up debug messenger!");
		}
		//[6]or
		//  createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
		//[6]指定希望调用回调严重性类型
		//createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
		//	VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
		//	VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
		//[6]滤回调通知的消息类型
		//createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | 
		//	VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
		//	VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
		//[6]指定指向回调函数的指针
		//createInfo.pfnUserCallback = debugCallback;
		//[6]返回的回调函数
		//createInfo.pUserData = nullptr; 


	}
	//[6]创建代理函数
	VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const
		VkDebugUtilsMessengerCreateInfoEXT * pCreateInfo, const
		VkAllocationCallbacks * pAllocator, VkDebugUtilsMessengerEXT *
		pDebugMessenger) {
		auto func = (PFN_vkCreateDebugUtilsMessengerEXT)
			//[6]如果无法加载,函数将返回nullptr。
			vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
		if (func != nullptr) {
			return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
		}
		else {
			return VK_ERROR_EXTENSION_NOT_PRESENT;
		}
	}
	//[6]创建代理函数 销毁CreateDebugUtilsMessengerEXT
	void DestroyDebugUtilsMessengerEXT(VkInstance instance,
		VkDebugUtilsMessengerEXT debugMessenger, const
		VkAllocationCallbacks* pAllocator) {
		auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)
			vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
		if (func != nullptr) {
			func(instance, debugMessenger, pAllocator);
		}
	}

	//[6]仔细阅读扩展文档,就会发现有一种方法可以专门为这两个函数调用创建单独的debug utils messenger。
	//[6]它要求您只需在VkInstanceCreateInfo的pNext扩展字段中
	//[6]传递一个指向VkDebugUtilsMessengerCreateInfoEXT结构的指针。
	//[6]首先将messenger创建信息的填充提取到单独的函数中:
	void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT&
			createInfo) {
		createInfo = {};
		createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
		createInfo.messageSeverity =
			VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
			VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
			VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
		createInfo.messageType =
			VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
			VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
			VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
		createInfo.pfnUserCallback = debugCallback;
	}
	void pickPhysicalDevice() {
		//[7]查询GPU数量
		uint32_t deviceCount = 0;
		vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
		if (deviceCount == 0) {
			throw std::runtime_error("failed to find GPUs with Vulkan support!");
		}
		//[7]获取驱动信息
		std::vector<VkPhysicalDevice> devices(deviceCount);
		vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
		//[7]选择适合该程序的GPU
		for (const auto& device : devices) {
			if (isDeviceSuitable(device)) {
				physicalDevice = device;
				break;
			}
		}
		if (physicalDevice == VK_NULL_HANDLE) {
			throw std::runtime_error("failed to find a suitable GPU!");
		}
		//or
		//[7]使用有序Map,通过分数自动对显卡排序
		std::multimap<int, VkPhysicalDevice> candidates;
		for (const auto& device : devices) {
			int score = rateDeviceSuitability(device);
			candidates.insert(std::make_pair(score, device));
			
		}
		// Check if the best candidate is suitable at all
		if (candidates.rbegin()->first > 0) {
			physicalDevice = candidates.rbegin()->second;
		}
		else {
			throw std::runtime_error("failed to find a suitable GPU!");	
		}

	}

	//[7]GPU是否适合该程序的
	bool isDeviceSuitable(VkPhysicalDevice device) {

		//[7]查询显卡属性,包括:名称,支持Vulkan的版本号
		//VkPhysicalDeviceProperties deviceProperties;
		//vkGetPhysicalDeviceProperties(device, &deviceProperties);
		//[11]扩展支持
		bool extensionsSupported = checkDeviceExtensionSupport(device);
		//[12]swap chain support
		bool swapChainAdequate = false;
		if (extensionsSupported) {
			SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device);
			swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
		}
		//[7]查询显卡特性,包括:纹理压缩,64位浮点述。多视口渲染(VR)
		//VkPhysicalDeviceFeatures deviceFeatures;
		//vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
		//[7]是否为专业显卡(a dedicated graphics card )(独显),是否支持几何着色器
		//return deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && deviceFeatures.geometryShader;
		//or
		QueueFamilyIndices indices = findQueueFamilies(device);
		//return indices.graphicsFamily.has_value();
		//or
		return indices.isComplete() && extensionsSupported && swapChainAdequate;
	}

	int rateDeviceSuitability(VkPhysicalDevice device) {
		
		//[7]查询显卡属性,包括:名称,支持Vulkan的版本号
		VkPhysicalDeviceProperties deviceProperties;
		vkGetPhysicalDeviceProperties(device, &deviceProperties);

		int score = 0;
		//离散GPU具有显著的性能优势
		if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
			score += 1000;
		}
		//支持纹理的最大值,影响图形质量
		score += deviceProperties.limits.maxImageDimension2D;

		//[7]查询显卡特性,包括:纹理压缩,64位浮点述。多视口渲染(VR)
		VkPhysicalDeviceFeatures deviceFeatures;
		vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
		// 不支持几何着色器
		if (!deviceFeatures.geometryShader) {
			return 0;
		}
		return score;
		
	}
	//[8]
	QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
		//[8]Logic to find graphics queue family
		QueueFamilyIndices indices;
		//[8]Logic to find queue family indices to populate struct with
		//[8]C++ 17引入了optional数据结构来区分存在或不存在的值的情况。
		//[8]std::optional<uint32_t> graphicsFamily;
		//[8]std::cout << std::boolalpha << graphicsFamily.has_value() <<std::endl; // false
		//[8]graphicsFamily = 0;
		//[8]std::cout << std::boolalpha << graphicsFamily.has_value() << std::endl; // true

		uint32_t queueFamilyCount = 0;
		vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
		std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
		vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
		//我们需要找到至少一个支持VK_QUEUE_GRAPHICS_BIT的族。
		int i = 0;
		for (const auto& queueFamily : queueFamilies) {
			//[10]寻找一个队列族,它能够链接window
			VkBool32 presentSupport = false;
			vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
			if (presentSupport) {
				indices.presentFamily = i;
			}
			if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
				indices.graphicsFamily = i;
				if (indices.isComplete())
					break;
			}
				i++;
		}
		
		return indices;
	}

	void createLogicalDevice() {
		QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
		VkDeviceQueueCreateInfo queueCreateInfo = {};
		queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
		queueCreateInfo.queueFamilyIndex = indices.graphicsFamily.value();
		queueCreateInfo.queueCount = 1;
		//[9]Vulkan使用0.0到1.0之间的浮点数为队列分配优先级, 来进行缓冲区执行的调度。即使只有一个队列,这也是必需的:
		float queuePriority = 1.0f;
		queueCreateInfo.pQueuePriorities = &queuePriority;
		//[9]device features
		VkPhysicalDeviceFeatures deviceFeatures = {};

		VkDeviceCreateInfo createInfo = {};
		createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
		createInfo.pQueueCreateInfos = &queueCreateInfo;
		createInfo.queueCreateInfoCount = 1;
		createInfo.pEnabledFeatures = &deviceFeatures;

		//[9]VK_KHR_swapchain 将该设备的渲染图像显示到windows
		//[9]之前版本Vulkan实现对实例和设备特定的验证层进行了区分,但现在情况不再如此。
		//[9]这意味着VkDeviceCreateInfo的enabledLayerCount和ppEnabledLayerNames字段被最新的实现忽略。不过,还是应该将它们设置为与较旧的实现兼容:
		createInfo.enabledExtensionCount = 0;
		if (enableValidationLayers) {
			createInfo.enabledLayerCount =	static_cast<uint32_t>(validationLayers.size());
			createInfo.ppEnabledLayerNames = validationLayers.data();

		}
		else {
			createInfo.enabledLayerCount = 0;
			
		}

		//[10]create a queue from both families
		std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
		std::set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value(), indices.presentFamily.value() };
		queuePriority = 1.0f;
		for (uint32_t queueFamily : uniqueQueueFamilies) {
			VkDeviceQueueCreateInfo queueCreateInfo = {};
			queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
			queueCreateInfo.queueFamilyIndex = queueFamily;
			queueCreateInfo.queueCount = 1;
			queueCreateInfo.pQueuePriorities = &queuePriority;
			queueCreateInfos.push_back(queueCreateInfo);

		}
		//[10]将队列信息加入驱动info
		createInfo.queueCreateInfoCount =
			static_cast<uint32_t>(queueCreateInfos.size());
		createInfo.pQueueCreateInfos = queueCreateInfos.data();
		//[11]开启扩展支持
		createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
		createInfo.ppEnabledExtensionNames = deviceExtensions.data();
		//[9]创建驱动
		if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
			throw std::runtime_error("failed to create logical device!");
		}
		//[9]获取驱动队列
		//[9]因为我们只从这个族中创建一个队列,所以我们只使用索引0
		vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
		//[10]显示队列
		vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);

	}
	void createSurface() {

		Windows的创建方法
		//VkWin32SurfaceCreateInfoKHR createInfo = {};
		//createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
		//createInfo.hwnd = glfwGetWin32Window(window);
		//createInfo.hinstance = GetModuleHandle(nullptr);
		//if (vkCreateWin32SurfaceKHR(instance, &createInfo, nullptr, &surface) != VK_SUCCESS) {
		//	throw std::runtime_error("failed to create window surface!");
		//}
		Linux的创建方法与上面类似 vkCreateXcbSurfaceKHR
		//[10]使用GLFWWindow surface
		if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {
			throw std::runtime_error("failed to create window surface!");

		}
	}
	bool checkDeviceExtensionSupport(VkPhysicalDevice device) {
	
		uint32_t extensionCount;
		vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
		std::vector<VkExtensionProperties> availableExtensions(extensionCount);
		vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
		std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());

		for(const auto& extension : availableExtensions) {
			requiredExtensions.erase(extension.extensionName);
		}
		return requiredExtensions.empty();
	}
	//[12]
	SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) {
		SwapChainSupportDetails details;
		//[12]basic surface capabilities 基本性能
		vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
		//[12]the supported surface formats
		uint32_t formatCount;
		vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount,	nullptr);
		if (formatCount != 0) {
			details.formats.resize(formatCount);
			vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());

		}
		//[12]the supported presentation modes
		uint32_t presentModeCount;
		vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
		if (presentModeCount != 0) {
			details.presentModes.resize(presentModeCount);
			vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
		}
		return details;
		
	}
	//[12]
	VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>&availableFormats) {

		for (const auto& availableFormat : availableFormats) {
			if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB 
				&& availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
				return availableFormat;
			}
		}
		//[12]如果查询失败返回第一个
		return availableFormats[0];
	}
	//[12]VK_PRESENT_MODE_IMMEDIATE_KHR
	//[12]VK_PRESENT_MODE_FIFO_KHR
	//[12]VK_PRESENT_MODE_FIFO_RELAXED_KHR
	//[12]VK_PRESENT_MODE_MAILBOX_KHR
	VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR>&availablePresentModes) {
		//[12]三级缓存更好,如果有就开启
		for (const auto& availablePresentMode : availablePresentModes) {
			if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
				 return availablePresentMode;
			}
		}
		return VK_PRESENT_MODE_FIFO_KHR;
	}
	//[12]在minImageExtent和maxImageExtent内选择与窗口最匹配的分辨率
	VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {
		if (capabilities.currentExtent.width != UINT32_MAX) {
			return capabilities.currentExtent;
		}
		else {
			VkExtent2D actualExtent = { WIDTH, HEIGHT };
			actualExtent.width = std::max(capabilities.minImageExtent.width,
					std::min(capabilities.maxImageExtent.width, actualExtent.width));
			actualExtent.height = std::max(capabilities.minImageExtent.height,
					std::min(capabilities.maxImageExtent.height, actualExtent.height));
				return actualExtent;
		}
	}

	void createSwapChain() {
		SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);
		VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
		VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
		VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);
		//[12]然而,简单地坚持这个最小值意味着我们有时可能需要等待驱动程序完成内部操作,
		//[12]然后才能获取另一个要渲染的图像。因此,建议请求至少比最小值多一个图像:
		//[12]uint32_t imageCount = swapChainSupport.capabilities.minImageCount;
		uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
		if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {
			imageCount = swapChainSupport.capabilities.maxImageCount;
		}

		VkSwapchainCreateInfoKHR createInfo = {};
		createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
		createInfo.surface = surface;

		createInfo.minImageCount = imageCount;
		createInfo.imageFormat = surfaceFormat.format;
		createInfo.imageColorSpace = surfaceFormat.colorSpace;
		createInfo.imageExtent = extent;
		//[12]imageArrayLayers指定每个图像包含的层的数量。除非您正在开发3D应用程序,否则该值始终为1。
		createInfo.imageArrayLayers = 1;
		createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;

		//[12]两种方法可以处理从多个队列访问的图像:
		//[12]VK_SHARING_MODE_CONCURRENT
		//[12]VK_SHARING_MODE_EXCLUSIVE
		QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
		uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(),
		indices.presentFamily.value() };
		if (indices.graphicsFamily != indices.presentFamily) {
			createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
			createInfo.queueFamilyIndexCount = 2;
			createInfo.pQueueFamilyIndices = queueFamilyIndices;
		}
		else {
			createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
			createInfo.queueFamilyIndexCount = 0; // Optional
			createInfo.pQueueFamilyIndices = nullptr; // Optional
		}
		//[12]指定对交换链中的图像应用某种变换
		createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
		//[12]alpha channel should be used for blending
		createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
		createInfo.presentMode = presentMode;
		createInfo.clipped = VK_TRUE;
		//[12]窗口重置是取缓存区图像方式
		createInfo.oldSwapchain = VK_NULL_HANDLE;

		if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
			throw std::runtime_error("failed to create swap chain!");
		}

		vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
		swapChainImages.resize(imageCount);
		vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
		swapChainImageFormat = surfaceFormat.format;
		swapChainExtent = extent;
	}


	void createImageViews() {

		swapChainImageViews.resize(swapChainImages.size());
		for (size_t i = 0; i < swapChainImages.size(); i++) {

			VkImageViewCreateInfo createInfo = {};
			createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
			createInfo.image = swapChainImages[i];
			//[13]选择视图类型 1D 2D 3D
			createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
			createInfo.format = swapChainImageFormat;
			//[13]components字段允许旋转颜色通道。 
			createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; //default
			createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
			createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
			createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
			//[13]描述图像的用途以及应访问图像的哪个部分。
			createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
			createInfo.subresourceRange.baseMipLevel = 0;
			createInfo.subresourceRange.levelCount = 1;
			createInfo.subresourceRange.baseArrayLayer = 0;
			createInfo.subresourceRange.layerCount = 1;
			if (vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) {
				throw std::runtime_error("failed to create image views!");
			}

		}
	}
private:
	GLFWwindow* window = nullptr;
	VkInstance instance = nullptr;
	VkDebugUtilsMessengerEXT debugMessenger;
	//[7]当vkinInstance被销毁时,该对象将被隐式销毁,因此不需要在cleanup函数中执行销毁。
	VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
	VkDevice device;
	//[9]当设备被销毁时,设备队列会被隐式清理,因此我们不需要在清理中执行任何操作。
	VkQueue graphicsQueue;
	//[10]Window surface creation
	VkSurfaceKHR surface;
	//[11]连接队列
	VkQueue presentQueue;
	VkSwapchainKHR swapChain;
	//[12]don’t need to add any cleanup code.
	std::vector<VkImage> swapChainImages;
	//[12]store the format and extent we’ve chosen for the swap chain images in member variables
	VkFormat swapChainImageFormat;
	VkExtent2D swapChainExtent;
	//[13]
	std::vector<VkImageView> swapChainImageViews;
};


int main() {
	HelloTriangleApplication app;
	//[1]捕获异常
	try {
		app.run();
	}
	catch (const std::exception& e) {
		std::cerr << e.what() << std::endl;
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值