423 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			423 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
| // VulkanTutorial.cpp: 定义应用程序的入口点。
 | ||
| //
 | ||
| 
 | ||
| #include "VulkanTutorial.h"
 | ||
| 
 | ||
| const int Width = 800;
 | ||
| const int Height = 600;
 | ||
| 
 | ||
| const std::vector<const char*> validationLayers = {
 | ||
| 	"VK_LAYER_KHRONOS_validation"
 | ||
| 
 | ||
| };
 | ||
| 
 | ||
| #ifdef NDEBUG
 | ||
| const bool enableValidationLayers = false;
 | ||
| #else
 | ||
| const bool enableValidationLayers = true;
 | ||
| #endif // NDEBUG
 | ||
| 
 | ||
| //window init
 | ||
| GLFWwindow* HelloTriangleApplication::initWindow(int Width, int Height) {
 | ||
| 	glfwInit();
 | ||
| 	glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
 | ||
| 	glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
 | ||
| 	window = glfwCreateWindow(Width, Height, "vulkan", nullptr, nullptr);
 | ||
| 	return window;
 | ||
| }
 | ||
| // vulkan instace create
 | ||
| void HelloTriangleApplication::createInstance() {
 | ||
| 
 | ||
| 	// check validation layers
 | ||
| 	if (enableValidationLayers && ! checkValidationLayerSupport())
 | ||
| 	{
 | ||
| 		throw std::runtime_error("validation layers requsted,but not available");
 | ||
| 	}
 | ||
| 
 | ||
| 	//setup appliaction info
 | ||
| 	VkApplicationInfo appInfo{};
 | ||
| 	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;
 | ||
| 
 | ||
| 	// setup createInfo
 | ||
| 	VkInstanceCreateInfo createInfo{};
 | ||
| 	createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
 | ||
| 	createInfo.pApplicationInfo = &appInfo;
 | ||
| 
 | ||
| 	auto requiredExtensions = getRequiredExtensions();
 | ||
| 	createInfo.enabledExtensionCount = static_cast<uint32_t>(requiredExtensions.size());
 | ||
| 	createInfo.ppEnabledExtensionNames = requiredExtensions.data();
 | ||
| 	
 | ||
| 
 | ||
| 	/* enable glfw extension in creatInfo
 | ||
| 	uint32_t glfwExtentionCount = 0;
 | ||
| 	const char** glfwExtensions;
 | ||
| 	glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtentionCount);
 | ||
| 	createInfo.enabledExtensionCount = glfwExtentionCount;
 | ||
| 	createInfo.ppEnabledExtensionNames = glfwExtensions;
 | ||
| 	*/
 | ||
| 
 | ||
| 	// enable validation layer if available in createInfo
 | ||
| 	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;
 | ||
| 	}
 | ||
| 
 | ||
| 	// throw error in creating instance
 | ||
| 	if (vkCreateInstance(&createInfo, nullptr, &instance)!=VK_SUCCESS)
 | ||
| 	{
 | ||
| 		throw std::runtime_error("failed to create instance");
 | ||
| 	}
 | ||
| 
 | ||
