当前位置: 首页 > news >正文

Vulkan 学习(18)---- 使用 ValidationLayer

目录

      • ValidationLayer 简介
      • 启用 ValidationLayer
        • Enable ValidationLayer
        • 检查扩展支持
        • 创建回调函数
        • 注册回调函数
      • Android ValidationLayer

ValidationLayer 简介

Vulkan API 的设计是按照最小化驱动程序的开销进行的,所以默认情况下 Vulkan API 提供的错误检测的功能非常有限,很多基本的错误都没有被 Vulkan 显式进行处理,遇到错误也是直接错误崩溃,或者直接发生未定义行为,比如使用了一个新的特性,但是在逻辑设备创建的时候没有添加这个拓展

Vulkan 引入验证层,验证层是一个可选组件,它会 hookVulkan 的函数调用中,验证层的常见功能为:

  • 对照规范检查参数的值是否合法
  • 跟踪对象的销毁和创建,找出潜在的资源泄露
  • 跟踪调用来源的线程来检查线程的安全性
  • 将每个调用及其参数记录到标准输出
  • 跟踪 Vulkan 调用进行分析和重放

ValidationLayer
这些验证层可以自由的开始或者关闭,可以在调试时开启验证层,在发布的时候禁用
Vulkan 本身实现不包含验证层的代码,但是 LunarG Vulkan SDK 提供了标准验证层的实现,用于检查常见的错误,它完全开源,只有安装了验证层才可以正常使用

启用 ValidationLayer

Enable ValidationLayer

添加一个新的函数 checkValidationLayerSupport,使用函数 vkEnumrateInstanceLayerProPerties 可以枚举出所有支持的 Layer

bool checkValidationLayerSupport() {uint32_t layerCount;vkEnumerateInstanceLayerProperties(&layerCount, nullptr);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;}
}
}

确定系统可以支持验证层之后,在 create_instance 的时候就可以指定参数开启验证层:

if (enableValidationLayers) {createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());createInfo.ppEnabledLayerNames = validationLayers.data();
} else {createInfo.enabledLayerCount = 0;
}

如果验证层在 sdk 中没有安装,vkCreateInstace 会提示 VK_ERROR_LAYER_NOT_PRESENT 错误

检查扩展支持

验证层会将消息打印到标准输出,但是我们也可以在程序中提供回调函数来处理验证层消息,还可以自己决定要看的消息类型,因为不是所有的消息都是错误或者致命错误
要在程序中回调处理相关的消息,需要使用 VK_EXT_debug_utils 扩展,然后再添加一个回调函数

这里使用 getRequiredExtensions 来获取需要的所有拓展,当然也包括添加 VK_EXT_DEBUG_UTILS_EXTENSION_NAME 拓展

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;
}
创建回调函数

debugcallback 回调函数的原型如下:

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;
}
  • 第一个参数表示消息的严重程度,可以是下面的值之一
  1. VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:诊断消息
  2. VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:信息性消息,例如资源的创建
  3. VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:关于不一定是错误的行为的消息,但很可能是应用程序中的错误
  4. VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:关于无效且可能导致崩溃的行为的消息
  • 第二个参数 messageType 可以是下面的值
  1. VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT:发生了一些与规范或性能无关的事件
  2. VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT:发生了一些违反规范或指示可能错误的事情
  3. VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXTVulkan 的潜在非最佳使用
  • pCallbackData 参数是指一个 VkDebugUtilsMessengerCallbackDataEXT 结构,其中包含消息本身的详细信息
  1. pMessage:调试消息
  2. pObjects:与消息相关的 Vulkan 对象句柄数组
  3. objectCount:数组中的对象数
  • pUserData 参数包含一个在回调设置期间指定的指针,允许您将自己的数据传递给它

返回值表示是否中止验证层的消息的 Vulkan 调用,如果回调返回 true,则调用将以 VK_ERROR_VALIDATION_FAILED_EXT 错误中止

注册回调函数

我们需要使用 vkCreateDebugUtilsMessengerEXT 函数用来创建 VkDebugUtilsMessengerEXT 对象
vkCreateDebugUtilsMessengerEXTpCreateInfo 参数传入了 debugCallback 的函数指针

需要注意的是,CreateDebugUtilsMessengerEXT 是扩展函数,因此不会自动加载,我们必须使用 vkGetInstanceProcAddr 自己查找其地址

PFN_vkCreateDebugUtilsMessengerEXT 的函数原型是:

typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugUtilsMessengerEXT)(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pMessenger);

参考的 CreateInfo 创建流程如下:

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;
}
  • messageSeverity 字段允许您指定希望调用回调的所有严重性类型
    在此处指定了除 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT 之外的所有类型,以接收有关可能问题的通知,同时排除详细的常规调试信息

  • messageType 字段允许您筛选通知回调的消息类型,这里启用了所有类型

  • pfnUserCallback 字段指定回调函数的指针,可以选择性地将指针传递给 pUserData 字段,该指针将通过 pUserData 参数传递给回调函数

参考代码如下:

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

Android ValidationLayer

Android 系统中使用 Vulkan loader 对接厂商的 vulkan api 的不同实现,vulkan loader 中也可以开启验证层
ValidationLayer 的实现可以从 khronos 的开源代码编译,生成对应的so,放到 /data/local/debug/vulkanVulkan loader 会自动查找此目录,并且对接到 ValidationLayer

http://www.lqws.cn/news/570259.html

相关文章:

  • 洛谷日常刷题3
  • 通过交互式可视化探索波动方程-AI云计算数值分析和代码验证
  • Xcode 中的 Compilation Mode 是管什么的
  • 模拟与可视化复杂非线性偏微分方程:从KdV到云端几何问题-AI云计算数值分析和代码验证
  • 现代 JavaScript (ES6+) 入门到实战(一):告别 var!拥抱 let 与 const,彻底搞懂作用域
  • 80%的知识库场景选择FastGPT,20%的复杂场景选择Dify
  • 概率论符号和公式整理
  • Dify私有化知识库搭建并通过ChatFlow智能机器人使用知识库的详细操作步骤
  • C# 合并两个byte数组的几种方法
  • linux运维学习第10周
  • 手机射频功放测试学习(二)——手机线性功放的静态电流和小信号(S-Parameter)测试
  • 计算机组成原理与体系结构-实验二 ALU(Proteus 8.15)
  • 电子计数跳绳原型
  • 数据结构 哈希表、栈的应用与链式队列 6.29 (尾)
  • Hive SQL 快速入门指南
  • GO 语言学习 之 数组和切片
  • Docker镜像制作案例
  • MATLAB中formattedDisplayText函数用法
  • 用户行为序列建模(篇八)-【阿里】DIEN
  • 由dbc文件解析can消息(一)
  • 信创背景下应用软件迁移解析:从政策解读到落地实践方案
  • 使用Xshell学习Linux的一些基本操作
  • JavaScript基础-常见网页特效案例
  • NumPy 统计函数与矩阵运算指南
  • 【大语言模型入门】—— 浅析LLM基座—Transformer原理
  • FPGA实现CameraLink视频解码,基于Xilinx ISERDES2原语,提供4套工程源码和技术支持
  • 【系统分析师】2021年真题:案例分析-答案及详解
  • SpringCloud系列(41)--SpringCloud Config分布式配置中心简介
  • 《从Backprop到Diffusion:深度学习的算法进化树全景图》
  • C++洛谷P1001 A+B Problem