blob: b7f77c4a6e1b0814b0885bf33805b91b00912893 [file] [log] [blame]
/*
* Vulkan
*
* Copyright (C) 2014 LunarG, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Courtney Goeltzenleuchter <courtney@lunarg.com>
*/
#ifndef LAYER_LOGGING_H
#define LAYER_LOGGING_H
#include <stdio.h>
#include <stdbool.h>
#include <unordered_map>
#include "vkLayer.h"
#include "layers_table.h"
struct debug_report_data {
VkLayerDbgFunctionNode *g_pDbgFunctionHead;
bool g_DEBUG_REPORT;
};
static std::unordered_map<void *, struct debug_report_data *> debug_report_data_map;
static struct debug_report_data *get_debug_data_ptr(
void *data_key)
{
struct debug_report_data *debug_data;
std::unordered_map<void *, struct debug_report_data *>::const_iterator got;
got = debug_report_data_map.find(data_key);
if ( got == debug_report_data_map.end() ) {
debug_data = new struct debug_report_data;
memset(debug_data, 0, sizeof(*debug_data));
debug_report_data_map[(void *) data_key] = debug_data;
} else {
debug_data = got->second;
}
return debug_data;
}
static struct debug_report_data *get_device_debug_data_ptr(
VkLayerDispatchTable *device_dispatch_ptr)
{
return get_debug_data_ptr((void *) device_dispatch_ptr);
}
static struct debug_report_data *get_instance_debug_data_ptr(
VkLayerInstanceDispatchTable *instance_dispatch_ptr)
{
return get_debug_data_ptr((void *) instance_dispatch_ptr);
}
static inline void debug_report_init_instance_extension_dispatch_table(
VkLayerInstanceDispatchTable *table,
PFN_vkGetInstanceProcAddr gpa,
VkInstance inst)
{
table->DbgCreateMsgCallback = (PFN_vkDbgCreateMsgCallback) gpa(inst, "vkDbgCreateMsgCallback");
table->DbgDestroyMsgCallback = (PFN_vkDbgDestroyMsgCallback) gpa(inst, "vkDbgDestroyMsgCallback");
}
// Utility function to handle reporting
static void debug_report_log_msg(
struct debug_report_data *debug_data,
VkFlags msgFlags,
VkObjectType objectType,
VkObject srcObject,
size_t location,
int32_t msgCode,
const char* pLayerPrefix,
const char* pMsg)
{
VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead;
while (pTrav) {
if (pTrav->msgFlags & msgFlags) {
pTrav->pfnMsgCallback(msgFlags,
objectType, srcObject,
location,
msgCode,
pLayerPrefix,
pMsg,
(void *) pTrav->pUserData);
}
pTrav = pTrav->pNext;
}
}
static inline void debug_report_create_instance(
VkLayerInstanceDispatchTable *instance_dispatch_ptr,
uint32_t extension_count,
const VkExtensionProperties* pEnabledExtensions) // layer or extension name to be enabled
{
struct debug_report_data *debug_data = get_debug_data_ptr(instance_dispatch_ptr);
for (uint32_t i = 0; i < extension_count; i++) {
/* TODO: Check other property fields */
if (strcmp(pEnabledExtensions[i].name, DEBUG_REPORT_EXTENSION_NAME) == 0) {
debug_data->g_DEBUG_REPORT = true;
}
}
}
static inline void layer_debug_report_destroy_instance(VkInstance instance)
{
VkLayerInstanceDispatchTable *instance_key = instance_dispatch_table(instance);
struct debug_report_data *debug_data =
get_debug_data_ptr(instance_dispatch_table(instance));
VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead;
VkLayerDbgFunctionNode *pTravNext;
/* Clear out any leftover callbacks */
while (pTrav) {
pTravNext = pTrav->pNext;
debug_report_log_msg(
debug_data, VK_DBG_REPORT_WARN_BIT,
VK_OBJECT_TYPE_INSTANCE, instance,
0, DEBUG_REPORT_CALLBACK_REF,
"DebugReport",
"Debug Report callbacks not removed before DestroyInstance");
free(pTrav);
pTrav = pTravNext;
}
debug_data->g_pDbgFunctionHead = NULL;
debug_report_data_map.erase((void *) instance_key);
tableInstanceMap.erase((void *) instance);
}
static inline void layer_debug_report_create_device(
VkLayerInstanceDispatchTable *instance_dispatch_ptr,
VkDevice device)
{
std::unordered_map<void *, struct debug_report_data *>::const_iterator got;
got = debug_report_data_map.find((void *) instance_dispatch_ptr);
if ( got == debug_report_data_map.end() ) {
// If we get here something is wrong
// We should always be able to find the instance key
assert(true);
} else {
VkLayerDispatchTable *device_key = device_dispatch_table(device);
debug_report_data_map[(void *) device_key ] = got->second;
}
}
static inline void layer_debug_report_destroy_device(VkDevice device)
{
VkLayerDispatchTable *device_key = device_dispatch_table(device);
debug_report_data_map.erase((void *) device_key);
tableMap.erase((void *) device);
}
static inline VkResult layer_create_msg_callback(
VkInstance instance,
VkLayerInstanceDispatchTable *nextTable,
VkFlags msgFlags,
const PFN_vkDbgMsgCallback pfnMsgCallback,
void *pUserData,
VkDbgMsgCallback *pMsgCallback)
{
VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode*)malloc(sizeof(VkLayerDbgFunctionNode));
if (!pNewDbgFuncNode)
return VK_ERROR_OUT_OF_HOST_MEMORY;
VkResult result = nextTable->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
if (result == VK_SUCCESS) {
struct debug_report_data *debug_data =
get_debug_data_ptr(instance_dispatch_table(instance));
pNewDbgFuncNode->msgCallback = *pMsgCallback;
pNewDbgFuncNode->pfnMsgCallback = pfnMsgCallback;
pNewDbgFuncNode->msgFlags = msgFlags;
pNewDbgFuncNode->pUserData = pUserData;
pNewDbgFuncNode->pNext = debug_data->g_pDbgFunctionHead;
debug_data->g_pDbgFunctionHead = pNewDbgFuncNode;
debug_report_log_msg(
debug_data, VK_DBG_REPORT_DEBUG_BIT,
VK_OBJECT_TYPE_INSTANCE, instance,
0, DEBUG_REPORT_CALLBACK_REF,
"DebugReport",
"Added callback");
} else {
free(pNewDbgFuncNode);
}
return result;
}
static VkResult layer_destroy_msg_callback(
VkInstance instance,
VkLayerInstanceDispatchTable *nextTable,
VkDbgMsgCallback msg_callback)
{
struct debug_report_data *debug_data =
get_debug_data_ptr(instance_dispatch_table(instance));
VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead;
VkLayerDbgFunctionNode *pPrev = pTrav;
VkResult result = nextTable->DbgDestroyMsgCallback(instance, msg_callback);
while (pTrav) {
if (pTrav->msgCallback == msg_callback) {
pPrev->pNext = pTrav->pNext;
if (debug_data->g_pDbgFunctionHead == pTrav) {
debug_data->g_pDbgFunctionHead = pTrav->pNext;
}
free(pTrav);
debug_report_log_msg(
debug_data, VK_DBG_REPORT_DEBUG_BIT,
VK_OBJECT_TYPE_INSTANCE, instance,
0, DEBUG_REPORT_CALLBACK_REF,
"DebugReport",
"Removed callback");
break;
}
pPrev = pTrav;
pTrav = pTrav->pNext;
}
return result;
}
static void* debug_report_get_instance_proc_addr(
VkInstance instance,
const char *funcName)
{
struct debug_report_data *debug_data =
get_debug_data_ptr(instance_dispatch_table(instance));
if (!debug_data->g_DEBUG_REPORT) {
return NULL;
}
if (!strcmp(funcName, "vkDbgCreateMsgCallback")) {
return (void *) vkDbgCreateMsgCallback;
}
if (!strcmp(funcName, "vkDbgDestroyMsgCallback")) {
return (void *) vkDbgDestroyMsgCallback;
}
return NULL;
}
/*
* Devices, Queue, SwapChain and Command buffers all
* use the same device dispatch table.
*/
static void device_log_msg(
VkObject object,
VkFlags msgFlags,
VkObjectType objectType,
VkObject srcObject,
size_t location,
int32_t msgCode,
const char* pLayerPrefix,
const char* pMsg)
{
struct debug_report_data *debug_data;
debug_data = get_device_debug_data_ptr(device_dispatch_table(object));
debug_report_log_msg(debug_data, msgFlags, objectType,
srcObject, location, msgCode,
pLayerPrefix, pMsg);
}
static void instance_log_msg(
VkInstance instance,
VkFlags msgFlags,
VkObjectType objectType,
VkObject srcObject,
size_t location,
int32_t msgCode,
const char* pLayerPrefix,
const char* pMsg)
{
struct debug_report_data *debug_data;
debug_data = get_instance_debug_data_ptr(instance_dispatch_table(instance));
debug_report_log_msg(debug_data, msgFlags, objectType,
srcObject, location, msgCode,
pLayerPrefix, pMsg);
}
#endif // LAYER_LOGGING_H