在上一章中,我們初始化了 Vulkan API 并知道了層和擴(kuò)展的概念。 我們連接物理硬件設(shè)備并理解了它所暴露的不同類型的隊(duì)列。 由于我們正在為實(shí)際具體的實(shí)現(xiàn)做前期的準(zhǔn)備工作,因此了解 Vulkan 中的調(diào)試功能,從而避免不愉快的錯(cuò)誤,就顯得非常重要了。
Vulkan 允許您通過(guò)驗(yàn)證層執(zhí)行調(diào)試。 這些驗(yàn)證層檢查是可選的,可以在運(yùn)行時(shí)注入到系統(tǒng)中。 傳統(tǒng)的圖形 API 會(huì)預(yù)先使用某種錯(cuò)誤檢查機(jī)制來(lái)執(zhí)行驗(yàn)證,這是管線的所必需部分。 這在開發(fā)階段確實(shí)很有用,但實(shí)際上,在發(fā)布階段這卻是一種開銷,因?yàn)轵?yàn)證錯(cuò)誤在開發(fā)階段本身可能已經(jīng)獲得了修復(fù)。 這種強(qiáng)制性檢查會(huì)導(dǎo)致 CPU 花費(fèi)大量的時(shí)間進(jìn)行錯(cuò)誤檢查。
另一方面,Vulkan 旨在提供最佳性能,其中可選的驗(yàn)證過(guò)程和調(diào)試模型起著至關(guān)重要的作用。 Vulkan 假定應(yīng)用程序已經(jīng)完成了它的功課 ------ 使用開發(fā)階段提供的驗(yàn)證和調(diào)試功能,并且在發(fā)布階段它是完全可以信賴的。
在本章中,我們將學(xué)習(xí) Vulkan 應(yīng)用程序的驗(yàn)證和調(diào)試過(guò)程。 我們將涵蓋以下主題
- 窺視 Vulkan 調(diào)試
- 了解 LunarG 驗(yàn)證層及其功能
- 在 Vulkan 中實(shí)現(xiàn)調(diào)試功能
窺視 VUlkan 調(diào)試
Vulkan 調(diào)試功能用于驗(yàn)證應(yīng)用程序的實(shí)現(xiàn)。 它不僅表示錯(cuò)誤,還表示一些其他的驗(yàn)證,例如正確的 API 使用。 它通過(guò)驗(yàn)證傳遞給它的每個(gè)參數(shù)來(lái)執(zhí)行這項(xiàng)操作,警告使用中可能存在不正確和危險(xiǎn)的 API 實(shí)踐,并在 API 未得到最佳使用時(shí)報(bào)告任何與性能相關(guān)的警告。 默認(rèn)情況下,是禁用調(diào)試功能的,并且啟用調(diào)試功能是應(yīng)用程序的責(zé)任。 調(diào)試僅適用于實(shí)例級(jí)、在實(shí)例(VkInstance)創(chuàng)建時(shí)明確啟用的那些層。
啟用調(diào)試功能時(shí),會(huì)將其自身插入到層感興趣的 Vulkan 命令的調(diào)用鏈中。對(duì)于每個(gè)命令,調(diào)試功能 debugging 會(huì)訪問(wèn)所有啟用的層并驗(yàn)證它們是否存在任何潛在的錯(cuò)誤、警告以及調(diào)試信息等。
在 Vulkan 中進(jìn)行調(diào)試很簡(jiǎn)單。 以下概述描述了在應(yīng)用程序中啟用調(diào)試所需的步驟:
通過(guò)在實(shí)例級(jí)添加 VK_EXT_DEBUG_REPORT_EXTENSION_NAME 擴(kuò)展來(lái)啟用調(diào)試功能。
-
定義用于調(diào)試的一組驗(yàn)證層。 例如,我們對(duì)實(shí)例和設(shè)備級(jí)的以下層感興趣。 有關(guān)這些層功能的更多信息,請(qǐng)參閱下一節(jié):
- VK_LAYER_GOOGLE_unique_objects
- VK_LAYER_LUNARG_api_dump
- VK_LAYER_LUNARG_core_validation
- VK_LAYER_LUNARG_image
- VK_LAYER_LUNARG_object_tracker
- VK_LAYER_LUNARG_parameter_validation
- VK_LAYER_LUNARG_swapchain
- VK_LAYER_GOOGLE_threading
Vulkan 調(diào)試 API 不是核心命令的一部分,核心命令可以通過(guò)加載程序靜態(tài)加載。 這些調(diào)試 API 是以擴(kuò)展 API 的形式存在的,可以在運(yùn)行時(shí)檢索并動(dòng)態(tài)鏈接到預(yù)定義的函數(shù)指針。 因此,下一步,就是動(dòng)態(tài)查詢和鏈接調(diào)試擴(kuò)展 API vkCreateDebugReportCallbackEXT 和 vkDestroyDebugReportCallbackEXT。 這兩個(gè) API 調(diào)用用于創(chuàng)建和銷毀調(diào)試報(bào)告。
一旦成功檢索到用于調(diào)試報(bào)告的函數(shù)指針,前一個(gè) API(vkCreateDebugReportCallbackEXT)就會(huì)創(chuàng)建調(diào)試報(bào)告對(duì)象, Vulkan 會(huì)在用戶自定義的回調(diào)中返回調(diào)試報(bào)告,這個(gè)回調(diào)必須鏈接到此 API。
不再需要調(diào)試時(shí),銷毀調(diào)試報(bào)告對(duì)象。
理解 LunarG 驗(yàn)證層以及它們的功能
LunarG Vulkan SDK 支持以下層用于調(diào)試和驗(yàn)證目的。 在以下幾點(diǎn)中,我們描述了一些層,可以幫助您理解 Vulkan 提供的功能:
- VK_LAYER_GOOGLE_unique_objects:不可分發(fā)的 Vulkan 對(duì)象句柄不必是唯一的;驅(qū)動(dòng)程序可以為它認(rèn)為等效的多個(gè)對(duì)象返回相同的句柄。 此行為使得跟蹤對(duì)象變得困難,因?yàn)樵趧h除時(shí)不清楚要引用哪個(gè)對(duì)象。 該層在創(chuàng)建時(shí)將 Vulkan 對(duì)象打包為一個(gè)唯一的標(biāo)識(shí)符,并在應(yīng)用程序使用時(shí)將其解包。 這確保了在驗(yàn)證時(shí)有適當(dāng)?shù)膶?duì)象生命周期跟蹤(object lifetime tracking)。 根據(jù) LunarG 的建議,該層必須位于驗(yàn)證層鏈中的最后一個(gè),使其更靠近顯示驅(qū)動(dòng)程序。
- VK_LAYER_LUNARG_api_dump:該層有助于了解傳遞給 Vulkan API 的參數(shù)值。 它會(huì)打印所有的數(shù)據(jù)結(jié)構(gòu)參數(shù)及其值。
- VK_LAYER_LUNARG_core_validation:用于驗(yàn)證和打印來(lái)自描述符集、管線狀態(tài)、動(dòng)態(tài)狀態(tài)等的重要信息。 該層跟蹤并驗(yàn)證 GPU 內(nèi)存、對(duì)象綁定和命令緩沖區(qū)。 此外,它還驗(yàn)證圖形管線和計(jì)算管線。
- VK_LAYER_LUNARG_image:該層可用于驗(yàn)證紋理格式、渲染目標(biāo)格式等。 例如,它會(huì)驗(yàn)證設(shè)備上是否支持請(qǐng)求的格式。 它驗(yàn)證圖像視圖的創(chuàng)建參數(shù)對(duì)于創(chuàng)建視圖的圖像是否合理。
- VK_LAYER_LUNARG_object_tracker:跟蹤對(duì)象的創(chuàng)建及其使用和銷毀,這有助于避免內(nèi)存泄漏。 它還驗(yàn)證所引用的對(duì)象是否已正確創(chuàng)建并且當(dāng)前有效。
- VK_LAYER_LUNARG_parameter_validation:這個(gè)驗(yàn)證層確保傳遞給 API 的所有參數(shù)按照規(guī)范約定都是正確的,并且達(dá)到所需的期望。 它檢查參數(shù)的值是否一致,并且符合 Vulkan 規(guī)范中定義的有效使用條件。 此外,它還會(huì)檢查 Vulkan 控制結(jié)構(gòu)的 type 字段是否包含與該類型結(jié)構(gòu)所期望的、相同的值。
- VK_LAYER_LUNARG_swapchain:該層驗(yàn)證 WSI 交換鏈擴(kuò)展的使用。 例如,它會(huì)在使用其函數(shù)之前檢查 WSI 擴(kuò)展是否可用。 此外,它還驗(yàn)證圖像索引是否在交換鏈中的圖像數(shù)量之內(nèi),即檢查是否超出了數(shù)量范圍。
- VK_LAYER_GOOGLE_threading:這對(duì)于線程安全來(lái)說(shuō)是很有幫助的。 它檢查多線程 API 使用的有效性。 該層確保在多線程環(huán)境下使用多個(gè)調(diào)用的若干對(duì)象的同時(shí)使用。 它報(bào)告線程規(guī)則的違規(guī)并為這些調(diào)用強(qiáng)制執(zhí)行互斥鎖。 此外,它允許應(yīng)用程序繼續(xù)運(yùn)行而不會(huì)真正崩潰,盡管報(bào)告了線程存在的問(wèn)題。
- VK_LAYER_LUNARG_standard_validation:以正確的順序啟用所有標(biāo)準(zhǔn)層。
注意
有關(guān)驗(yàn)證層的更多信息,請(qǐng)?jiān)L問(wèn) LunarG 的官方網(wǎng)站。 查看 https://vulkan.lunarg.com/doc/sdk,并特別參考“驗(yàn)證層詳細(xì)信息”部分以獲取更多詳細(xì)信息。
Vulkan 中實(shí)現(xiàn)調(diào)試
由于調(diào)試是通過(guò)驗(yàn)證層暴露的,因此調(diào)試的大多數(shù)核心實(shí)現(xiàn)會(huì)在 VulkanLayerAndExtension 類(VulkanLEDer / .cpp)下完成。 在本節(jié)中,我們將學(xué)習(xí)有助于我們?cè)?Vulkan 中啟用調(diào)試過(guò)程的實(shí)現(xiàn)細(xì)節(jié):
Vulkan 調(diào)試工具不是核心功能默認(rèn)的一部分。 因此,為了啟用調(diào)試和訪問(wèn)報(bào)告回調(diào)功能,我們需要添加一些必要的擴(kuò)展和層:
- 擴(kuò)展:將 VK_EXT_DEBUG_REPORT_EXTENSION_NAME 擴(kuò)展添加到實(shí)例級(jí)別。 這有助于將 Vulkan 調(diào)試 API 暴露給應(yīng)用程序:
vector<const char *> instanceExtensionNames = {
. . . . // other extensios VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
};
- 層:在實(shí)例級(jí)別定義以下層,以允許在這些層上進(jìn)行調(diào)試:
vector<const char *> layerNames = { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_device_limits", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_image", "VK_LAYER_LUNARG_core_validation", "VK_LAYER_LUNARG_swapchain", "VK_LAYER_GOOGLE_unique_objects"
};
注意
除啟用的驗(yàn)證層外,LunarG SDK 還提供了一個(gè)稱為 VK_LAYER_LUNARG_standard_validation 的特殊層。 這樣就可以按照此處提到的正確順序啟用基本的驗(yàn)證。 此外,此內(nèi)置元數(shù)據(jù)層會(huì)以最佳順序加載一組標(biāo)準(zhǔn)的驗(yàn)證層。 如果您對(duì)層沒有特別指定的話,那么這是一個(gè)不錯(cuò)的選擇。
a)VK_LAYER_GOOGLE_threading
b)VK_LAYER_LUNARG_parameter_validation
c)VK_LAYER_LUNARG_object_tracker
d)VK_LAYER_LUNARG_image
e)VK_LAYER_LUNARG_core_validation
f)VK_LAYER_LUNARG_swapchain
g)VK_LAYER_GOOGLE_unique_objects
然后將這些層提供給 vkCreateInstance()API,從而啟用它們:
VulkanApplication* appObj = VulkanApplication::GetInstance(); appObj->createVulkanInstance(layerNames,
instanceExtensionNames, title);
// VulkanInstance::createInstance()
VkResult VulkanInstance::createInstance(vector<const char *>& layers, std::vector<const char *>& extensionNames,
char const*const appName)
{
. . .
VkInstanceCreateInfo instInfo = {};
// Specify the list of layer name to be enabled. instInfo.enabledLayerCount = layers.size(); instInfo.ppEnabledLayerNames = layers.data();
// Specify the list of extensions to
// be used in the application. instInfo.enabledExtensionCount = extensionNames.size(); instInfo.ppEnabledExtensionNames = extensionNames.data();
. . .
vkCreateInstance(&instInfo, NULL, &instance);
}
驗(yàn)證層是特定于供應(yīng)商和 SDK 版本的。 因此,建議在將它們傳遞給 vkCreateInstance()API 之前,首先檢查底層實(shí)現(xiàn)是否支持這些層。 這樣,當(dāng)運(yùn)行在其他驅(qū)動(dòng)程序的實(shí)現(xiàn)上時(shí),應(yīng)用程序始終保持可移植性。
areLayersSupported()函數(shù)是用戶定義的實(shí)用程序函數(shù),用于檢查傳入的層名稱是否和系統(tǒng)支持的層沖突。 在將不支持的層提供給系統(tǒng)之前,不支持的層會(huì)被通知給應(yīng)用程序并從層名稱中移除:
// VulkanLED.cpp
VkBool32 VulkanLayerAndExtension::areLayersSupported (vector<const char *> &layerNames)
{
uint32_t checkCount = layerNames.size(); uint32_t layerCount = layerPropertyList.size(); std::vector<const char*> unsupportLayerNames; for (uint32_t i = 0; i < checkCount; i++) {
VkBool32 isSupported = 0;
for (uint32_t j = 0; j < layerCount; j++) {
if (!strcmp(layerNames[i], layerPropertyList[j]. properties.layerName)) {
isSupported = 1;
}
}
if (!isSupported) {
std::cout << "No Layer support found, removed" " from layer: "<< layerNames[i] << endl;
unsupportLayerNames.push_back(layerNames[i]);
}
else {
cout << "Layer supported: " << layerNames[i] << endl;
}
}
for (auto i : unsupportLayerNames) {
auto it = std::find(layerNames.begin(),
layerNames.end(), i);
if (it != layerNames.end()) layerNames.erase(it);
}
return true;
}
調(diào)試報(bào)告是使用 vkCreateDebugReportCallbackEXT API 創(chuàng)建的。 這個(gè) API 不是 Vulkan 核心命令的一部分;因此,加載程序無(wú)法對(duì)其進(jìn)行靜態(tài)鏈接。 如果您嘗試按以下方式對(duì)其進(jìn)行訪問(wèn),您會(huì)收到“未定義的符號(hào)引用”錯(cuò)誤:
vkCreateDebugReportCallbackEXT(instance, NULL, NULL, NULL);
所有調(diào)試相關(guān)的 API 都需要使用 vkGetInstanceProcAddr()API 進(jìn)行查詢并動(dòng)態(tài)鏈接。 檢索到的 API 引用被存儲(chǔ)在相應(yīng)的函數(shù)指針中,名為 PFN_vkCreateDebugReportCallbackEXT。 VulkanLayerAndExtension :: createDebugReportCallback()函數(shù)檢索創(chuàng)建調(diào)試和銷毀調(diào)試 API,具體的實(shí)現(xiàn)如下所示:
/********* VulkanLED.h *********/
// Declaration of the create and destroy function pointers PFN_vkCreateDebugReportCallbackEXT dbgCreateDebugReportCallback; PFN_vkDestroyDebugReportCallbackEXT dbgDestroyDebugReportCallback;
/********* VulkanLED.cpp *********/
VulkanLayerAndExtension::createDebugReportCallback(){
. . .
// Get vkCreateDebugReportCallbackEXT API dbgCreateDebugReportCallback=(PFN_vkCreateDebugReportCallbackEXT) vkGetInstanceProcAddr(*instance,"vkCreateDebugReportCallbackEXT");
if (!dbgCreateDebugReportCallback) {
std::cout << "Error: GetInstanceProcAddr unable to locate vkCreateDebugReportCallbackEXT function.\n";
return VK_ERROR_INITIALIZATION_FAILED;
}
// Get vkDestroyDebugReportCallbackEXT API
dbgDestroyDebugReportCallback= (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr (*instance, "vkDestroyDebugReportCallbackEXT ");
if (!dbgDestroyDebugReportCallback) {
std::cout << "Error: GetInstanceProcAddr unable to locate vkDestroyDebugReportCallbackEXT function.\n";
return VK_ERROR_INITIALIZATION_FAILED;
}
. . .
}
vkGetInstanceProcAddr()API 動(dòng)態(tài)獲取實(shí)例級(jí)擴(kuò)展;這些擴(kuò)展不會(huì)在平臺(tái)上靜態(tài)暴露,并且需要通過(guò)該 API 動(dòng)態(tài)鏈接。 以下是此 API 的簽名:
PFN_vkVoidFunction vkGetInstanceProcAddr(
VkInstance instance,
const char* name);
下表介紹了 API 的各參數(shù):
| 參數(shù) | 描述 |
|---|---|
| instance | 這是一個(gè) VkInstance 變量。 如果此變量為 NULL,則該名稱必須是以下之一:vkEnumerateInstanceExtensionProperties,vkEnumerateInstanceLayerProperties 或 vkCreateInstance。 |
| name | 這是需要查詢的、用來(lái)動(dòng)態(tài)鏈接的 API 名稱。 |
使用 dbgCreateDebugReportCallback()函數(shù)指針,創(chuàng)建調(diào)試報(bào)告對(duì)象并將該句柄存儲(chǔ)在 debugReportCallback 中。 API 的第二個(gè)參數(shù)接受一個(gè) VkDebugReportCallbackCreateInfoEXT 控制結(jié)構(gòu)。 這個(gè)數(shù)據(jù)結(jié)構(gòu)定義了調(diào)試的行為,例如調(diào)試信息應(yīng)該包含的內(nèi)容:錯(cuò)誤、一般警告、信息、與性能相關(guān)的警告、調(diào)試信息等等。
另外,它還需要用戶自定義函數(shù)(debugFunction)的引用;這有助于過(guò)濾和打印從系統(tǒng)中檢索到的調(diào)試信息。 以下是創(chuàng)建調(diào)試報(bào)告的語(yǔ)法:
struct VkDebugReportCallbackCreateInfoEXT { VkStructureType type;
const void* pNext;
VkDebugReportFlagsEXT flags; PFN_vkDebugReportCallbackEXT fnCallback; void* pUserData;
};
下表描述了上面提到的結(jié)構(gòu)體字段的作用:
| 字段 | 描述 |
|---|---|
| type | 這是這個(gè)控制結(jié)構(gòu)的類型信息。 必須將其指定為 VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT。 |
| flags | 該字段是為了定義打開調(diào)試時(shí)要獲得的調(diào)試信息的種類;下表格定義了這些標(biāo)志。 |
| fnCallback | 該參字段指的是過(guò)濾和顯示調(diào)試消息的函數(shù)。 |
VkDebugReportFlagBitsEXT 控制結(jié)構(gòu)可以顯示以下標(biāo)志值的按位組合:
| 標(biāo)志位 | 描述 |
|---|---|
| VK_DEBUG_REPORT_INFORMATION_BIT_EXT | 這是用來(lái)顯示用戶友好的信息,描述當(dāng)前正在運(yùn)行的應(yīng)用程序中的后臺(tái)活動(dòng)的內(nèi)容,例如,調(diào)試應(yīng)用程序時(shí),資源的詳細(xì)信息可能是有用的,可以用來(lái)做進(jìn)一步優(yōu)化的判斷依據(jù)。 |
| VK_DEBUG_REPORT_WARNING_BIT_EXT | 這是用來(lái)對(duì) API 可能的錯(cuò)誤或危險(xiǎn)用法,提供警告消息。 |
| VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | 該參數(shù)表明 Vulkan 可能不是最佳的使用方式,可能會(huì)導(dǎo)致性能損失。 |
| VK_DEBUG_REPORT_ERROR_BIT_EXT | 這是指錯(cuò)誤消息,指定了錯(cuò)誤的 API 使用,這可能導(dǎo)致未定義的結(jié)果 - 例如,應(yīng)用程序崩潰 |
| VK_DEBUG_REPORT_DEBUG_BIT_EXT | 這表示來(lái)自加載程序和層的診斷信息。 |
createDebugReportCallback 函數(shù)實(shí)現(xiàn)調(diào)試報(bào)告的創(chuàng)建。 首先,它會(huì)創(chuàng)建 VulkanLayerAndExtension 控制結(jié)構(gòu)對(duì)象并填充相關(guān)信息。 這其中主要包括兩件事情:首先,分配一個(gè)用戶自定義的函數(shù)(pfnCallback),它會(huì)打印從系統(tǒng)接收到的調(diào)試信息(參見下一點(diǎn)); 其次,分配開發(fā)人員感興趣的調(diào)試標(biāo)志(flags):
/********* VulkanLED.h *********/
// Handle of the debug report callback
VkDebugReportCallbackEXT debugReportCallback;
// Debug report callback create information control structure
VkDebugReportCallbackCreateInfoEXT dbgReportCreateInfo = {};
/********* VulkanLED.cpp *********/
VulkanLayerAndExtension::createDebugReportCallback(){
. . .
// Define the debug report control structure,
// provide the reference of 'debugFunction',
// this function prints the debug information on the console.
dbgReportCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG
_REPORT_CREATE_INFO_EXT;
dbgReportCreateInfo.pfnCallback = debugFunction; dbgReportCreateInfo.pUserData = NULL; dbgReportCreateInfo.pNext = NULL;
dbgReportCreateInfo.flags = 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;
// Create the debug report callback and store the handle
// into 'debugReportCallback'
result = dbgCreateDebugReportCallback
(*instance, &dbgReportCreateInfo, NULL, &debugReportCallback);
if (result == VK_SUCCESS) {
cout << "Debug report callback object created successfully\n";
}
return result;
}
定義 debugFunction()函數(shù),以用戶友好的方式打印檢索到的調(diào)試信息。 它描述了調(diào)試信息的類型以及報(bào)告的消息:
VKAPI_ATTR VkBool32 VKAPI_CALL
VulkanLayerAndExtension::debugFunction( VkFlags msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject,
size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg, void *pUserData) {
if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
std::cout << "[VK_DEBUG_REPORT] ERROR: ["<<layerPrefix<<"]
Code" << msgCode << ":" << msg << std::endl;
}
else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
std::cout << "[VK_DEBUG_REPORT] WARNING: ["<<layerPrefix<<"]
Code" << msgCode << ":" << msg << std::endl;
}
else if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
std::cout<<"[VK_DEBUG_REPORT] INFORMATION:[" <<layerPrefix<<"]
Code" << msgCode << ":" << msg << std::endl;
}
else if(msgFlags& VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT){
cout <<"[VK_DEBUG_REPORT] PERFORMANCE: ["<<layerPrefix<<"]
Code" << msgCode << ":" << msg << std::endl;
}
else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
cout << "[VK_DEBUG_REPORT] DEBUG: ["<<layerPrefix<<"]
Code" << msgCode << ":" << msg << std::endl;
}
else {
return VK_FALSE;
}
return VK_SUCCESS;
}
下表描述了 debugFunction()回調(diào)的各個(gè)參數(shù):
| 參數(shù) | 描述 |
|---|---|
| msgFlags | 該參數(shù)指定了已經(jīng)觸發(fā)該調(diào)用的調(diào)試事件的類型,例如錯(cuò)誤、警告、性能警告等。 |
| objType | 該參數(shù)是指由觸發(fā)調(diào)用操作的對(duì)象類型。 |
| srcObject | 該參數(shù)是指由觸發(fā)的調(diào)用創(chuàng)建或操縱的對(duì)象句柄。 |
| location | 該參數(shù)是指描述事件的代碼位置。 |
| msgCode | 該參數(shù)是指消息代碼。 |
| layerPrefix | 該參數(shù)是指負(fù)責(zé)觸發(fā)調(diào)試事件的層。 |
| msg | 該參數(shù)包含調(diào)試消息文本。 |
| userData | 任何特定于應(yīng)用程序的用戶數(shù)據(jù)都使用此參數(shù)指定給回調(diào)。 |
提示
debugFunction 回調(diào)具有布爾返回值。 true 的返回值表示即使在發(fā)生錯(cuò)誤后,命令鏈仍然會(huì)繼續(xù)傳遞到后續(xù)的驗(yàn)證層。
但是,false 值指示驗(yàn)證層在發(fā)生錯(cuò)誤時(shí)中止執(zhí)行。 建議在第一個(gè)錯(cuò)誤處停止執(zhí)行。
錯(cuò)誤出現(xiàn)的本身就已經(jīng)表明意外發(fā)生了某些事情;讓系統(tǒng)在這些情況下運(yùn)行可能會(huì)導(dǎo)致未定義的結(jié)果或更進(jìn)一步的錯(cuò)誤,而且有時(shí)可能完全沒有意義。 在后一種情況下,如果在此處執(zhí)行被中止,則為開發(fā)人員提供了一個(gè)更好的機(jī)會(huì)來(lái)收集和修復(fù)報(bào)告中的錯(cuò)誤。 相比之下,前一種方法在系統(tǒng)拋出大量錯(cuò)誤的情況下,可能會(huì)使開發(fā)人員處于混亂狀態(tài),這有時(shí)會(huì)很麻煩。
為了在 vkCreateInstance 中啟用調(diào)試功能,將 dbgReportCreateInfo 提供給
VkInstanceCreateInfo 結(jié)構(gòu)的 pNext 字段:
VkInstanceCreateInfo instInfo = {};
. . .
instInfo.pNext = & layerExtension.dbgReportCreateInfo;
vkCreateInstance(&instInfo, NULL, &instance);
最后,一旦不再使用調(diào)試功能,就需要銷毀調(diào)試回調(diào)對(duì)象:
void VulkanLayerAndExtension::destroyDebugReportCallback(){ VulkanApplication* appObj = VulkanApplication::GetInstance(); dbgDestroyDebugReportCallback(instance,debugReportCallback,NULL);
}
以下是實(shí)現(xiàn)的、調(diào)試報(bào)告的輸出。 基于 GPU 供應(yīng)商和 SDK 提供商的差異,您的輸出可能與此不同。 此外,所報(bào)告的錯(cuò)誤或警告的解釋對(duì)于 SDK 本身而言是非常具體的,不同的 SDK 版本可能會(huì)存在一些差異。 但是在更高的層面上,規(guī)范仍然有效;這意味著您可以根據(jù)您打開的調(diào)試標(biāo)志看到攜帶警告、信息、調(diào)試幫助等的調(diào)試報(bào)告。

