1. Drawing
Open bnvulkanex / util / fileutil H file addition
//A structure SpvDataStruct for storing SPIR-V data is declared //The structure has two members, where size is used to store the total bytes of SPIR-V data, and data is the pointer to the first address of SPIR-V data memory block. typedef struct SpvDataStruct //Structure for storing SPIR-V data { int size; //Total bytes of SPIR-V data uint32_t* data; //Pointer to the first address of SPIR-V data memory block }SpvData;
BNVulkanEx/util/FileUtil.cpp
SpvData& FileUtil::loadSPV(string fname) //Load the SPIR-V data file under the folder { size_t size = (getfilesize(fname));//Gets the total number of bytes of the SPIR-V data file cout<<"len:"<<size<<endl; SpvData spvData;//Building SpvData structure instances spvData.size = size;//Sets the total number of bytes of SPIR-V data spvData.data = (uint32_t*)(malloc(size)); Allocate the corresponding number of bytes of memory char* buf = (char*)spvData.data;//Load data from file into memory char c_file[1000]; strcpy(c_file,fname.c_str()); FILE *fpSPV; fpSPV = fopen(c_file,"rb"); if(fpSPV == NULL) { printf("Open file%s fail\n",fname.c_str()); } fread(buf,size,1,fpSPV); return spvData; }
The Asset in the book should be the directory of android
Different GPU s of different models will provide different verification Layer combinations according to different manufacturers and driver versions
Common validation layers
name | explain |
---|---|
VK_LAYER_GOOGLE_unique_objects | Since non dispatched Vulkan object handles do not require uniqueness, it is possible for Vulkan drivers to return the same handle as long as these different objects are considered equivalent. This makes it difficult to trace objects during debugging. After activating this verification Layer, each Vulkan object will be assigned a unique ID, which makes object tracking during debugging much easier. In addition, it should be noted that this verification Layer must be placed at the end of all active verification Layer sequences, that is, the position closest to the drive |
VK_LAYER_LUNARG_api_dump | After this verification Layer is opened, all relevant parameter values in all called Vulkan function methods will be printed during program running, which is convenient for developers to debug |
VK_LAYER_LUNARG_core_validation | After this verification Layer is activated, important information such as description set and pipeline status will be verified and printed during program operation. At the same time, after this verification Layer is activated, it will track and verify the display memory, object binding, command buffer, etc., and also verify the graphics pipeline and calculation pipeline |
VK_LAYER_LUNARG_image | This verification Layer is used to verify the texture format, render target format, and so on. For example, you can verify whether the requested format is supported in the corresponding device, and whether the image view creation parameters match the corresponding image |
VK_LAYER_LUNARG_object_tracker | This verification Layer is used to track the whole process of objects from creation to use and then to destruction. It can help developers avoid memory leakage. It can also be used to verify whether the objects of interest are properly created and currently effective |
VK_LAYER_LUNARG_parameter_validation | This verification Layer is used to verify that the parameters passed to the Vulkan function method are correct |
VK_LAYER_LUNARG_swapchain | This verification Layer is used to verify the use of WSI exchange chain extensions. For example, it can verify whether the extension is available before using the WSI exchange chain extension related function method, and can be used to verify whether the given image index is within the allowable range of the exchange chain, etc |
VK_LAYER_GOOGLE_threading | This verification Layer is mainly used to help check the thread safety of Vulkan context. It can check whether the multi-threaded related API is used correctly, and it can also report object access that violates the multi-threaded mutually exclusive access rules. At the same time, it also enables applications to continue to run normally without crashing when threading problems are reported |
VK_LAYER_LUNARG_standard_validation | This validation Layer is used to confirm that all validation layers are organized in the correct order |
Different types of verification letters
name | Information type flag | explain |
---|---|---|
error message | VK_DEBUG_REPORT_ERROR_BIT_EXT | Generally refers to the wrong API use. Such problems may lead to unpredictable program running results, such as program crash |
Warning message | VK_DEBUG_REPORT_WARNING_BIT_EXT | Generally, it refers to potential wrong API use or dangerous API use |
Message information | VK_DEBUG_REPORT_INFORMATION_BIT_EXT | Used to display user-friendly prompts. Generally, this information is used to describe the activities in the background of the program, such as the details of resources, which is very helpful for debugging |
Performance warning information | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | It is generally used to alert potential non optimal Vulkan calls, which may lead to poor program performance |
debug information | VK_DEBUG_REPORT_DEBUG_BIT_EXT | Used to give diagnostic information from the loader or verify the Layer |
BNVulkanEx/main_ Add bnvalidateutil. Under task h BNValidateUtil. cpp
CMAKELISTS.txt add bnvalidateutil h BNValidateUtil. cpp
#ifndef VULKANEXBASE_BNValidateUtil_H #define VULKANEXBASE_BNValidateUtil_H #include <vector> #include <vulkan/vulkan.h> #include <string> //A structure with the name BNDeviceLayerAndExtensionType is declared, which contains two members //One is the verification Layer name list layerNames that can be supported after deletion //The other is a list of device extension names required to support these validation layers typedef struct BNDeviceLayerAndExtensionType { std::vector<std::string *> layerNames; //List of supported validation Layer names std::vector<std::string *> extensionNames; //Supported list of names of extensions required to validate Layer } BNDeviceLayerAndExtension; class BNValidateUtil { public: //The obtained verification Layer attribute list layerList, two function pointers dbgCreateDebug ReportCallback and dbgDestroyDebugReportCallback, and the debug report object debugReportCallback are declared respectively static std::vector<VkLayerProperties> layerList; //Gets the list of validation Layer properties for the static PFN_vkCreateDebugReportCallbackEXT dbgCreateDebugReportCallback; static PFN_vkDestroyDebugReportCallbackEXT dbgDestroyDebugReportCallback; static VkDebugReportCallbackEXT debugReportCallback; Debugging report callback //The getLayerProperties method is declared, and the parameter of this method is the list of validation Layer names expected to be started. //Its function is to find the intersection between the expected validation Layer name list and the actually supported validation Layer name list, and then return the supported validation Layer name list and the required instance extension name list. static BNDeviceLayerAndExtension getLayerProperties(std::vector<const char *> exceptedLayerNames); //Getlayerdevice extension method is declared. The first parameter of this method is the specified physical device; //The second parameter is the specified verification Layer name list. The function is to obtain the logical device extension name list required by the specified verification Layer name list. static std::vector<std::string *> getLayerDeviceExtension(VkPhysicalDevice &gpu, std::vector<std::string *> supportedlayerNames); //First, the method of creating a debug report callback createDebugReportCallbackSelf is declared, static void createDebugReportCallbackSelf(VkInstance &instance); //Method for creating debug report callback //Then it declares the method of destroying the debugging report callback destroyDebugReportCallbackSelf, //dbgDestroyDebug ReportCallback points to the dynamically loaded method used to destroy the debug report callback. static void destroyDebugReportCallbackSelf(VkInstance &instance); //Method of destroying debugging report callback //Finally, the method debugFunction for being called back to print verification information is declared //The createDebugReportCallbackSelf and destroyDebugReportCallbackSelf methods will call the corresponding methods of dynamic loading described earlier to complete the target task. static VKAPI_ATTR VkBool32 VKAPI_CALL debugFunction( //Method for being called back to print verification information VkFlags msgFlags, //Flag of the debug event type that triggered the execution of this callback VkDebugReportObjectTypeEXT objType, //The type of object processed by this callback uint64_t srcObject, //Handle to the object created or processed by this callback size_t location, //Describes the location of the corresponding debug event code int32_t msgCode, //Message code const char *layerPrefix, //Validation Layer that triggers this callback const char *msg, //Message string void *pUserData //User defined data ); }; #endif
Implementation of verification code
#include "BNValidateUtil.h" #include <iostream> #include <cstring> #define LOGE printf std::vector<VkLayerProperties> BNValidateUtil::layerList; PFN_vkCreateDebugReportCallbackEXT BNValidateUtil::dbgCreateDebugReportCallback; PFN_vkDestroyDebugReportCallbackEXT BNValidateUtil::dbgDestroyDebugReportCallback; VkDebugReportCallbackEXT BNValidateUtil::debugReportCallback; //Two overloaded versions of the isContain method //The two isContain methods have different entry parameter types and basically the same functions. They are used to judge whether the specified string is included in the specified string list. bool isContain(std::vector<const char *> inNames, char *inName) { //Method to determine whether the string is in the list for (auto s : inNames) { //Traversal string list if (strcmp(s, inName) == 0) { //If the given string is the same as the current string return true; //Returns true, indicating that the specified string is in the list } } return false; //Returns false, indicating that the specified string is not in the list } bool isContain(std::vector<std::string *> inNames, char *inName) { //Method to determine whether the string is in the list for (auto s : inNames) { //Traversal string list if (strcmp((*s).c_str(), inName) == 0) { //If the given string is the same as the current string return true; //Returns true, indicating that the specified string is in the list } } return false; //Returns false, indicating that the specified string is not in the list } //getLayerProperties method. This method receives the list of verified Layer names that are expected to start, then calls the vkEnumerateInstanceLayerProperties method to get the list of validation Layer attributes that can be supported at present. //Then we call the vkEnumerateInstanceLayerProperties method to get the list of Layer attributes that can be supported at present. BNDeviceLayerAndExtension BNValidateUtil::getLayerProperties(std::vector<const char *> exceptedLayerNames) { BNDeviceLayerAndExtension result; //Return result structure instance uint32_t layerCount; //Total number of validation layers vkEnumerateInstanceLayerProperties(&layerCount, NULL); //Gets the total number of validation layers LOGE("Layer The quantity of is %d\n", layerCount); //Print the total number of validation layers layerList.resize(layerCount); //Change list length vkEnumerateInstanceLayerProperties(&layerCount, layerList.data()); //Get the total list of validation Layer properties //Then traverse the obtained verification Layer attribute list to investigate each verification Layer attribute. for (int i = 0; i < layerList.size(); i++) { //Traverse and verify the Layer attribute list VkLayerProperties lp = layerList[i]; //Gets the current validation Layer property LOGE("----------------Layer %d----------------\n", i); //Print verification Layer serial number LOGE("layer name %s\n", lp.layerName); //Print verification Layer name LOGE("layer describe %s\n", lp.description); //Print verification Layer description information bool flag = isContain(exceptedLayerNames, lp.layerName); //Whether the current verification Layer needs if (flag) { //If necessary, record the current verification Layer name in the verification Layer name result list //Record the name of this verification Layer in the result list (list of supported verification Layer names), result.layerNames.push_back(new std::string(lp.layerName)); } uint32_t propertyCount; //Number of extended attributes corresponding to this validation Layer vkEnumerateInstanceExtensionProperties(lp.layerName, &propertyCount, NULL); std::vector<VkExtensionProperties> propertiesList; //Extended attribute list propertiesList.resize(propertyCount); //Adjust list length vkEnumerateInstanceExtensionProperties(lp.layerName, &propertyCount, propertiesList.data()); for (auto ep : propertiesList) { //Traverse the list of extended properties corresponding to this validation Layer LOGE(" Required extensions:%s\n", ep.extensionName); //Print extension name if (flag) { //If the current verification Layer is required if (!isContain(result.extensionNames, ep.extensionName)) { //At the same time, the instance extension name required for this verification Layer is also recorded in the result list (the list of supported extension names required for verification Layer), result.extensionNames.push_back(new std::string(ep.extensionName)); } } } } //Finally, the structure instance containing two result lists is returned return result; //Return results } //The getlayerdevice extension method receives the specified physical device and a list of validation Layer names that need to be supported std::vector<std::string *> BNValidateUtil::getLayerDeviceExtension(VkPhysicalDevice &gpu, std::vector<std::string *> supportedlayerNames) { //Then traverse all the current verification Layer attribute lists to obtain the device extension attribute list required for each verification Layer. std::vector<std::string *> result; //Required device extension name result list for (int i = 0; i < layerList.size(); i++) { //Get the list of device extended attributes required for each validation Layer. //Traverse the attribute list of all validation layers VkLayerProperties lp = layerList[i]; //Gets the current validation Layer property LOGE("----------------Layer %d----------------\n", i); //Print verification Layer serial number LOGE("layer name %s\n", lp.layerName); //Print verification Layer name LOGE("layer describe %s\n", lp.description); //Print verification Layer description information uint32_t propertyCount; //Number of device extended attributes vkEnumerateDeviceExtensionProperties(gpu, lp.layerName, &propertyCount, NULL); //Gets the number of device extended attributes corresponding to the current verification Layer std::vector<VkExtensionProperties> propertiesList; //Device extended attribute list propertiesList.resize(propertyCount); //Adjust list length vkEnumerateDeviceExtensionProperties(gpu, lp.layerName, &propertyCount, propertiesList.data()); //Fill in the device extended attribute list corresponding to the current verification Layer for (auto ep : propertiesList) { //Traverse device extended attribute list LOGE(" Required device extensions:%s\n", ep.extensionName); if (isContain(supportedlayerNames, lp.layerName)) { //Judge whether the current verification Layer is required if (!isContain(result, ep.extensionName)) { //Judge whether the current device extension is already in the list result.push_back(new std::string(ep.extensionName)); //Adds the current device extension name to the list } } } } return result; //Returns the result list of the required device extension name } //If the return value of this method is VK_SUCCESS means that after the callback, the subsequent verification Layer will continue to execute. If the return value is VK_FALSE indicates that the subsequent verification Layer will not continue. // VKAPI_ATTR VkBool32 VKAPI_CALL BNValidateUtil::debugFunction( VkFlags msgFlags, //Flag of the debug event type that triggered the execution of this callback VkDebugReportObjectTypeEXT objType, //The type of object processed by this callback uint64_t srcObject, //Handle to the object created or processed by this callback size_t location, //Describes the location of the corresponding debug event code int32_t msgCode, //Message code const char *layerPrefix, //The validation Layer that triggers this callback, such as loader or validation Layer const char *msg, //Message string void *pUserData) { //User defined data //According to the message code, the message is divided into error information, warning information, message information, performance warning information and debugging information, and printed respectively. //In actual development, if readers have other special needs, they can further customize the output debugging information. //The name of this callback method can be customized, but its entry parameter sequence is specified in Vulkan and cannot be changed at will. if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { //error message LOGE("[VK_DEBUG_REPORT] ERROR: [%s]Code%d:%s\n", layerPrefix, msgCode, msg); } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { //Warning message LOGE("[VK_DEBUG_REPORT] WARNING: [%s]Code%d:%s\n", layerPrefix, msgCode, msg); } else if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { //Message information LOGE("[VK_DEBUG_REPORT] INFORMATION:[%s]Code%d:%s\n", layerPrefix, msgCode, msg); } else if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) { //Performance warning information LOGE("[VK_DEBUG_REPORT] PERFORMANCE: [%s]Code%d:%s\n", layerPrefix, msgCode, msg); } else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { //debug information LOGE("[VK_DEBUG_REPORT] DEBUG: [%s]Code%d:%s\n", layerPrefix, msgCode, msg); } else { return VK_FALSE; //Other unknown situations } return VK_SUCCESS; } //Method for creating a debug report callback createDebugReportCallbackSelf void BNValidateUtil::createDebugReportCallbackSelf(VkInstance &instance) { //Create debug report callback related //First, dynamically load the vkCreateDebugReportCallbackEXT method, dbgCreateDebugReportCallback = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); //Then build a debug report callback to create an instance of the information structure VkDebugReportCallbackCreateInfoEXT dbgReportCreateInfo = {}; //Build the instance of information structure for debugging report callback creation //Specify the callback method as debugFunction, and confirm that the callback method is triggered by warning information, performance warning information, error information and debugging information //Next, create a debug report callback instance using the dynamically loaded vkCreateDebugReportCallbackEXT method dbgReportCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; dbgReportCreateInfo.pfnCallback = debugFunction; //Specify callback method dbgReportCreateInfo.pUserData = NULL; //User defined data passed to callback dbgReportCreateInfo.pNext = NULL; //Pointer to custom data dbgReportCreateInfo.flags = //The type of event required to trigger the message callback VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT; VkResult result = dbgCreateDebugReportCallback(instance, &dbgReportCreateInfo, NULL, &debugReportCallback); //Create debug report callback instance if (result == VK_SUCCESS) { LOGE("Debugging report callback object created successfully!\n"); } } //The method of callback of debug report is destroyed. destroyDebugReportCallbackSelf, in this method, the vkDestroyDebugReportCallbackEXT method is first loaded dynamically, then the vkDestroyDebugReportCallbackEXT method is called to destroy the specified debug report callback. void BNValidateUtil::destroyDebugReportCallbackSelf(VkInstance &instance) //Destroy debugging report callback related { dbgDestroyDebugReportCallback = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"); dbgDestroyDebugReportCallback(instance, debugReportCallback, NULL); }
MyVulkanManager. Add in H
//In order to use the validation Layer, two members are added #include "BNValidateUtil.h" class MyVulkanManager { public: //Window auxiliary structure static struct WindowInfo info; //Cycle flag drawn by vulkan static bool loopDrawFlag; //One is a list of validation Layer names that you want to start //The other is the combination structure that can support the verification Layer and the required instance extension name list static std::vector<const char* >exceptionLayerNames; static BNDeviceLayerAndExtension bdlae;
The following work is init in MyVulkanManager class_ vulkan_ Instance method, create_vulkan_devices methods and destroy_ vulkan_ Add the relevant calling code to the instance method
init_vulkan_instance
//Modified init_vulkan_instance method, in which there are two main changes. The first point is to add "VK_EXT_DEBUG_REPORT_EXTENSION_NAME" to the required instance extension name list //Enabling this instance extension enables the dynamic loading of the vkCreateDebugReportCallbackEXT method and the vkDestroyDebugReportCallbackEXT method to succeed instanceExtensionNames.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); //The verification Layer name list that the organization expects to start and the code to obtain the supported verification Layer name list and the corresponding required instance extension name list based on the current environment are added. //When building an instance and creating an information structure instance, the two obtained lists are used, and the relevant code for creating a debugging report callback is added at the end of the method. std::vector<const char*>exceptedLayerNames;//List of validation Layer names expected to start exceptedLayerNames.push_back("VK_LAYER_LUNARG_core_validation"); exceptedLayerNames.push_back("VK_LAYER_LUNARG_parameter_validation"); exceptedLayerNames.push_back("VK_LAYER_LUNARG_standard_validation"); //The two lists obtained are used when building an instance and creating an information structure instance bdlae = BNValidateUtil::getLayerProperties(exceptedLayerNames);//Get support for(auto s: bdlae.extensionNames)//Add the required extension to the extension name list { instanceExtensionNames.push_back((*s).c_str()); } exceptedLayerNames.clear();//Clear validation Layer name list for(auto s : bdlae.layerNames) Will be able to support validation Layer Name join Layer Name list { exceptedLayerNames.push_back((*s).c_str()); }
create_vulkan_devices
//Changed create_vulkan_devices method, which mainly adds the relevant code to obtain the list of device extension names required to start the verification Layer. std::vector<std::string*> needsDeviceExtensions = BNValidateUtil::getLayerDeviceExtension(gpus[USED_GPU_INDEX], bdlae.layerNames);//Gets the device extension required to validate Layer for(auto s : needsDeviceExtensions)//Add required device extensions to the list { deviceExtensionNames.push_back((*s).c_str()); }
destroy_vulkan_instance
//Only the code related to destroying the debugging report callback is added. if(exceptedLayerNames.size() > 0)//Destroy debug report callback { BNValidateUtil::destroyDebugReportCallbackSelf(instance); }