mirror of
https://github.com/openharmony/third_party_vulkan-loader.git
synced 2026-07-19 09:05:16 -04:00
4f6ccc2f2f
Previously the loader would destroy any debug callbacks created during instance creation to later create new ones during instance destruction. This required a memory allocation to occur inside vkDestroyInstance, which can cause leaks if an OOM occurs during instance destruction. This commit simplifies the logic by keeping around the allocations made during instance creation by moving them into their own debug node chain. Then during instance destruction moves them back. Also renames several functions to better describe their intended purpose.
699 lines
31 KiB
C
699 lines
31 KiB
C
/*
|
|
* Copyright (c) 2015-2021 The Khronos Group Inc.
|
|
* Copyright (c) 2015-2021 Valve Corporation
|
|
* Copyright (c) 2015-2021 LunarG, Inc.
|
|
* Copyright (C) 2015-2016 Google Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
|
|
* Author: Jon Ashburn <jon@LunarG.com>
|
|
* Author: Mark Young <marky@lunarg.com>
|
|
* Author: Charles Giessen <charles@lunarg.com>
|
|
*
|
|
*/
|
|
|
|
#include <inttypes.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifndef WIN32
|
|
#include <signal.h>
|
|
#else
|
|
#endif
|
|
|
|
#include "vulkan/vk_layer.h"
|
|
#include "vk_object_types.h"
|
|
|
|
#include "allocation.h"
|
|
#include "debug_utils.h"
|
|
#include "log.h"
|
|
#include "loader.h"
|
|
#include "vk_loader_platform.h"
|
|
|
|
// VK_EXT_debug_report related items
|
|
|
|
VkResult util_CreateDebugUtilsMessenger(struct loader_instance *inst, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
|
|
const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT messenger) {
|
|
VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
|
|
|
|
pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_calloc_with_instance_fallback(
|
|
pAllocator, inst, sizeof(VkLayerDbgFunctionNode), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
|
|
if (!pNewDbgFuncNode) {
|
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
}
|
|
|
|
pNewDbgFuncNode->is_messenger = true;
|
|
pNewDbgFuncNode->messenger.messenger = messenger;
|
|
pNewDbgFuncNode->messenger.pfnUserCallback = pCreateInfo->pfnUserCallback;
|
|
pNewDbgFuncNode->messenger.messageSeverity = pCreateInfo->messageSeverity;
|
|
pNewDbgFuncNode->messenger.messageType = pCreateInfo->messageType;
|
|
pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
|
|
pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
|
|
inst->DbgFunctionHead = pNewDbgFuncNode;
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
static VKAPI_ATTR VkResult VKAPI_CALL
|
|
debug_utils_CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
|
|
const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT *pMessenger) {
|
|
struct loader_instance *inst = loader_get_instance(instance);
|
|
loader_platform_thread_lock_mutex(&loader_lock);
|
|
VkResult result = inst->disp->layer_inst_disp.CreateDebugUtilsMessengerEXT(inst->instance, pCreateInfo, pAllocator, pMessenger);
|
|
loader_platform_thread_unlock_mutex(&loader_lock);
|
|
return result;
|
|
}
|
|
|
|
VkBool32 util_SubmitDebugUtilsMessageEXT(const struct loader_instance *inst, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
|
VkDebugUtilsMessageTypeFlagsEXT messageTypes,
|
|
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) {
|
|
VkBool32 bail = false;
|
|
|
|
if (NULL != pCallbackData) {
|
|
VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
|
|
VkDebugReportObjectTypeEXT object_type = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;
|
|
VkDebugReportFlagsEXT object_flags = 0;
|
|
uint64_t object_handle = 0;
|
|
|
|
debug_utils_AnnotFlagsToReportFlags(messageSeverity, messageTypes, &object_flags);
|
|
if (0 < pCallbackData->objectCount) {
|
|
debug_utils_AnnotObjectToDebugReportObject(pCallbackData->pObjects, &object_type, &object_handle);
|
|
}
|
|
|
|
while (pTrav) {
|
|
if (pTrav->is_messenger && (pTrav->messenger.messageSeverity & messageSeverity) &&
|
|
(pTrav->messenger.messageType & messageTypes)) {
|
|
if (pTrav->messenger.pfnUserCallback(messageSeverity, messageTypes, pCallbackData, pTrav->pUserData)) {
|
|
bail = true;
|
|
}
|
|
}
|
|
if (!pTrav->is_messenger && pTrav->report.msgFlags & object_flags) {
|
|
if (pTrav->report.pfnMsgCallback(object_flags, object_type, object_handle, 0, pCallbackData->messageIdNumber,
|
|
pCallbackData->pMessageIdName, pCallbackData->pMessage, pTrav->pUserData)) {
|
|
bail = true;
|
|
}
|
|
}
|
|
|
|
pTrav = pTrav->pNext;
|
|
}
|
|
}
|
|
|
|
return bail;
|
|
}
|
|
|
|
void util_DestroyDebugUtilsMessenger(struct loader_instance *inst, VkDebugUtilsMessengerEXT messenger,
|
|
const VkAllocationCallbacks *pAllocator) {
|
|
VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
|
|
VkLayerDbgFunctionNode *pPrev = pTrav;
|
|
|
|
while (pTrav) {
|
|
if (pTrav->is_messenger && pTrav->messenger.messenger == messenger) {
|
|
pPrev->pNext = pTrav->pNext;
|
|
if (inst->DbgFunctionHead == pTrav) inst->DbgFunctionHead = pTrav->pNext;
|
|
loader_free_with_instance_fallback(pAllocator, inst, pTrav);
|
|
break;
|
|
}
|
|
pPrev = pTrav;
|
|
pTrav = pTrav->pNext;
|
|
}
|
|
}
|
|
|
|
VkResult util_CreateDebugUtilsMessengers(struct loader_instance *inst, const void *pChain,
|
|
const VkAllocationCallbacks *pAllocator) {
|
|
const void *pNext = pChain;
|
|
while (pNext) {
|
|
if (((const VkBaseInStructure *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
|
|
// Assign a unique handle to each messenger (just use the address of the VkDebugUtilsMessengerCreateInfoEXT)
|
|
// This is only being used this way due to it being for an 'anonymous' callback during instance creation
|
|
VkDebugUtilsMessengerEXT messenger_handle = (VkDebugUtilsMessengerEXT)(uintptr_t)pNext;
|
|
VkResult ret = util_CreateDebugUtilsMessenger(inst, (const VkDebugUtilsMessengerCreateInfoEXT *)pNext, pAllocator,
|
|
messenger_handle);
|
|
if (ret != VK_SUCCESS) {
|
|
return ret;
|
|
}
|
|
}
|
|
pNext = (void *)((VkBaseInStructure *)pNext)->pNext;
|
|
}
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
static VKAPI_ATTR void VKAPI_CALL debug_utils_SubmitDebugUtilsMessageEXT(
|
|
VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes,
|
|
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) {
|
|
struct loader_instance *inst = loader_get_instance(instance);
|
|
|
|
inst->disp->layer_inst_disp.SubmitDebugUtilsMessageEXT(inst->instance, messageSeverity, messageTypes, pCallbackData);
|
|
}
|
|
|
|
static VKAPI_ATTR void VKAPI_CALL debug_utils_DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
|
|
const VkAllocationCallbacks *pAllocator) {
|
|
struct loader_instance *inst = loader_get_instance(instance);
|
|
loader_platform_thread_lock_mutex(&loader_lock);
|
|
|
|
inst->disp->layer_inst_disp.DestroyDebugUtilsMessengerEXT(inst->instance, messenger, pAllocator);
|
|
|
|
loader_platform_thread_unlock_mutex(&loader_lock);
|
|
}
|
|
|
|
// This is the instance chain terminator function for CreateDebugUtilsMessenger
|
|
VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugUtilsMessengerEXT(VkInstance instance,
|
|
const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
|
|
const VkAllocationCallbacks *pAllocator,
|
|
VkDebugUtilsMessengerEXT *pMessenger) {
|
|
VkDebugUtilsMessengerEXT *icd_info = NULL;
|
|
const struct loader_icd_term *icd_term;
|
|
struct loader_instance *inst = (struct loader_instance *)instance;
|
|
VkResult res = VK_SUCCESS;
|
|
uint32_t storage_idx;
|
|
VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
|
|
|
|
icd_info = (VkDebugUtilsMessengerEXT *)loader_calloc_with_instance_fallback(
|
|
pAllocator, inst, inst->total_icd_count * sizeof(VkDebugUtilsMessengerEXT), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
|
|
if (!icd_info) {
|
|
res = VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
goto out;
|
|
}
|
|
|
|
storage_idx = 0;
|
|
for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
|
|
if (!icd_term->dispatch.CreateDebugUtilsMessengerEXT) {
|
|
continue;
|
|
}
|
|
|
|
res = icd_term->dispatch.CreateDebugUtilsMessengerEXT(icd_term->instance, pCreateInfo, pAllocator, &icd_info[storage_idx]);
|
|
|
|
if (res != VK_SUCCESS) {
|
|
goto out;
|
|
}
|
|
storage_idx++;
|
|
}
|
|
|
|
// Setup the debug report callback in the terminator since a layer may want
|
|
// to grab the information itself (RenderDoc) and then return back to the
|
|
// user callback a sub-set of the messages.
|
|
pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_calloc_with_instance_fallback(
|
|
pAllocator, inst, sizeof(VkLayerDbgFunctionNode), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
if (!pNewDbgFuncNode) {
|
|
res = VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
goto out;
|
|
}
|
|
|
|
pNewDbgFuncNode->is_messenger = true;
|
|
pNewDbgFuncNode->messenger.pfnUserCallback = pCreateInfo->pfnUserCallback;
|
|
pNewDbgFuncNode->messenger.messageSeverity = pCreateInfo->messageSeverity;
|
|
pNewDbgFuncNode->messenger.messageType = pCreateInfo->messageType;
|
|
pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
|
|
pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
|
|
inst->DbgFunctionHead = pNewDbgFuncNode;
|
|
|
|
*(VkDebugUtilsMessengerEXT **)pMessenger = icd_info;
|
|
pNewDbgFuncNode->messenger.messenger = *pMessenger;
|
|
|
|
out:
|
|
|
|
// Roll back on errors
|
|
if (VK_SUCCESS != res) {
|
|
storage_idx = 0;
|
|
for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
|
|
if (NULL == icd_term->dispatch.DestroyDebugUtilsMessengerEXT) {
|
|
continue;
|
|
}
|
|
|
|
if (icd_info && icd_info[storage_idx]) {
|
|
icd_term->dispatch.DestroyDebugUtilsMessengerEXT(icd_term->instance, icd_info[storage_idx], pAllocator);
|
|
}
|
|
storage_idx++;
|
|
}
|
|
loader_free(pAllocator, pNewDbgFuncNode);
|
|
loader_free(pAllocator, icd_info);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
// This is the instance chain terminator function for DestroyDebugUtilsMessenger
|
|
VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
|
|
const VkAllocationCallbacks *pAllocator) {
|
|
uint32_t storage_idx;
|
|
VkDebugUtilsMessengerEXT *icd_info;
|
|
const struct loader_icd_term *icd_term;
|
|
|
|
struct loader_instance *inst = (struct loader_instance *)instance;
|
|
icd_info = *(VkDebugUtilsMessengerEXT **)&messenger;
|
|
storage_idx = 0;
|
|
for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
|
|
if (NULL == icd_term->dispatch.DestroyDebugUtilsMessengerEXT) {
|
|
continue;
|
|
}
|
|
|
|
if (icd_info && icd_info[storage_idx]) {
|
|
icd_term->dispatch.DestroyDebugUtilsMessengerEXT(icd_term->instance, icd_info[storage_idx], pAllocator);
|
|
}
|
|
storage_idx++;
|
|
}
|
|
|
|
util_DestroyDebugUtilsMessenger(inst, messenger, pAllocator);
|
|
|
|
loader_free(pAllocator, icd_info);
|
|
}
|
|
|
|
// This is the instance chain terminator function for SubmitDebugUtilsMessageEXT
|
|
VKAPI_ATTR void VKAPI_CALL terminator_SubmitDebugUtilsMessageEXT(VkInstance instance,
|
|
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
|
VkDebugUtilsMessageTypeFlagsEXT messageTypes,
|
|
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) {
|
|
loader_platform_thread_lock_mutex(&loader_lock);
|
|
// NOTE: Just make the callback ourselves because there could be one or more ICDs that support this extension
|
|
// and each one will trigger the callback to the user. This would result in multiple callback triggers
|
|
// per message. Instead, if we get a messaged up to here, then just trigger the message ourselves and
|
|
// return. This would still allow the ICDs to trigger their own messages, but won't get any external ones.
|
|
struct loader_instance *inst = (struct loader_instance *)instance;
|
|
util_SubmitDebugUtilsMessageEXT(inst, messageSeverity, messageTypes, pCallbackData);
|
|
loader_platform_thread_unlock_mutex(&loader_lock);
|
|
}
|
|
|
|
// VK_EXT_debug_report related items
|
|
|
|
VkResult util_CreateDebugReportCallback(struct loader_instance *inst, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
|
|
const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT callback) {
|
|
VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
|
|
|
|
pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_calloc_with_instance_fallback(
|
|
pAllocator, inst, sizeof(VkLayerDbgFunctionNode), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
if (!pNewDbgFuncNode) {
|
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
}
|
|
|
|
pNewDbgFuncNode->is_messenger = false;
|
|
pNewDbgFuncNode->report.msgCallback = callback;
|
|
pNewDbgFuncNode->report.pfnMsgCallback = pCreateInfo->pfnCallback;
|
|
pNewDbgFuncNode->report.msgFlags = pCreateInfo->flags;
|
|
pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
|
|
pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
|
|
inst->DbgFunctionHead = pNewDbgFuncNode;
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
static VKAPI_ATTR VkResult VKAPI_CALL
|
|
debug_utils_CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
|
|
const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback) {
|
|
struct loader_instance *inst = loader_get_instance(instance);
|
|
loader_platform_thread_lock_mutex(&loader_lock);
|
|
VkResult result = inst->disp->layer_inst_disp.CreateDebugReportCallbackEXT(inst->instance, pCreateInfo, pAllocator, pCallback);
|
|
loader_platform_thread_unlock_mutex(&loader_lock);
|
|
return result;
|
|
}
|
|
|
|
// Utility function to handle reporting
|
|
VkBool32 util_DebugReportMessage(const struct loader_instance *inst, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType,
|
|
uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
|
|
VkBool32 bail = false;
|
|
VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
|
|
VkDebugUtilsMessageSeverityFlagBitsEXT severity;
|
|
VkDebugUtilsMessageTypeFlagsEXT types;
|
|
VkDebugUtilsMessengerCallbackDataEXT callback_data;
|
|
VkDebugUtilsObjectNameInfoEXT object_name;
|
|
|
|
debug_utils_ReportFlagsToAnnotFlags(msgFlags, false, &severity, &types);
|
|
debug_utils_ReportObjectToAnnotObject(objectType, srcObject, &object_name);
|
|
|
|
callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
|
|
callback_data.pNext = NULL;
|
|
callback_data.flags = 0;
|
|
callback_data.pMessageIdName = pLayerPrefix;
|
|
callback_data.messageIdNumber = msgCode;
|
|
callback_data.pMessage = pMsg;
|
|
callback_data.cmdBufLabelCount = 0;
|
|
callback_data.pCmdBufLabels = NULL;
|
|
callback_data.queueLabelCount = 0;
|
|
callback_data.pQueueLabels = NULL;
|
|
callback_data.objectCount = 1;
|
|
callback_data.pObjects = &object_name;
|
|
|
|
while (pTrav) {
|
|
if (!pTrav->is_messenger && pTrav->report.msgFlags & msgFlags) {
|
|
if (pTrav->report.pfnMsgCallback(msgFlags, objectType, srcObject, location, msgCode, pLayerPrefix, pMsg,
|
|
pTrav->pUserData)) {
|
|
bail = true;
|
|
}
|
|
}
|
|
if (pTrav->is_messenger && (pTrav->messenger.messageSeverity & severity) && (pTrav->messenger.messageType & types)) {
|
|
if (pTrav->messenger.pfnUserCallback(severity, types, &callback_data, pTrav->pUserData)) {
|
|
bail = true;
|
|
}
|
|
}
|
|
|
|
pTrav = pTrav->pNext;
|
|
}
|
|
|
|
return bail;
|
|
}
|
|
|
|
void util_DestroyDebugReportCallback(struct loader_instance *inst, VkDebugReportCallbackEXT callback,
|
|
const VkAllocationCallbacks *pAllocator) {
|
|
VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
|
|
VkLayerDbgFunctionNode *pPrev = pTrav;
|
|
|
|
while (pTrav) {
|
|
if (!pTrav->is_messenger && pTrav->report.msgCallback == callback) {
|
|
pPrev->pNext = pTrav->pNext;
|
|
if (inst->DbgFunctionHead == pTrav) inst->DbgFunctionHead = pTrav->pNext;
|
|
loader_free_with_instance_fallback(pAllocator, inst, pTrav);
|
|
break;
|
|
}
|
|
pPrev = pTrav;
|
|
pTrav = pTrav->pNext;
|
|
}
|
|
}
|
|
|
|
VkResult util_CreateDebugReportCallbacks(struct loader_instance *inst, const void *pChain,
|
|
const VkAllocationCallbacks *pAllocator) {
|
|
const void *pNext = pChain;
|
|
while (pNext) {
|
|
if (((VkBaseInStructure *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) {
|
|
// Assign a unique handle to each callback (just use the address of the VkDebugReportCallbackCreateInfoEXT):
|
|
// This is only being used this way due to it being for an 'anonymous' callback during instance creation
|
|
VkDebugReportCallbackEXT report_handle = (VkDebugReportCallbackEXT)(uintptr_t)pNext;
|
|
VkResult ret =
|
|
util_CreateDebugReportCallback(inst, (const VkDebugReportCallbackCreateInfoEXT *)pNext, pAllocator, report_handle);
|
|
if (ret != VK_SUCCESS) {
|
|
return ret;
|
|
}
|
|
}
|
|
pNext = (void *)((VkBaseInStructure *)pNext)->pNext;
|
|
}
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
static VKAPI_ATTR void VKAPI_CALL debug_utils_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
|
|
const VkAllocationCallbacks *pAllocator) {
|
|
struct loader_instance *inst = loader_get_instance(instance);
|
|
loader_platform_thread_lock_mutex(&loader_lock);
|
|
|
|
inst->disp->layer_inst_disp.DestroyDebugReportCallbackEXT(inst->instance, callback, pAllocator);
|
|
|
|
loader_platform_thread_unlock_mutex(&loader_lock);
|
|
}
|
|
|
|
static VKAPI_ATTR void VKAPI_CALL debug_utils_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
|
|
VkDebugReportObjectTypeEXT objType, uint64_t object,
|
|
size_t location, int32_t msgCode, const char *pLayerPrefix,
|
|
const char *pMsg) {
|
|
struct loader_instance *inst = loader_get_instance(instance);
|
|
|
|
inst->disp->layer_inst_disp.DebugReportMessageEXT(inst->instance, flags, objType, object, location, msgCode, pLayerPrefix,
|
|
pMsg);
|
|
}
|
|
|
|
// This is the instance chain terminator function
|
|
// for CreateDebugReportCallback
|
|
VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugReportCallbackEXT(VkInstance instance,
|
|
const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
|
|
const VkAllocationCallbacks *pAllocator,
|
|
VkDebugReportCallbackEXT *pCallback) {
|
|
VkDebugReportCallbackEXT *icd_info = NULL;
|
|
const struct loader_icd_term *icd_term;
|
|
struct loader_instance *inst = (struct loader_instance *)instance;
|
|
VkResult res = VK_SUCCESS;
|
|
uint32_t storage_idx;
|
|
VkLayerDbgFunctionNode *pNewDbgFuncNode = NULL;
|
|
|
|
icd_info = ((VkDebugReportCallbackEXT *)loader_calloc(pAllocator, inst->total_icd_count * sizeof(VkDebugReportCallbackEXT),
|
|
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
|
|
if (!icd_info) {
|
|
res = VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
goto out;
|
|
}
|
|
|
|
storage_idx = 0;
|
|
for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
|
|
if (!icd_term->dispatch.CreateDebugReportCallbackEXT) {
|
|
continue;
|
|
}
|
|
|
|
res = icd_term->dispatch.CreateDebugReportCallbackEXT(icd_term->instance, pCreateInfo, pAllocator, &icd_info[storage_idx]);
|
|
|
|
if (res != VK_SUCCESS) {
|
|
goto out;
|
|
}
|
|
storage_idx++;
|
|
}
|
|
|
|
// Setup the debug report callback in the terminator since a layer may want
|
|
// to grab the information itself (RenderDoc) and then return back to the
|
|
// user callback a sub-set of the messages.
|
|
pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_calloc_with_instance_fallback(
|
|
pAllocator, inst, sizeof(VkLayerDbgFunctionNode), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
|
|
if (!pNewDbgFuncNode) {
|
|
res = VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
goto out;
|
|
}
|
|
|
|
pNewDbgFuncNode->is_messenger = false;
|
|
pNewDbgFuncNode->report.pfnMsgCallback = pCreateInfo->pfnCallback;
|
|
pNewDbgFuncNode->report.msgFlags = pCreateInfo->flags;
|
|
pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
|
|
pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
|
|
inst->DbgFunctionHead = pNewDbgFuncNode;
|
|
|
|
*(VkDebugReportCallbackEXT **)pCallback = icd_info;
|
|
pNewDbgFuncNode->report.msgCallback = *pCallback;
|
|
|
|
out:
|
|
|
|
// Roll back on errors
|
|
if (VK_SUCCESS != res) {
|
|
storage_idx = 0;
|
|
for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
|
|
if (NULL == icd_term->dispatch.DestroyDebugReportCallbackEXT) {
|
|
continue;
|
|
}
|
|
|
|
if (icd_info && icd_info[storage_idx]) {
|
|
icd_term->dispatch.DestroyDebugReportCallbackEXT(icd_term->instance, icd_info[storage_idx], pAllocator);
|
|
}
|
|
storage_idx++;
|
|
}
|
|
loader_free(pAllocator, pNewDbgFuncNode);
|
|
loader_free(pAllocator, icd_info);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
// This is the instance chain terminator function for DestroyDebugReportCallback
|
|
VKAPI_ATTR void VKAPI_CALL terminator_DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
|
|
const VkAllocationCallbacks *pAllocator) {
|
|
uint32_t storage_idx;
|
|
VkDebugReportCallbackEXT *icd_info;
|
|
const struct loader_icd_term *icd_term;
|
|
|
|
struct loader_instance *inst = (struct loader_instance *)instance;
|
|
icd_info = *(VkDebugReportCallbackEXT **)&callback;
|
|
storage_idx = 0;
|
|
for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
|
|
if (NULL == icd_term->dispatch.DestroyDebugReportCallbackEXT) {
|
|
continue;
|
|
}
|
|
|
|
if (icd_info[storage_idx]) {
|
|
icd_term->dispatch.DestroyDebugReportCallbackEXT(icd_term->instance, icd_info[storage_idx], pAllocator);
|
|
}
|
|
storage_idx++;
|
|
}
|
|
|
|
util_DestroyDebugReportCallback(inst, callback, pAllocator);
|
|
|
|
loader_free(pAllocator, icd_info);
|
|
}
|
|
|
|
// This is the instance chain terminator function for DebugReportMessage
|
|
VKAPI_ATTR void VKAPI_CALL terminator_DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags,
|
|
VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
|
|
int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
|
|
const struct loader_icd_term *icd_term;
|
|
|
|
struct loader_instance *inst = (struct loader_instance *)instance;
|
|
|
|
loader_platform_thread_lock_mutex(&loader_lock);
|
|
for (icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
|
|
if (icd_term->dispatch.DebugReportMessageEXT != NULL) {
|
|
icd_term->dispatch.DebugReportMessageEXT(icd_term->instance, flags, objType, object, location, msgCode, pLayerPrefix,
|
|
pMsg);
|
|
}
|
|
}
|
|
|
|
// Now that all ICDs have seen the message, call the necessary callbacks. Ignoring "bail" return value
|
|
// as there is nothing to bail from at this point.
|
|
|
|
util_DebugReportMessage(inst, flags, objType, object, location, msgCode, pLayerPrefix, pMsg);
|
|
|
|
loader_platform_thread_unlock_mutex(&loader_lock);
|
|
}
|
|
|
|
// General utilities
|
|
|
|
static const VkExtensionProperties debug_utils_extension_info[] = {
|
|
{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION},
|
|
{VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_SPEC_VERSION},
|
|
};
|
|
|
|
void destroy_debug_callbacks_chain(struct loader_instance *inst, const VkAllocationCallbacks *pAllocator) {
|
|
VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
|
|
VkLayerDbgFunctionNode *pNext = NULL;
|
|
while (pTrav) {
|
|
pNext = pTrav->pNext;
|
|
loader_free_with_instance_fallback(pAllocator, inst, pTrav);
|
|
pTrav = pNext;
|
|
}
|
|
inst->DbgFunctionHead = NULL;
|
|
}
|
|
|
|
void add_debug_extensions_to_ext_list(const struct loader_instance *inst, struct loader_extension_list *ext_list) {
|
|
loader_add_to_ext_list(inst, ext_list, sizeof(debug_utils_extension_info) / sizeof(VkExtensionProperties),
|
|
debug_utils_extension_info);
|
|
}
|
|
|
|
void check_for_enabled_debug_extensions(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo) {
|
|
for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
|
|
if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
|
|
ptr_instance->enabled_known_extensions.ext_debug_report = 1;
|
|
} else if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) {
|
|
ptr_instance->enabled_known_extensions.ext_debug_utils = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool debug_extensions_InstanceGpa(struct loader_instance *ptr_instance, const char *name, void **addr) {
|
|
bool ret_type = false;
|
|
|
|
*addr = NULL;
|
|
|
|
if (!strcmp("vkCreateDebugReportCallbackEXT", name)) {
|
|
*addr =
|
|
ptr_instance->enabled_known_extensions.ext_debug_report == 1 ? (void *)debug_utils_CreateDebugReportCallbackEXT : NULL;
|
|
ret_type = true;
|
|
} else if (!strcmp("vkDestroyDebugReportCallbackEXT", name)) {
|
|
*addr =
|
|
ptr_instance->enabled_known_extensions.ext_debug_report == 1 ? (void *)debug_utils_DestroyDebugReportCallbackEXT : NULL;
|
|
ret_type = true;
|
|
} else if (!strcmp("vkDebugReportMessageEXT", name)) {
|
|
*addr = ptr_instance->enabled_known_extensions.ext_debug_report == 1 ? (void *)debug_utils_DebugReportMessageEXT : NULL;
|
|
return true;
|
|
}
|
|
if (!strcmp("vkCreateDebugUtilsMessengerEXT", name)) {
|
|
*addr =
|
|
ptr_instance->enabled_known_extensions.ext_debug_utils == 1 ? (void *)debug_utils_CreateDebugUtilsMessengerEXT : NULL;
|
|
ret_type = true;
|
|
} else if (!strcmp("vkDestroyDebugUtilsMessengerEXT", name)) {
|
|
*addr =
|
|
ptr_instance->enabled_known_extensions.ext_debug_utils == 1 ? (void *)debug_utils_DestroyDebugUtilsMessengerEXT : NULL;
|
|
ret_type = true;
|
|
} else if (!strcmp("vkSubmitDebugUtilsMessageEXT", name)) {
|
|
*addr = ptr_instance->enabled_known_extensions.ext_debug_utils == 1 ? (void *)debug_utils_SubmitDebugUtilsMessageEXT : NULL;
|
|
ret_type = true;
|
|
}
|
|
|
|
return ret_type;
|
|
}
|
|
|
|
bool debug_utils_ReportFlagsToAnnotFlags(VkDebugReportFlagsEXT dr_flags, bool default_flag_is_spec,
|
|
VkDebugUtilsMessageSeverityFlagBitsEXT *da_severity,
|
|
VkDebugUtilsMessageTypeFlagsEXT *da_type) {
|
|
bool type_set = false;
|
|
if (NULL == da_severity || NULL == da_type) {
|
|
return false;
|
|
}
|
|
*da_type = 0;
|
|
*da_severity = 0;
|
|
|
|
if ((dr_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) != 0) {
|
|
*da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
|
|
*da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
|
|
type_set = true;
|
|
} else if ((dr_flags & (VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)) != 0) {
|
|
*da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
|
|
} else if ((dr_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) {
|
|
*da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
|
} else if ((dr_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) != 0) {
|
|
*da_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
|
|
*da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
|
|
type_set = true;
|
|
}
|
|
|
|
if ((dr_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) != 0) {
|
|
*da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
|
} else if (!type_set) {
|
|
if (default_flag_is_spec) {
|
|
*da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
|
|
} else {
|
|
*da_type |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool debug_utils_AnnotFlagsToReportFlags(VkDebugUtilsMessageSeverityFlagBitsEXT da_severity,
|
|
VkDebugUtilsMessageTypeFlagsEXT da_type, VkDebugReportFlagsEXT *dr_flags) {
|
|
if (NULL == dr_flags) {
|
|
return false;
|
|
}
|
|
|
|
*dr_flags = 0;
|
|
|
|
if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0) {
|
|
*dr_flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
|
|
} else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0) {
|
|
if ((da_type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0) {
|
|
*dr_flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
|
|
} else {
|
|
*dr_flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
|
|
}
|
|
} else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0) {
|
|
*dr_flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
|
|
} else if ((da_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0) {
|
|
*dr_flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool debug_utils_ReportObjectToAnnotObject(VkDebugReportObjectTypeEXT dr_object_type, uint64_t object_handle,
|
|
VkDebugUtilsObjectNameInfoEXT *da_object_name_info) {
|
|
if (NULL == da_object_name_info) {
|
|
return false;
|
|
}
|
|
da_object_name_info->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
|
|
da_object_name_info->pNext = NULL;
|
|
da_object_name_info->objectHandle = (uint64_t)(uintptr_t)object_handle;
|
|
da_object_name_info->pObjectName = NULL;
|
|
da_object_name_info->objectType = convertDebugReportObjectToCoreObject(dr_object_type);
|
|
return true;
|
|
}
|
|
|
|
bool debug_utils_AnnotObjectToDebugReportObject(const VkDebugUtilsObjectNameInfoEXT *da_object_name_info,
|
|
VkDebugReportObjectTypeEXT *dr_object_type, uint64_t *dr_object_handle) {
|
|
if (NULL == da_object_name_info || NULL == dr_object_type || NULL == dr_object_handle) {
|
|
return false;
|
|
}
|
|
*dr_object_type = convertCoreObjectToDebugReportObject(da_object_name_info->objectType);
|
|
*dr_object_handle = da_object_name_info->objectHandle;
|
|
return true;
|
|
}
|