| 	
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| void HelloTriangleApplication::initVulkan() {
 | ||
| 
 | ||
| 	createInstance();
 | ||
| 
 | ||
| 	showAvailableExtension();
 | ||
| 
 | ||
| 	setupDebugMessenger();
 | ||
| 
 | ||
| 	createSurface();
 | ||
| 
 | ||
| 	pickPhysicalDevice();
 | ||
| 
 | ||
| 	createLogicalDevice();
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| void HelloTriangleApplication::mainLoop(GLFWwindow* window){
 | ||
| 
 | ||
| 	while (!glfwWindowShouldClose(window))
 | ||
| 	{
 | ||
| 		glfwPollEvents();
 | ||
| 	}
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| void HelloTriangleApplication::cleanup(GLFWwindow* window) {
 | ||
| 
 | ||
| 	vkDestroyDevice(device, nullptr);
 | ||
| 
 | ||
| 	if (enableValidationLayers)
 | ||
| 	{
 | ||
| 		DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
 | ||
| 	}
 | ||
| 
 | ||
| 	vkDestroySurfaceKHR(instance, surface, nullptr);
 | ||
| 
 | ||
| 	vkDestroyInstance(instance, nullptr);
 | ||
| 
 | ||
| 	glfwDestroyWindow(window);
 | ||
| 
 | ||
| 	glfwTerminate();
 | ||
| 	
 | ||
| 	
 | ||
| }
 | ||
| 
 | ||
| std::vector<const char*> HelloTriangleApplication::getRequiredExtensions() {
 | ||
| 	uint32_t glfwExtensionCount = 0;
 | ||
| 	const char** glfwExtensions;
 | ||
| 	glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
 | ||
| 
 | ||
| 	std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
 | ||
| 
 | ||
| 	if (enableValidationLayers)
 | ||
| 	{
 | ||
| 		extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
 | ||
| 		
 | ||
| 	}
 | ||
| 
 | ||
| 	return extensions;
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
| void HelloTriangleApplication::showAvailableExtension()
 | ||
| {
 | ||
| 	// show available extensions
 | ||
| 
 | ||
| 	uint32_t availableExtensionCount = 0;
 | ||
| 	vkEnumerateInstanceExtensionProperties(nullptr, &availableExtensionCount, nullptr);
 | ||
| 	std::vector<VkExtensionProperties> availableExtensions(availableExtensionCount);
 | ||
| 	vkEnumerateInstanceExtensionProperties(nullptr, &availableExtensionCount, availableExtensions.data());
 | ||
| 	std::cout << "available extensions :" << std::endl;
 | ||
| 	for (const auto& extension : availableExtensions)
 | ||
| 	{
 | ||
| 		std::cout << "\t" << extension.extensionName << " ver:" << extension.specVersion << std::endl;
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| VKAPI_ATTR VkBool32 VKAPI_CALL HelloTriangleApplication::debugCallback(
 | ||
| 	VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
 | ||
| 	VkDebugUtilsMessageTypeFlagsEXT messageTypes,
 | ||
| 	const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
 | ||
| 	void* pUserData)
 | ||
| {
 | ||
| 	std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl;
 | ||
| 
 | ||
| 	return VK_FALSE;
 | ||
| }
 | ||
| 
 | ||
| void HelloTriangleApplication::setupDebugMessenger()
 | ||
| {
 | ||
| 	if (! enableValidationLayers)
 | ||
| 	{
 | ||
| 		return;
 | ||
| 	}
 | ||
| 
 | ||
| 	VkDebugUtilsMessengerCreateInfoEXT createInfo{};
 | ||
| 	populateDebugMessengerCreateInfo(createInfo);
 | ||
| 
 | ||
| 
 | ||
| 	if (CreateDebugUtilsMessengerEXT(instance,&createInfo,nullptr,&debugMessenger)!= VK_SUCCESS)
 | ||
| 	{
 | ||
| 		throw std::runtime_error("failed to set up debug messenger in setupDebugMessenger");
 | ||
| 	}
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
| void HelloTriangleApplication::populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& 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;
 | ||
| 	createInfo.pUserData = nullptr;
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
| void HelloTriangleApplication::createSurface()
 | ||
| {
 | ||
| 	if (glfwCreateWindowSurface(instance,window,nullptr,&surface) != VK_SUCCESS)
 | ||
| 	{
 | ||
| 		throw std::runtime_error("failed to create window surface in createSurface()");
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void HelloTriangleApplication::pickPhysicalDevice()
 | ||
| {
 | ||
| 	uint32_t deviceCount = 0;
 | ||
| 	vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
 | ||
| 	if (deviceCount==0)
 | ||
| 	{
 | ||
| 		throw std::runtime_error("failed to find GPUs with Vulkan support");
 | ||
| 
 | ||
| 	}
 | ||
| 
 | ||
| 	std::vector<VkPhysicalDevice> devices(deviceCount);
 | ||
| 	vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
 | ||
| 
 | ||
| 	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");
 | ||
| 	}
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
| bool HelloTriangleApplication::isDeviceSuitable(VkPhysicalDevice device)
 | ||
| {
 | ||
| 	QueueFamilyIndices indices = findQueueFamilies(device);
 | ||
| 
 | ||
| 	return indices.isComplete();
 | ||
| }
 | ||
| 
 | ||
| HelloTriangleApplication::QueueFamilyIndices HelloTriangleApplication::findQueueFamilies(VkPhysicalDevice device)
 | ||
| {
 | ||
| 	QueueFamilyIndices indices;
 | ||
| 
 | ||
| 	uint32_t queueFamilyCount = 0;
 | ||
| 	vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
 | ||
| 
 | ||
| 	std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
 | ||
| 	vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
 | ||
| 
 | ||
| 	VkBool32 presentSupport = false;
 | ||
| 	
 | ||
| 
 | ||
| 	int i = 0;
 | ||
| 	vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
 | ||
| 	for (const auto& queueFamily : queueFamilies)
 | ||
| 	{
 | ||
| 		if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
 | ||
| 			indices.graphicsFamily = i;
 | ||
| 		}
 | ||
| 		if (indices.isComplete())
 | ||
| 		{
 | ||
| 			break;
 | ||
| 		}
 | ||
| 		if (presentSupport)
 | ||
| 		{
 | ||
| 			indices.presentFamily = i;
 | ||
| 		}
 | ||
| 
 | ||
| 		i++;
 | ||
| 
 | ||
| 	}
 | ||
| 
 | ||
| 	return indices;
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
| void HelloTriangleApplication::createLogicalDevice()
 | ||
| {
 | ||
| 	QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
 | ||
| 	
 | ||
| 	std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
 | ||
| 	std::set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value(),indices.presentFamily.value() };
 | ||
| 
 | ||
| 	float 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);
 | ||
| 
 | ||
| 	}
 | ||
| 	/*
 | ||
| 	VkDeviceQueueCreateInfo queueCreateInfo{};
 | ||
| 	queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
 | ||
| 	queueCreateInfo.queueFamilyIndex = indices.graphicsFamily.value();
 | ||
| 	queueCreateInfo.queueCount = 1;
 | ||
| 	float queuePriority = 1.0f;
 | ||
| 	queueCreateInfo.pQueuePriorities = &queuePriority;
 | ||
| 	*/
 | ||
| 
 | ||
| 	VkDeviceCreateInfo deviceCreateInfo{};
 | ||
| 	deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
 | ||
| 	deviceCreateInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
 | ||
| 	deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data();
 | ||
| 	deviceCreateInfo.pEnabledFeatures = &deviceFeatures;
 | ||
| 	//新版本vulkan已不对实例和设备特定验证层做区分,此处保证兼容性
 | ||
| 	deviceCreateInfo.enabledExtensionCount = 0;
 | ||
| 	if (enableValidationLayers)
 | ||
| 	{
 | ||
| 		deviceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
 | ||
| 		deviceCreateInfo.ppEnabledLayerNames = validationLayers.data();
 | ||
| 	}
 | ||
| 	else
 | ||
| 	{
 | ||
| 		deviceCreateInfo.enabledLayerCount = 0;
 | ||
| 	}
 | ||
| 
 | ||
| 	if (vkCreateDevice(physicalDevice,&deviceCreateInfo,nullptr,&device) != VK_SUCCESS)
 | ||
| 	{
 | ||
| 		throw std::runtime_error("failed to create logical device");
 | ||
| 	}
 | ||
| 
 | ||
| 	vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicQueue);
 | ||
| 	vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| bool HelloTriangleApplication::checkValidationLayerSupport() {
 | ||
| 	uint32_t layerCount;
 | ||
| 	vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
 | ||
| 
 | ||
| 	std::vector<VkLayerProperties> availableLayers(layerCount);
 | ||
| 	vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
 | ||
| 
 | ||
| 	// check if validationLayers can be found in availableLayers
 | ||
| 	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;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger)
 | ||
| {
 | ||
| 	auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
 | ||
| 
 | ||
| 	if (func != nullptr)
 | ||
| 	{
 | ||
| 		return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
 | ||
| 
 | ||
| 	}
 | ||
| 	else
 | ||
| 	{
 | ||
| 		return VK_ERROR_EXTENSION_NOT_PRESENT;
 | ||
| 	}
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
| void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator)
 | ||
| {
 | ||
| 	auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
 | ||
| 
 | ||
| 		if (func!=nullptr)
 | ||
| 		{
 | ||
| 			func(instance, debugMessenger, pAllocator);
 | ||
| 		}
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| int main()
 | ||
| {
 | ||
| 	HelloTriangleApplication app;
 | ||
| 
 | ||
| 	try
 | ||
| 	{
 | ||
| 		app.run(Width,Height);
 | ||
| 	}
 | ||
| 	catch (const std::exception& e)
 | ||
| 	{
 | ||
| 		std::cerr << e.what() << std::endl;
 | ||
| 		return EXIT_FAILURE;
 | ||
| 	}
 | ||
| 	return EXIT_SUCCESS;
 | ||
| }
 | ||
| 
 | ||
| 
 |