接触图形也有一段时间了,也差不多玩明白Google FIlament引擎。虽然苹果抛弃了OpenGL,但我还是认为OpenGL依然有着跨平台的优势。 依旧坚持使用OpenGL做开发。但事与愿违,虽然大佬们依然继续维护OpenGL。但渐渐发现,OpenGL的跨平台的优势一步步被Vulkan取代。至少在我能接触的领域中,对Vulkan支持已经大于对OpenGL的支持。为了学习NRD(NVIDIA Real-Time Denoiser),也是正好想拓展一下技术面。撸起袖子,冲鸭!#109。
Vulkan教程示例的项目框架搭建,参照官方文档。
initWindow(); //初始化窗口
initVulkan(); //初始化Vulakn相关
mainLoop(); //渲染循环
cleanup(); //释放资源
glfwInit(); //初始化GLFW库
//由于glfw原本是用来创建OpenGL Context的,因此需要使用GLFW_NO_API(不进行OpenGL Context创建)
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); //关闭重置窗口
//创建窗体
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
createInstance();//创建Vulkan实例
void createInstance() {
//创建实例时检测是否启用验证层
checkValidationLayerSupport();
//结构体必须指明类型,pNext指向扩展信息
VkApplicationInfo appInfo = {};
//Vulkan驱动程序使用哪些全局扩展和验证,后续后详细说明[代码中]
VkInstanceCreateInfo createInfo = {};
//创建实例
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS)
{
throw std::runtime_error("failed to create instance!");
}
//支持扩展的数量
uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
//支持的扩展详细信息
std::vector<VkExtensionProperties> extensionsProperties(extensionCount);
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensionsProperties.data());
//查询扩展的详细信息
std::cout << "available extensions:" << std::endl;
for (const auto& extension : extensionsProperties) {
std::cout << "\t" << extension.extensionName << std::endl;
}
}
setupDebugMessenger();//设置调试信息
void setupDebugMessenger() {
if (!enableValidationLayers) return;
VkDebugUtilsMessengerCreateInfoEXT createInfo = {};
populateDebugMessengerCreateInfo(createInfo);
//messenger创建信息的填充提取到单独的函数中
if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr,
&debugMessenger) != VK_SUCCESS) {
throw std::runtime_error("failed to set up debug messenger!");
}
}
//窗口关门,终止渲染
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
}
//销毁代理函数
if (enableValidationLayers) {
DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
}
//销毁实例
vkDestroyInstance(instance, nullptr);
//释放GLFW资源
glfwDestroyWindow(window);
glfwTerminate();
验证层是可选组件,Vulkan函数调用时可以进行附加操作。
验证层中的常见操作有:
建议:
Vulkan以前有两种不同类型的验证层:实例验证层和设备验证层。其思想是实例层只检查与全局Vulkan对象(如实例)相关的调用,而特定驱动(device specific)层只检查与特定GPU相关的调用。device specific层现在已被弃用,这意味着实例验证层将应用于所有Vulkan调用。规范文档仍然建议您在设备级别启用验证层以实现兼容性,这是某些实现所必需的。我们只需在逻辑设备级别指定与实例相同的层即可。
Message callback:
vk_layer_settings.txt 是消息层使用的文档
#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>
const int WIDTH = 800;
const int HEIGHT = 600;
//[4]所有有用的标准验证都捆绑到SDK的一个层中,称为VK_LAYER_KHRONOS_validation层。
const std::vector<const char*> validationLayers = {
"VK_LAYER_KHRONOS_validation"
};
//[4]验证层Debug时开启
#ifdef NDEBUG
const bool enableValidationLayers = false;
#else
const bool enableValidationLayers = true;
#endif
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();
//[6]
setupDebugMessenger();
}
void mainLoop()
{
//[2]窗口关门,终止渲染
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
}
}
void cleanup()
{
//[6]销毁代理函数
if (enableValidationLayers) {
DestroyDebugUtilsMessengerEXT(instance, debugMessenger, 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;
}
private:
GLFWwindow* window = nullptr;
VkInstance instance = nullptr;
VkDebugUtilsMessengerEXT debugMessenger;
};
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;
}