天天看點

【Vulkan】學習筆記2——執行個體(instance)、驗證層(validation layers)

以下是基本的代碼,包含了驗證層

#define GLFW_INCLUDE_VULKAN
//#include<vulkan/vulkan.h>

#include<GLFW/glfw3.h>

#include<iostream>
#include<stdexcept>//with iostream,included for reporting and propagating errors
#include<vector>
#include<cstring>
#include<cstdlib> //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;
}
           

繼續閱讀