Home | History | Annotate | Download | only in loader
      1 /*
      2  * Copyright (c) 2015-2016 The Khronos Group Inc.
      3  * Copyright (c) 2015-2016 Valve Corporation
      4  * Copyright (c) 2015-2016 LunarG, Inc.
      5  * Copyright (C) 2015-2016 Google Inc.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a copy
      8  * of this software and/or associated documentation files (the "Materials"), to
      9  * deal in the Materials without restriction, including without limitation the
     10  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
     11  * sell copies of the Materials, and to permit persons to whom the Materials are
     12  * furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice(s) and this permission notice shall be included in
     15  * all copies or substantial portions of the Materials.
     16  *
     17  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     20  *
     21  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
     22  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     23  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
     24  * USE OR OTHER DEALINGS IN THE MATERIALS.
     25  *
     26  * Author: Courtney Goeltzenleuchter <courtney (at) LunarG.com>
     27  * Author: Jon Ashburn <jon (at) LunarG.com>
     28  *
     29  */
     30 
     31 #define _GNU_SOURCE
     32 #include <stdio.h>
     33 #include <string.h>
     34 #include <stdlib.h>
     35 #include <inttypes.h>
     36 #ifndef WIN32
     37 #include <signal.h>
     38 #else
     39 #endif
     40 #include "vk_loader_platform.h"
     41 #include "debug_report.h"
     42 #include "vulkan/vk_layer.h"
     43 
     44 typedef void(VKAPI_PTR *PFN_stringCallback)(char *message);
     45 
     46 static const VkExtensionProperties debug_report_extension_info = {
     47     .extensionName = VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
     48     .specVersion = VK_EXT_DEBUG_REPORT_SPEC_VERSION,
     49 };
     50 
     51 void debug_report_add_instance_extensions(
     52     const struct loader_instance *inst,
     53     struct loader_extension_list *ext_list) {
     54     loader_add_to_ext_list(inst, ext_list, 1, &debug_report_extension_info);
     55 }
     56 
     57 void debug_report_create_instance(struct loader_instance *ptr_instance,
     58                                   const VkInstanceCreateInfo *pCreateInfo) {
     59     ptr_instance->debug_report_enabled = false;
     60 
     61     for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
     62         if (strcmp(pCreateInfo->ppEnabledExtensionNames[i],
     63                    VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
     64             ptr_instance->debug_report_enabled = true;
     65             return;
     66         }
     67     }
     68 }
     69 
     70 VkResult
     71 util_CreateDebugReportCallback(struct loader_instance *inst,
     72                                VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
     73                                const VkAllocationCallbacks *pAllocator,
     74                                VkDebugReportCallbackEXT callback) {
     75     VkLayerDbgFunctionNode *pNewDbgFuncNode;
     76     if (pAllocator != NULL) {
     77         pNewDbgFuncNode = (VkLayerDbgFunctionNode *)pAllocator->pfnAllocation(
     78             pAllocator->pUserData, sizeof(VkLayerDbgFunctionNode),
     79             sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
     80     } else {
     81         pNewDbgFuncNode = (VkLayerDbgFunctionNode *)loader_heap_alloc(
     82             inst, sizeof(VkLayerDbgFunctionNode),
     83             VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
     84     }
     85     if (!pNewDbgFuncNode)
     86         return VK_ERROR_OUT_OF_HOST_MEMORY;
     87 
     88     pNewDbgFuncNode->msgCallback = callback;
     89     pNewDbgFuncNode->pfnMsgCallback = pCreateInfo->pfnCallback;
     90     pNewDbgFuncNode->msgFlags = pCreateInfo->flags;
     91     pNewDbgFuncNode->pUserData = pCreateInfo->pUserData;
     92     pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
     93     inst->DbgFunctionHead = pNewDbgFuncNode;
     94 
     95     return VK_SUCCESS;
     96 }
     97 
     98 static VKAPI_ATTR VkResult VKAPI_CALL debug_report_CreateDebugReportCallback(
     99     VkInstance instance, VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
    100     VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback) {
    101     struct loader_instance *inst = loader_get_instance(instance);
    102     loader_platform_thread_lock_mutex(&loader_lock);
    103     VkResult result = inst->disp->CreateDebugReportCallbackEXT(
    104         instance, pCreateInfo, pAllocator, pCallback);
    105     if (result == VK_SUCCESS) {
    106         result = util_CreateDebugReportCallback(inst, pCreateInfo, pAllocator,
    107                                                 *pCallback);
    108     }
    109     loader_platform_thread_unlock_mutex(&loader_lock);
    110     return result;
    111 }
    112 
    113 // Utility function to handle reporting
    114 VkBool32 util_DebugReportMessage(const struct loader_instance *inst,
    115                                  VkFlags msgFlags,
    116                                  VkDebugReportObjectTypeEXT objectType,
    117                                  uint64_t srcObject, size_t location,
    118                                  int32_t msgCode, const char *pLayerPrefix,
    119                                  const char *pMsg) {
    120     VkBool32 bail = false;
    121     VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
    122     while (pTrav) {
    123         if (pTrav->msgFlags & msgFlags) {
    124             if (pTrav->pfnMsgCallback(msgFlags, objectType, srcObject, location,
    125                                       msgCode, pLayerPrefix, pMsg,
    126                                       pTrav->pUserData)) {
    127                 bail = true;
    128             }
    129         }
    130         pTrav = pTrav->pNext;
    131     }
    132 
    133     return bail;
    134 }
    135 
    136 void util_DestroyDebugReportCallback(struct loader_instance *inst,
    137                                      VkDebugReportCallbackEXT callback,
    138                                      const VkAllocationCallbacks *pAllocator) {
    139     VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
    140     VkLayerDbgFunctionNode *pPrev = pTrav;
    141 
    142     while (pTrav) {
    143         if (pTrav->msgCallback == callback) {
    144             pPrev->pNext = pTrav->pNext;
    145             if (inst->DbgFunctionHead == pTrav)
    146                 inst->DbgFunctionHead = pTrav->pNext;
    147             if (pAllocator != NULL) {
    148                 pAllocator->pfnFree(pAllocator->pUserData, pTrav);
    149             } else {
    150                 loader_heap_free(inst, pTrav);
    151             }
    152             break;
    153         }
    154         pPrev = pTrav;
    155         pTrav = pTrav->pNext;
    156     }
    157 }
    158 
    159 static VKAPI_ATTR void VKAPI_CALL
    160 debug_report_DestroyDebugReportCallback(VkInstance instance,
    161                                         VkDebugReportCallbackEXT callback,
    162                                         VkAllocationCallbacks *pAllocator) {
    163     struct loader_instance *inst = loader_get_instance(instance);
    164     loader_platform_thread_lock_mutex(&loader_lock);
    165 
    166     inst->disp->DestroyDebugReportCallbackEXT(instance, callback, pAllocator);
    167 
    168     util_DestroyDebugReportCallback(inst, callback, pAllocator);
    169 
    170     loader_platform_thread_unlock_mutex(&loader_lock);
    171 }
    172 
    173 static VKAPI_ATTR void VKAPI_CALL debug_report_DebugReportMessage(
    174     VkInstance instance, VkDebugReportFlagsEXT flags,
    175     VkDebugReportObjectTypeEXT objType, uint64_t object, size_t location,
    176     int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
    177     struct loader_instance *inst = loader_get_instance(instance);
    178 
    179     inst->disp->DebugReportMessageEXT(instance, flags, objType, object,
    180                                       location, msgCode, pLayerPrefix, pMsg);
    181 }
    182 
    183 /*
    184  * This is the instance chain terminator function
    185  * for CreateDebugReportCallback
    186  */
    187 
    188 VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDebugReportCallback(
    189     VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
    190     const VkAllocationCallbacks *pAllocator,
    191     VkDebugReportCallbackEXT *pCallback) {
    192     VkDebugReportCallbackEXT *icd_info;
    193     const struct loader_icd *icd;
    194     struct loader_instance *inst = (struct loader_instance *)instance;
    195     VkResult res = VK_SUCCESS;
    196     uint32_t storage_idx;
    197 
    198     icd_info = calloc(sizeof(VkDebugReportCallbackEXT), inst->total_icd_count);
    199     if (!icd_info) {
    200         return VK_ERROR_OUT_OF_HOST_MEMORY;
    201     }
    202 
    203     storage_idx = 0;
    204     for (icd = inst->icds; icd; icd = icd->next) {
    205         if (!icd->CreateDebugReportCallbackEXT) {
    206             continue;
    207         }
    208 
    209         res = icd->CreateDebugReportCallbackEXT(
    210             icd->instance, pCreateInfo, pAllocator, &icd_info[storage_idx]);
    211 
    212         if (res != VK_SUCCESS) {
    213             break;
    214         }
    215         storage_idx++;
    216     }
    217 
    218     /* roll back on errors */
    219     if (icd) {
    220         storage_idx = 0;
    221         for (icd = inst->icds; icd; icd = icd->next) {
    222             if (icd_info[storage_idx]) {
    223                 icd->DestroyDebugReportCallbackEXT(
    224                     icd->instance, icd_info[storage_idx], pAllocator);
    225             }
    226             storage_idx++;
    227         }
    228 
    229         return res;
    230     }
    231 
    232     *(VkDebugReportCallbackEXT **)pCallback = icd_info;
    233 
    234     return VK_SUCCESS;
    235 }
    236 
    237 /*
    238  * This is the instance chain terminator function
    239  * for DestroyDebugReportCallback
    240  */
    241 VKAPI_ATTR void VKAPI_CALL
    242 terminator_DestroyDebugReportCallback(VkInstance instance,
    243                                       VkDebugReportCallbackEXT callback,
    244                                       const VkAllocationCallbacks *pAllocator) {
    245     uint32_t storage_idx;
    246     VkDebugReportCallbackEXT *icd_info;
    247     const struct loader_icd *icd;
    248 
    249     struct loader_instance *inst = (struct loader_instance *)instance;
    250     icd_info = *(VkDebugReportCallbackEXT **)&callback;
    251     storage_idx = 0;
    252     for (icd = inst->icds; icd; icd = icd->next) {
    253         if (icd_info[storage_idx]) {
    254             icd->DestroyDebugReportCallbackEXT(
    255                 icd->instance, icd_info[storage_idx], pAllocator);
    256         }
    257         storage_idx++;
    258     }
    259 }
    260 
    261 /*
    262  * This is the instance chain terminator function
    263  * for DebugReportMessage
    264  */
    265 VKAPI_ATTR void VKAPI_CALL
    266 terminator_DebugReportMessage(VkInstance instance, VkDebugReportFlagsEXT flags,
    267                               VkDebugReportObjectTypeEXT objType,
    268                               uint64_t object, size_t location, int32_t msgCode,
    269                               const char *pLayerPrefix, const char *pMsg) {
    270     const struct loader_icd *icd;
    271 
    272     struct loader_instance *inst = (struct loader_instance *)instance;
    273 
    274     loader_platform_thread_lock_mutex(&loader_lock);
    275     for (icd = inst->icds; icd; icd = icd->next) {
    276         if (icd->DebugReportMessageEXT != NULL) {
    277             icd->DebugReportMessageEXT(icd->instance, flags, objType, object,
    278                                        location, msgCode, pLayerPrefix, pMsg);
    279         }
    280     }
    281 
    282     /*
    283      * Now that all ICDs have seen the message, call the necessary callbacks.
    284      * Ignoring "bail" return value as there is nothing to bail from at this
    285      * point.
    286      */
    287 
    288     util_DebugReportMessage(inst, flags, objType, object, location, msgCode,
    289                             pLayerPrefix, pMsg);
    290 
    291     loader_platform_thread_unlock_mutex(&loader_lock);
    292 }
    293 
    294 bool debug_report_instance_gpa(struct loader_instance *ptr_instance,
    295                                const char *name, void **addr) {
    296     // debug_report is currently advertised to be supported by the loader,
    297     // so always return the entry points if name matches and it's enabled
    298     *addr = NULL;
    299 
    300     if (!strcmp("vkCreateDebugReportCallbackEXT", name)) {
    301         *addr = ptr_instance->debug_report_enabled
    302                     ? (void *)debug_report_CreateDebugReportCallback
    303                     : NULL;
    304         return true;
    305     }
    306     if (!strcmp("vkDestroyDebugReportCallbackEXT", name)) {
    307         *addr = ptr_instance->debug_report_enabled
    308                     ? (void *)debug_report_DestroyDebugReportCallback
    309                     : NULL;
    310         return true;
    311     }
    312     if (!strcmp("vkDebugReportMessageEXT", name)) {
    313         *addr = ptr_instance->debug_report_enabled
    314                     ? (void *)debug_report_DebugReportMessage
    315                     : NULL;
    316         return true;
    317     }
    318     return false;
    319 }
    320