Vlukan基础教程 - 04.物理设备
作者:Sun zi chao     发布时间:2022-03-27 21:00:00    阅读次数:98
本系列文章介绍Vlukan编程。Vlukan是一个跨平台的2D和3D绘图应用程序接口(API),是OpenGL的“继任者”。学习本教程的同学需要有GLFW以及C++的编程经验。有OpenGL或DirectX经验更好。

对于一台包含多个物理GPU的主机,Vulkan程序可以选择其中一块GPU作为它的运行平台。Vulkan程序枚举当前主机所有的GPU设备,并检查这些设备的特性是否符合特定要求,比如,要求是物理GPU,要求支持geometryShader等各种Shader。这些都可以检测出来。

今天的程序为了简洁,我把上节启动校验层给禁止了,这个禁还是很简单的,只要加一句:#define NDEBUG 0 就可以了。另外还加入了下面一些变量和类函数。

	//定义一个物理设备(GPU)
	VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;

	//加入一个pickPhysicalDevice函数,它负责枚举主机所有GPU,并选择一个基于GPU的且支持geometryShader的设备作为物理渲染设备
	void 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());
        std::cout<<"GPU Devices:"<<deviceCount<<"\n";


        VkPhysicalDeviceProperties DeviceProperties;
        VkPhysicalDeviceFeatures DeviceFeatures;

        for (const auto& device : devices) {

            vkGetPhysicalDeviceProperties(device,&DeviceProperties);
            vkGetPhysicalDeviceFeatures(device,&DeviceFeatures);

            if(DeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
           DeviceFeatures.geometryShader){
                std::cout<<"Device Name:"<<DeviceProperties.deviceName<<"\n";
                physicalDevice = device;
                break;
           }
        }

        if (physicalDevice == VK_NULL_HANDLE) {
            throw std::runtime_error("failed to find a suitable GPU!");
        }
    }

