Home | History | Annotate | Download | only in layers
      1 /* Copyright (c) 2015-2016 The Khronos Group Inc.
      2  * Copyright (c) 2015-2016 Valve Corporation
      3  * Copyright (c) 2015-2016 LunarG, Inc.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a copy
      6  * of this software and/or associated documentation files (the "Materials"), to
      7  * deal in the Materials without restriction, including without limitation the
      8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
      9  * sell copies of the Materials, and to permit persons to whom the Materials
     10  * are furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice(s) and this permission notice shall be included
     13  * in all copies or substantial portions of the Materials.
     14  *
     15  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     18  *
     19  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
     20  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     21  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
     22  * USE OR OTHER DEALINGS IN THE MATERIALS
     23  *
     24  * Author: Courtney Goeltzenleuchter <courtney (at) LunarG.com>
     25  * Author: Tobin Ehlis <tobin (at) lunarg.com>
     26  *
     27  */
     28 
     29 #ifndef LAYER_LOGGING_H
     30 #define LAYER_LOGGING_H
     31 
     32 #include <stdio.h>
     33 #include <stdarg.h>
     34 #include <stdbool.h>
     35 #include <unordered_map>
     36 #include <inttypes.h>
     37 #include "vk_loader_platform.h"
     38 #include "vulkan/vk_layer.h"
     39 #include "vk_layer_data.h"
     40 #include "vk_layer_table.h"
     41 
     42 typedef struct _debug_report_data {
     43     VkLayerDbgFunctionNode *g_pDbgFunctionHead;
     44     VkFlags active_flags;
     45     bool g_DEBUG_REPORT;
     46 } debug_report_data;
     47 
     48 template debug_report_data *get_my_data_ptr<debug_report_data>(void *data_key,
     49                                                                std::unordered_map<void *, debug_report_data *> &data_map);
     50 
     51 // Utility function to handle reporting
     52 static inline VkBool32 debug_report_log_msg(debug_report_data *debug_data, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType,
     53                                             uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix,
     54                                             const char *pMsg) {
     55     VkBool32 bail = false;
     56     VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead;
     57     while (pTrav) {
     58         if (pTrav->msgFlags & msgFlags) {
     59             if (pTrav->pfnMsgCallback(msgFlags, objectType, srcObject, location, msgCode, pLayerPrefix, pMsg, pTrav->pUserData)) {
     60                 bail = true;
     61             }
     62         }
     63         pTrav = pTrav->pNext;
     64     }
     65 
     66     return bail;
     67 }
     68 
     69 static inline debug_report_data *
     70 debug_report_create_instance(VkLayerInstanceDispatchTable *table, VkInstance inst, uint32_t extension_count,
     71                              const char *const *ppEnabledExtensions) // layer or extension name to be enabled
     72 {
     73     debug_report_data *debug_data;
     74     PFN_vkGetInstanceProcAddr gpa = table->GetInstanceProcAddr;
     75 
     76     table->CreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)gpa(inst, "vkCreateDebugReportCallbackEXT");
     77     table->DestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)gpa(inst, "vkDestroyDebugReportCallbackEXT");
     78     table->DebugReportMessageEXT = (PFN_vkDebugReportMessageEXT)gpa(inst, "vkDebugReportMessageEXT");
     79 
     80     debug_data = (debug_report_data *)malloc(sizeof(debug_report_data));
     81     if (!debug_data)
     82         return NULL;
     83 
     84     memset(debug_data, 0, sizeof(debug_report_data));
     85     for (uint32_t i = 0; i < extension_count; i++) {
     86         /* TODO: Check other property fields */
     87         if (strcmp(ppEnabledExtensions[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
     88             debug_data->g_DEBUG_REPORT = true;
     89         }
     90     }
     91     return debug_data;
     92 }
     93 
     94 static inline void layer_debug_report_destroy_instance(debug_report_data *debug_data) {
     95     VkLayerDbgFunctionNode *pTrav;
     96     VkLayerDbgFunctionNode *pTravNext;
     97 
     98     if (!debug_data) {
     99         return;
    100     }
    101 
    102     pTrav = debug_data->g_pDbgFunctionHead;
    103     /* Clear out any leftover callbacks */
    104     while (pTrav) {
    105         pTravNext = pTrav->pNext;
    106 
    107         debug_report_log_msg(debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
    108                              (uint64_t)pTrav->msgCallback, 0, VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT, "DebugReport",
    109                              "Debug Report callbacks not removed before DestroyInstance");
    110 
    111         free(pTrav);
    112         pTrav = pTravNext;
    113     }
    114     debug_data->g_pDbgFunctionHead = NULL;
    115 
    116     free(debug_data);
    117 }
    118 
    119 static inline debug_report_data *layer_debug_report_create_device(debug_report_data *instance_debug_data, VkDevice device) {
    120     /* DEBUG_REPORT shares data between Instance and Device,
    121      * so just return instance's data pointer */
    122     return instance_debug_data;
    123 }
    124 
    125 static inline void layer_debug_report_destroy_device(VkDevice device) { /* Nothing to do since we're using instance data record */ }
    126 
    127 static inline VkResult layer_create_msg_callback(debug_report_data *debug_data,
    128                                                  const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
    129                                                  const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback) {
    130     /* TODO: Use app allocator */
    131     VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode));
    132     if (!pNewDbgFuncNode)
    133         return VK_ERROR_OUT_OF_HOST_MEMORY;
    134 
    135     // Handle of 0 is logging_callback so use allocated Node address as unique handle
    136     if (!(*pCallback))
    137         *pCallback = (VkDebugReportCallbackEXT)pNewDbgFuncNode;
    138     pNewDbgFuncNode->msgCallback = *pCallback;
    139     pNewDbgFuncNode->pfnMsgCallback = pCreateInfo->pfnCallback;
    140     pNewDbgFuncNode->msgFlags = pCreateInfo->flags;
    141     pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
    142     pNewDbgFuncNode->pNext = debug_data->g_pDbgFunctionHead;
    143 
    144     debug_data->g_pDbgFunctionHead = pNewDbgFuncNode;
    145     debug_data->active_flags |= pCreateInfo->flags;
    146 
    147     debug_report_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
    148                          (uint64_t)*pCallback, 0, VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT, "DebugReport", "Added callback");
    149     return VK_SUCCESS;
    150 }
    151 
    152 static inline void layer_destroy_msg_callback(debug_report_data *debug_data, VkDebugReportCallbackEXT callback,
    153                                               const VkAllocationCallbacks *pAllocator) {
    154     VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead;
    155     VkLayerDbgFunctionNode *pPrev = pTrav;
    156     bool matched;
    157 
    158     debug_data->active_flags = 0;
    159     while (pTrav) {
    160         if (pTrav->msgCallback == callback) {
    161             matched = true;
    162             pPrev->pNext = pTrav->pNext;
    163             if (debug_data->g_pDbgFunctionHead == pTrav) {
    164                 debug_data->g_pDbgFunctionHead = pTrav->pNext;
    165             }
    166             debug_report_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
    167                                  (uint64_t)pTrav->msgCallback, 0, VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT, "DebugReport",
    168                                  "Destroyed callback");
    169         } else {
    170             matched = false;
    171             debug_data->active_flags |= pTrav->msgFlags;
    172         }
    173         pPrev = pTrav;
    174         pTrav = pTrav->pNext;
    175         if (matched) {
    176             /* TODO: Use pAllocator */
    177             free(pPrev);
    178         }
    179     }
    180 }
    181 
    182 static inline PFN_vkVoidFunction debug_report_get_instance_proc_addr(debug_report_data *debug_data, const char *funcName) {
    183     if (!debug_data || !debug_data->g_DEBUG_REPORT) {
    184         return NULL;
    185     }
    186 
    187     if (!strcmp(funcName, "vkCreateDebugReportCallbackEXT")) {
    188         return (PFN_vkVoidFunction)vkCreateDebugReportCallbackEXT;
    189     }
    190     if (!strcmp(funcName, "vkDestroyDebugReportCallbackEXT")) {
    191         return (PFN_vkVoidFunction)vkDestroyDebugReportCallbackEXT;
    192     }
    193 
    194     if (!strcmp(funcName, "vkDebugReportMessageEXT")) {
    195         return (PFN_vkVoidFunction)vkDebugReportMessageEXT;
    196     }
    197 
    198     return NULL;
    199 }
    200 
    201 /*
    202  * Checks if the message will get logged.
    203  * Allows layer to defer collecting & formating data if the
    204  * message will be discarded.
    205  */
    206 static inline VkBool32 will_log_msg(debug_report_data *debug_data, VkFlags msgFlags) {
    207     if (!debug_data || !(debug_data->active_flags & msgFlags)) {
    208         /* message is not wanted */
    209         return false;
    210     }
    211 
    212     return true;
    213 }
    214 
    215 /*
    216  * Output log message via DEBUG_REPORT
    217  * Takes format and variable arg list so that output string
    218  * is only computed if a message needs to be logged
    219  */
    220 #ifndef WIN32
    221 static inline VkBool32 log_msg(debug_report_data *debug_data, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType,
    222                                uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *format,
    223                                ...) __attribute__((format(printf, 8, 9)));
    224 #endif
    225 static inline VkBool32 log_msg(debug_report_data *debug_data, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType,
    226                                uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *format,
    227                                ...) {
    228     if (!debug_data || !(debug_data->active_flags & msgFlags)) {
    229         /* message is not wanted */
    230         return false;
    231     }
    232 
    233     char str[1024];
    234     va_list argptr;
    235     va_start(argptr, format);
    236     vsnprintf(str, 1024, format, argptr);
    237     va_end(argptr);
    238     return debug_report_log_msg(debug_data, msgFlags, objectType, srcObject, location, msgCode, pLayerPrefix, str);
    239 }
    240 
    241 static inline VKAPI_ATTR VkBool32 VKAPI_CALL log_callback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject,
    242                                                           size_t location, int32_t msgCode, const char *pLayerPrefix,
    243                                                           const char *pMsg, void *pUserData) {
    244     char msg_flags[30];
    245 
    246     print_msg_flags(msgFlags, msg_flags);
    247 
    248     fprintf((FILE *)pUserData, "%s(%s): object: %#" PRIx64 " type: %d location: %lu msgCode: %d: %s\n", pLayerPrefix, msg_flags,
    249             srcObject, objType, (unsigned long)location, msgCode, pMsg);
    250     fflush((FILE *)pUserData);
    251 
    252     return false;
    253 }
    254 
    255 static inline VKAPI_ATTR VkBool32 VKAPI_CALL win32_debug_output_msg(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
    256                                                                     uint64_t srcObject, size_t location, int32_t msgCode,
    257                                                                     const char *pLayerPrefix, const char *pMsg, void *pUserData) {
    258 #ifdef WIN32
    259     char msg_flags[30];
    260     char buf[2048];
    261 
    262     print_msg_flags(msgFlags, msg_flags);
    263     _snprintf(buf, sizeof(buf) - 1,
    264               "%s (%s): object: 0x%" PRIxPTR " type: %d location: " PRINTF_SIZE_T_SPECIFIER " msgCode: %d: %s\n", pLayerPrefix,
    265               msg_flags, (size_t)srcObject, objType, location, msgCode, pMsg);
    266 
    267     OutputDebugString(buf);
    268 #endif
    269 
    270     return false;
    271 }
    272 
    273 #endif // LAYER_LOGGING_H
    274