總結(jié)
本章簡(jiǎn)短、精確并且擁有大量的實(shí)踐和實(shí)現(xiàn)。 在沒有調(diào)試功能的情況下使用 Vulkan 就像在黑暗中沒有閃光燈拍照一樣。 我們非常清楚 Vulkan 需要大量的編程,而且開發(fā)人員出于顯而易見的原因會(huì)經(jīng)常犯錯(cuò), 畢竟他們是人類。 我們從錯(cuò)誤中學(xué)習(xí),調(diào)試使我們能夠找到并糾正這些錯(cuò)誤。 調(diào)試功能同時(shí)還提供有建設(shè)性的信息來(lái)構(gòu)建高質(zhì)量的軟件產(chǎn)品。
讓我們快速回顧一下。 我們知道了 Vulkan 的調(diào)試過(guò)程。 我們查看了各種 LunarG 驗(yàn)證層,并理解了其中每一個(gè)所扮演的角色及其責(zé)任。 接下來(lái),我們添加了一些選定的驗(yàn)證層,我們對(duì)其中的調(diào)試功能比較感興趣。
我們還添加了暴露了調(diào)試功能的調(diào)試擴(kuò)展;否則,API 的定義將無(wú)法動(dòng)態(tài)鏈接到應(yīng)用程序。 然后,我們通過(guò) Vulkan 創(chuàng)建用戶自定義調(diào)試報(bào)告的函數(shù)并將其鏈接到我們的調(diào)試報(bào)告回調(diào)上;這個(gè)回調(diào)以一種用戶友好和可展示的方式組織捕獲到的調(diào)試報(bào)告。
最后,我們實(shí)現(xiàn)了 API 來(lái)銷毀調(diào)試報(bào)告的回調(diào)對(duì)象。
在下一章中,我們將了解命令緩沖區(qū),探索它們?cè)?Vulkan 管線中的作用,并學(xué)習(xí)如何使用它們記錄和執(zhí)行 API 的調(diào)用。 我們還將深入研究用于主機(jī)內(nèi)存和設(shè)備內(nèi)存的 Vulkan 內(nèi)存管理;我們將學(xué)習(xí)各種 API 來(lái)對(duì)它們進(jìn)行控制。