第 4 章. Vulkan 中的調(diào)試

在上一章中,我們初始化了 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)試所需的步驟:

  1. 通過(guò)在實(shí)例級(jí)添加 VK_EXT_DEBUG_REPORT_EXTENSION_NAME 擴(kuò)展來(lái)啟用調(diào)試功能。

  2. 定義用于調(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
  3. 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)告。

  4. 一旦成功檢索到用于調(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。

  5. 不再需要調(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)告。

4-001.png

總結(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)行控制。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 利用我們前兩章中獲得的知識(shí),我們現(xiàn)在已經(jīng)達(dá)到了可以從 0 開始進(jìn)行 Vulkan 編程的水平。 這兩章奠定了基礎(chǔ),...
    雨中亭_聽雨中閱讀 1,173評(píng)論 1 0
  • Vulkan 是一套革命性的高性能 3D 圖形、計(jì)算 API,適用于現(xiàn)代 GPU 管線系統(tǒng),用來(lái)滿足社區(qū)的苛刻要求...
    雨中亭_聽雨中閱讀 2,907評(píng)論 0 8
  • ORA-00001: 違反唯一約束條件 (.) 錯(cuò)誤說(shuō)明:當(dāng)在唯一索引所對(duì)應(yīng)的列上鍵入重復(fù)值時(shí),會(huì)觸發(fā)此異常。 O...
    我想起個(gè)好名字閱讀 5,985評(píng)論 0 9
  • [[SDImageCache sharedImageCache] getSize]換取緩存大小,單位字節(jié),除以10...
    流沙3333閱讀 933評(píng)論 0 0
  • 憂悶填滿心房的時(shí)候 花零葉落,呵,又是 又是慘切凄寒的深秋 耳鼓回漾著低微的嘆息 ~~所有成過(guò)去的過(guò)去 留剩些只能...
    Beloved雅閱讀 360評(píng)論 0 0

友情鏈接更多精彩內(nèi)容