主程序

	#define GLFW_INCLUDE_VULKAN
	#include <GLFW/glfw3.h>
	#include <string.h>
	#include <iostream>
	#include <vector>


	const uint32_t WIDTH = 800;
	const uint32_t HEIGHT = 600;

	const std::vector<const char*> validationLayers = {
		"VK_LAYER_KHRONOS_validation"
	};


	#define NDEBUG 0

	//是否启用校验层
	#ifdef NDEBUG
	const bool enableValidationLayers = false;
	#else
	const bool enableValidationLayers = true;
	#endif


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

	class HelloTriangleApplication {
	public:
		void run() {
			initWindow();
			initVulkan();
			mainLoop();
			cleanup();
		}

	private:
		GLFWwindow* window;

		VkInstance instance;
		VkDebugUtilsMessengerEXT debugMessenger;

		VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;

		void initWindow() {
			glfwInit();

			glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
			glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

			window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan_01", nullptr, nullptr);
		}

		void initVulkan() {
			createInstance();
			setupDebugMessenger();
			pickPhysicalDevice();
		}

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

		void cleanup() {

			if (enableValidationLayers && !checkValidationLayerSupport()) {
				throw std::runtime_error("validation layers requested, but not available!");
			}

			vkDestroyInstance(instance, nullptr);

			glfwDestroyWindow(window);

			glfwTerminate();
		}

		void createInstance() {
			//检查校验层是否有效
			if (enableValidationLayers && !checkValidationLayerSupport()) {
				throw std::runtime_error("validation layers requested, but not available!");
			}

			//定义程序信息
			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;

			VkInstanceCreateInfo createInfo{};
			createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
			createInfo.pApplicationInfo = &appInfo;

			//获取所需Vulkan的扩展
			auto extensions = getRequiredExtensions();

			createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
			createInfo.ppEnabledExtensionNames = extensions.data();

			createInfo.enabledLayerCount = 0;

			//校验层
			VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
			createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
			createInfo.ppEnabledLayerNames = validationLayers.data();
			populateDebugMessengerCreateInfo(debugCreateInfo);
			createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) &debugCreateInfo;

			//创建Vulkan实例
			if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
				throw std::runtime_error("failed to create instance!");
			}
		}

		//返回GFLW所需扩展和启用校验层所需扩展
		std::vector<const char*> 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 showExtensions(){
			uint32_t extensionCount = 0;
			vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);

			std::vector<VkExtensionProperties> extensions(extensionCount);

			vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());

			std::cout << "\n系统支持Vulkan扩展:\n";

			for (const auto& extension : extensions) {
				std::cout << '\t' << extension.extensionName << '\n';
			}
		}

		bool checkValidationLayerSupport() {
			uint32_t layerCount;
			vkEnumerateInstanceLayerProperties(&layerCount, nullptr);

			std::vector<VkLayerProperties> availableLayers(layerCount);
			vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());

			std::cout<<"本系统支持校验层数:"<<layerCount<<"\n";
			int i=1;

			for (const auto& layerProperties : availableLayers) {
				std::cout<<"-------Validtion Layer "<<i++<<"---------\n";
				std::cout<<"名称:"<<layerProperties.layerName<<"\n";
				std::cout<<"描述:"<<layerProperties.description<<"\n\n";
			}

			bool layerFound;

			for (const char* layerName : validationLayers) {
				bool layerFound = false;

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

						uint32_t propertyCount;

						vkEnumerateInstanceExtensionProperties(layerProperties.layerName,&propertyCount,NULL);
						std::vector<VkExtensionProperties> propertiesList;
						propertiesList.resize(propertyCount);

						vkEnumerateInstanceExtensionProperties(layerProperties.layerName,&propertyCount,propertiesList.data());

						std::cout<<"所需扩展:\n";

						for(auto ep:propertiesList){
							if(enableValidationLayers==true){
								std::cout<<"\t"<<ep.extensionName<<"\n";
							}
						}
						break;
					}
				}

				if (!layerFound) {
					return false;
				}
			}



			return true;
		}

		//设置调试相关参数及回调函数
		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;
			//设置调试信息回调函数debugCallback
			createInfo.pfnUserCallback = debugCallback;
		}

		static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) {

			if(!enableValidationLayers)
				return VK_FALSE;

			std::string msg="Validation Layer ";

			switch(messageSeverity){
				case 1:
					msg+="诊断信息:";
					break;
				case 2:
					msg+="资源创建:";
					break;
				case 3:
					msg+="警告信息:";
					break;
				case 4:
					msg+="错误信息:";
					break;
			}

			std::cerr << msg << pCallbackData->pMessage <<"\t"<<"\n\n";
			return VK_FALSE;
		}

		void 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!");
			}
		}

		void 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());
			std::cout<<"GPU Devices:"<<deviceCount<<"\n";


			VkPhysicalDeviceProperties DeviceProperties;
			VkPhysicalDeviceFeatures DeviceFeatures;

			for (const auto& device : devices) {

				vkGetPhysicalDeviceProperties(device,&DeviceProperties);
				vkGetPhysicalDeviceFeatures(device,&DeviceFeatures);

				if(DeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
			   DeviceFeatures.geometryShader){
					std::cout<<"Device Name:"<<DeviceProperties.deviceName<<"\n";
					physicalDevice = device;
					break;
			   }
			}

			if (physicalDevice == VK_NULL_HANDLE) {
				throw std::runtime_error("failed to find a suitable GPU!");
			}
		}

	};

	int main() {
		HelloTriangleApplication app;

		try {
			app.run();
		} catch (const std::exception& e) {
			std::cerr << e.what() << std::endl;
			return EXIT_FAILURE;
		}

		return EXIT_SUCCESS;
	}

运行结果,显示出主机包含GPU数量,和符合条件的GPU名称

GPU Devices:1
Device Name:GeForce GTX 1050 Ti


桂ICP备11003301号-1 公安备案号:45040302000027 Copyright @ 2021- 2022 By Sun zi chao

阅读统计: 1.93W 文章数量: 76 运行天数: 416天 返回cmnsoft