【Vulkan】学习笔记2——实例(instance)、验证层(validation layers)

以下是基本的代码,包含了验证层

#define GLFW_INCLUDE_VULKAN
//#include

#include

#include
#include//with iostream,included for reporting and propagating errors
#include
#include
#include //provide EXIT_SUCCESS and EXIT_FAILURE


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

const std::vector<const char*> validationlayers = { "VK_LAYER_KHRONOS_validation" };
//通过宏定义NDBUG来决定是否启用验证层
//通过在构建时使用或不使用宏定义来在调试和发布版本中选择是否启用验证层,从而在调试版本中提高
//错误检测能力,而在发布版本中减少运行时开销。
#ifdef NDEBUG
	//如果NDEBUG已定义,则表示不启用验证层
	const bool enablevalidationlayers = false;
#else
	const bool enablevalidationlayers = true;
#endif // 
	//instance是 Messenger 将使用的实例。

	//pCreateInfo是指向包含回调指针的 VkDebugUtilsMessengerCreateInfoEXT结构的指针,以及定义此信使将触发回调的条件。

		//pAllocator如 内存分配一章所述控制主机内存分配。

		//pMessenger是指向VkDebugUtilsMessengerEXT句柄的指针,在该句柄中返回创建的对象。
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;
	}

}
//该VkDebugUtilsMessengerEXT对象还需要通过调用来清理 vkDestroyDebugUtilsMessengerEXT。类似于vkCreateDebugUtilsMessengerEXT 需要显式加载的函数。
//在下面创建另一个代理函数CreateDebugUtilsMessengerEXT
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;

	void InitWindow()
	{
		glfwInit();

		//因为 GLFW 最初设计用于创建 OpenGL 上下文,我们需要告诉它不要通过后续调用创建 OpenGL 上下文:
		glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
		//因为处理调整大小的窗口需要特别小心,所以现在用另一个窗口提示调用禁用它:
		glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

		//创建实际的窗口
		window = glfwCreateWindow(WIDTH, HEIGHT, "vulkan", nullptr, nullptr);
	}

	void InitVulkan()
	{
		CreateInstance();

		SetupDebugMessenger();

	}

	//为了保持应用程序运行直到发生错误或窗口关闭,我们需要向mainLoop函数添加一个事件循环
	void MainLoop()
	{
		while (!glfwWindowShouldClose(window))
		{
			glfwPollEvents();
		}
	}

	void CleanUp()
	{
		if (enablevalidationlayers)
		{
			DestroyDebugUtilsMessengerEXT(instance, debugmessenger, nullptr);
		}
		vkDestroyInstance(instance, nullptr);

		glfwDestroyWindow(window);

		glfwTerminate();
	}

	void CreateInstance()
	{
		if (enablevalidationlayers && !CheckValidationLayerSupport())
		{
			throw std::runtime_error("validation layers requested,but not available!");
		}

		//首先,向驱动程序提供一些有用的信息来优化我们的特定应用程序
		VkApplicationInfo appinfo{};

		//在stype中显式指定类型
		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;

		//Vulkan很多信息是通过结构而不是函数参数传递,必须再填充一个结构来为创建实例提供
		//足够的信息
		VkInstanceCreateInfo createinfo{};
		createinfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
		createinfo.pApplicationInfo = &appinfo;

		auto extensions = GetRequireExtensions();
		createinfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
		createinfo.ppEnabledExtensionNames = extensions.data();

		VkDebugUtilsMessengerCreateInfoEXT debugcreateinfo{};
		if (enablevalidationlayers)
		{
			createinfo.enabledLayerCount = static_cast<uint32_t>(validationlayers.size());
			createinfo.ppEnabledLayerNames = validationlayers.data();

			PopulateDebugMessagerCreateInfo(debugcreateinfo);
			createinfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)& debugcreateinfo;
		}
		else
		{
			createinfo.enabledLayerCount = 0;

			createinfo.pNext = nullptr;
		}

		VkResult result = vkCreateInstance(&createinfo, nullptr, &instance);
		if (result != VK_SUCCESS)
		{
			throw std::runtime_error("Failed to create instance!");
		}
	}

	void PopulateDebugMessagerCreateInfo(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 SetupDebugMessenger()
	{
		if (!enablevalidationlayers) return;

		VkDebugUtilsMessengerCreateInfoEXT createinfo;
		PopulateDebugMessagerCreateInfo(createinfo);

		if (CreateDebugUtilsMessengerEXT(instance, &createinfo, nullptr, &debugmessenger) != VK_SUCCESS)
		{
			throw std::runtime_error("failed to set up debug messenger!");
		}
	}

	std::vector<const char*> GetRequireExtensions()
	{
		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;
	}

	//检查是否所有请求的层都可用
	bool CheckValidationLayerSupport()
	{
		uint32_t layercount;

		//是一个 Vulkan API 函数,用于枚举可用的实例层
		vkEnumerateInstanceLayerProperties(&layercount, nullptr);
		//这个vector包含VkLayerProperties结构体,大小为layercount,此vector大小等于可用实例层的数量
		std::vector<VkLayerProperties> availablelayers(layercount);
		vkEnumerateInstanceLayerProperties(&layercount, availablelayers.data());

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

	static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallBack(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) 
	{
		std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl;

		return VK_FALSE;
	}
};

int main()
{
	HelloTriangleApplication app;

	try
	{
		app.run();
	}
	catch (const std::exception& e)
	{
		std::cerr << e.what() << std::endl;//std::cerr是一个非缓冲输出流,它的输出不会被缓存,而是立即输出到标准错误设备(通常是控制台)
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}

你可能感兴趣的:(Vulkan,学习,c++,开发语言)