111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* Copyright (c) 2015-2016 The Khronos Group Inc. 211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Copyright (c) 2015-2016 Valve Corporation 311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Copyright (c) 2015-2016 LunarG, Inc. 411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Licensed under the Apache License, Version 2.0 (the "License"); 611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * you may not use this file except in compliance with the License. 711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * You may obtain a copy of the License at 811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * http://www.apache.org/licenses/LICENSE-2.0 1011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 1111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Unless required by applicable law or agreed to in writing, software 1211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * distributed under the License is distributed on an "AS IS" BASIS, 1311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * See the License for the specific language governing permissions and 1511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * limitations under the License. 1611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 1711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> 1811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Author: Tobin Ehlis <tobin@lunarg.com> 1911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 2011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 2111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 2211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#ifndef LAYER_LOGGING_H 2311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define LAYER_LOGGING_H 2411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 2511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include "vk_layer_config.h" 2611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include "vk_layer_data.h" 2711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include "vk_layer_table.h" 2811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include "vk_loader_platform.h" 2911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include "vulkan/vk_layer.h" 3011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <cinttypes> 3111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <stdarg.h> 3211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <stdbool.h> 3311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <stdio.h> 3411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <unordered_map> 3511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 3611cd02dfb91661c65134cac258cf5924270e9d2Dan Alberttypedef struct _debug_report_data { 3711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert VkLayerDbgFunctionNode *g_pDbgFunctionHead; 3811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert VkFlags active_flags; 3911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert bool g_DEBUG_REPORT; 4011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} debug_report_data; 4111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 4211cd02dfb91661c65134cac258cf5924270e9d2Dan Alberttemplate debug_report_data *get_my_data_ptr<debug_report_data>(void *data_key, 4311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert std::unordered_map<void *, debug_report_data *> &data_map); 4411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 4511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Utility function to handle reporting 4611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic inline bool debug_report_log_msg(const debug_report_data *debug_data, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType, 4711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, 4811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const char *pMsg) { 4911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert bool bail = false; 5011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead; 5111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert while (pTrav) { 5211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (pTrav->msgFlags & msgFlags) { 5311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (pTrav->pfnMsgCallback(msgFlags, objectType, srcObject, location, msgCode, pLayerPrefix, pMsg, pTrav->pUserData)) { 5411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert bail = true; 5511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 5611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 5711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pTrav = pTrav->pNext; 5811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 5911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 6011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return bail; 6111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 6211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 6311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic inline debug_report_data * 6411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertdebug_report_create_instance(VkLayerInstanceDispatchTable *table, VkInstance inst, uint32_t extension_count, 6511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const char *const *ppEnabledExtensions) // layer or extension name to be enabled 6611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 6711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert debug_report_data *debug_data; 6811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert PFN_vkGetInstanceProcAddr gpa = table->GetInstanceProcAddr; 6911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 7011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert table->CreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)gpa(inst, "vkCreateDebugReportCallbackEXT"); 7111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert table->DestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)gpa(inst, "vkDestroyDebugReportCallbackEXT"); 7211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert table->DebugReportMessageEXT = (PFN_vkDebugReportMessageEXT)gpa(inst, "vkDebugReportMessageEXT"); 7311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 7411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert debug_data = (debug_report_data *)malloc(sizeof(debug_report_data)); 7511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!debug_data) 7611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return NULL; 7711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 7811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert memset(debug_data, 0, sizeof(debug_report_data)); 7911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert for (uint32_t i = 0; i < extension_count; i++) { 8011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* TODO: Check other property fields */ 8111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (strcmp(ppEnabledExtensions[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) { 8211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert debug_data->g_DEBUG_REPORT = true; 8311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 8411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 8511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return debug_data; 8611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 8711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 8811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic inline void layer_debug_report_destroy_instance(debug_report_data *debug_data) { 8911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert VkLayerDbgFunctionNode *pTrav; 9011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert VkLayerDbgFunctionNode *pTravNext; 9111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 9211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!debug_data) { 9311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return; 9411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 9511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 9611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pTrav = debug_data->g_pDbgFunctionHead; 9711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Clear out any leftover callbacks */ 9811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert while (pTrav) { 9911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pTravNext = pTrav->pNext; 10011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 10111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert debug_report_log_msg(debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, 10211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert (uint64_t)pTrav->msgCallback, 0, VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT, "DebugReport", 10311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert "Debug Report callbacks not removed before DestroyInstance"); 10411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 10511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert free(pTrav); 10611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pTrav = pTravNext; 10711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 10811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert debug_data->g_pDbgFunctionHead = NULL; 10911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 11011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert free(debug_data); 11111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 11211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 11311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic inline debug_report_data *layer_debug_report_create_device(debug_report_data *instance_debug_data, VkDevice device) { 11411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* DEBUG_REPORT shares data between Instance and Device, 11511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * so just return instance's data pointer */ 11611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return instance_debug_data; 11711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 11811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 11911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic inline void layer_debug_report_destroy_device(VkDevice device) { /* Nothing to do since we're using instance data record */ } 12011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 12111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic inline VkResult layer_create_msg_callback(debug_report_data *debug_data, 12211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, 12311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback) { 12411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* TODO: Use app allocator */ 12511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *)malloc(sizeof(VkLayerDbgFunctionNode)); 12611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!pNewDbgFuncNode) 12711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return VK_ERROR_OUT_OF_HOST_MEMORY; 12811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 12911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // Handle of 0 is logging_callback so use allocated Node address as unique handle 13011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!(*pCallback)) 13111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert *pCallback = (VkDebugReportCallbackEXT)pNewDbgFuncNode; 13211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pNewDbgFuncNode->msgCallback = *pCallback; 13311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pNewDbgFuncNode->pfnMsgCallback = pCreateInfo->pfnCallback; 13411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pNewDbgFuncNode->msgFlags = pCreateInfo->flags; 13511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pNewDbgFuncNode->pUserData = pCreateInfo->pUserData; 13611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pNewDbgFuncNode->pNext = debug_data->g_pDbgFunctionHead; 13711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 13811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert debug_data->g_pDbgFunctionHead = pNewDbgFuncNode; 13911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert debug_data->active_flags |= pCreateInfo->flags; 14011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 14111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert debug_report_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, 14211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert (uint64_t)*pCallback, 0, VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT, "DebugReport", "Added callback"); 14311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return VK_SUCCESS; 14411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 14511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 14611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic inline void layer_destroy_msg_callback(debug_report_data *debug_data, VkDebugReportCallbackEXT callback, 14711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const VkAllocationCallbacks *pAllocator) { 14811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead; 14911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert VkLayerDbgFunctionNode *pPrev = pTrav; 15011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert bool matched; 15111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 15211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert debug_data->active_flags = 0; 15311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert while (pTrav) { 15411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (pTrav->msgCallback == callback) { 15511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert matched = true; 15611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pPrev->pNext = pTrav->pNext; 15711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (debug_data->g_pDbgFunctionHead == pTrav) { 15811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert debug_data->g_pDbgFunctionHead = pTrav->pNext; 15911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 16011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert debug_report_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, 16111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert (uint64_t)pTrav->msgCallback, 0, VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT, "DebugReport", 16211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert "Destroyed callback"); 16311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } else { 16411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert matched = false; 16511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert debug_data->active_flags |= pTrav->msgFlags; 16611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 16711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pPrev = pTrav; 16811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pTrav = pTrav->pNext; 16911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (matched) { 17011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* TODO: Use pAllocator */ 17111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert free(pPrev); 17211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 17311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 17411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 17511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 17611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic inline PFN_vkVoidFunction debug_report_get_instance_proc_addr(debug_report_data *debug_data, const char *funcName) { 17711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!debug_data || !debug_data->g_DEBUG_REPORT) { 17811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return NULL; 17911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 18011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 18111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!strcmp(funcName, "vkCreateDebugReportCallbackEXT")) { 18211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return (PFN_vkVoidFunction)vkCreateDebugReportCallbackEXT; 18311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 18411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!strcmp(funcName, "vkDestroyDebugReportCallbackEXT")) { 18511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return (PFN_vkVoidFunction)vkDestroyDebugReportCallbackEXT; 18611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 18711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 18811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!strcmp(funcName, "vkDebugReportMessageEXT")) { 18911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return (PFN_vkVoidFunction)vkDebugReportMessageEXT; 19011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 19111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 19211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return NULL; 19311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 19411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 19511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// This utility (called at vkCreateInstance() time), looks at a pNext chain. 19611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// It counts any VkDebugReportCallbackCreateInfoEXT structs that it finds. It 19711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// then allocates an array that can hold that many structs, as well as that 19811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// many VkDebugReportCallbackEXT handles. It then copies each 19911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// VkDebugReportCallbackCreateInfoEXT, and initializes each handle. 20011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic VkResult layer_copy_tmp_callbacks(const void *pChain, uint32_t *num_callbacks, VkDebugReportCallbackCreateInfoEXT **infos, 20111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert VkDebugReportCallbackEXT **callbacks) { 20211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert uint32_t n = *num_callbacks = 0; 20311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 20411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const void *pNext = pChain; 20511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert while (pNext) { 20611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // 1st, count the number VkDebugReportCallbackCreateInfoEXT: 20711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (((VkDebugReportCallbackCreateInfoEXT *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) { 20811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert n++; 20911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 21011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pNext = (void *)((VkDebugReportCallbackCreateInfoEXT *)pNext)->pNext; 21111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 21211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (n == 0) { 21311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return VK_SUCCESS; 21411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 21511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 21611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // 2nd, allocate memory for each VkDebugReportCallbackCreateInfoEXT: 21711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert VkDebugReportCallbackCreateInfoEXT *pInfos = *infos = 21811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert ((VkDebugReportCallbackCreateInfoEXT *)malloc(n * sizeof(VkDebugReportCallbackCreateInfoEXT))); 21911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!pInfos) { 22011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return VK_ERROR_OUT_OF_HOST_MEMORY; 22111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 22211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // 3rd, allocate memory for a unique handle for each callback: 22311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert VkDebugReportCallbackEXT *pCallbacks = *callbacks = ((VkDebugReportCallbackEXT *)malloc(n * sizeof(VkDebugReportCallbackEXT))); 22411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!pCallbacks) { 22511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert free(pInfos); 22611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return VK_ERROR_OUT_OF_HOST_MEMORY; 22711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 22811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // 4th, copy each VkDebugReportCallbackCreateInfoEXT for use by 22911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // vkDestroyInstance, and assign a unique handle to each callback (just 23011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // use the address of the copied VkDebugReportCallbackCreateInfoEXT): 23111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pNext = pChain; 23211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert while (pNext) { 23311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (((VkInstanceCreateInfo *)pNext)->sType == VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT) { 23411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert memcpy(pInfos, pNext, sizeof(VkDebugReportCallbackCreateInfoEXT)); 23511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert *pCallbacks++ = (VkDebugReportCallbackEXT)pInfos++; 23611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 23711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pNext = (void *)((VkInstanceCreateInfo *)pNext)->pNext; 23811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 23911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 24011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert *num_callbacks = n; 24111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return VK_SUCCESS; 24211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 24311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 24411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// This utility frees the arrays allocated by layer_copy_tmp_callbacks() 24511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void layer_free_tmp_callbacks(VkDebugReportCallbackCreateInfoEXT *infos, VkDebugReportCallbackEXT *callbacks) { 24611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert free(infos); 24711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert free(callbacks); 24811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 24911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 25011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// This utility enables all of the VkDebugReportCallbackCreateInfoEXT structs 25111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// that were copied by layer_copy_tmp_callbacks() 25211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic VkResult layer_enable_tmp_callbacks(debug_report_data *debug_data, uint32_t num_callbacks, 25311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert VkDebugReportCallbackCreateInfoEXT *infos, VkDebugReportCallbackEXT *callbacks) { 25411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert VkResult rtn = VK_SUCCESS; 25511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert for (uint32_t i = 0; i < num_callbacks; i++) { 25611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert rtn = layer_create_msg_callback(debug_data, &infos[i], NULL, &callbacks[i]); 25711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (rtn != VK_SUCCESS) { 25811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert for (uint32_t j = 0; j < i; j++) { 25911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert layer_destroy_msg_callback(debug_data, callbacks[j], NULL); 26011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 26111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return rtn; 26211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 26311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 26411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return rtn; 26511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 26611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 26711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// This utility disables all of the VkDebugReportCallbackCreateInfoEXT structs 26811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// that were copied by layer_copy_tmp_callbacks() 26911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void layer_disable_tmp_callbacks(debug_report_data *debug_data, uint32_t num_callbacks, 27011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert VkDebugReportCallbackEXT *callbacks) { 27111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert for (uint32_t i = 0; i < num_callbacks; i++) { 27211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert layer_destroy_msg_callback(debug_data, callbacks[i], NULL); 27311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 27411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 27511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 27611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* 27711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Checks if the message will get logged. 27811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Allows layer to defer collecting & formating data if the 27911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * message will be discarded. 28011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 28111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic inline bool will_log_msg(debug_report_data *debug_data, VkFlags msgFlags) { 28211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!debug_data || !(debug_data->active_flags & msgFlags)) { 28311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* message is not wanted */ 28411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return false; 28511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 28611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 28711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return true; 28811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 28911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 29011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#ifdef WIN32 29111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic inline int vasprintf(char **strp, char const *fmt, va_list ap) { 29211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert *strp = nullptr; 29311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int size = _vscprintf(fmt, ap); 29411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (size >= 0) { 29511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert *strp = (char *)malloc(size+1); 29611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!*strp) { 29711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return -1; 29811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 29911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert _vsnprintf(*strp, size+1, fmt, ap); 30011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 30111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return size; 30211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 30311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif 30411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 30511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* 30611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Output log message via DEBUG_REPORT 30711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Takes format and variable arg list so that output string 30811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * is only computed if a message needs to be logged 30911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 31011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#ifndef WIN32 31111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic inline bool log_msg(const debug_report_data *debug_data, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType, 31211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *format, ...) 31311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert __attribute__((format(printf, 8, 9))); 31411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif 31511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic inline bool log_msg(const debug_report_data *debug_data, VkFlags msgFlags, VkDebugReportObjectTypeEXT objectType, 31611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *format, 31711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert ...) { 31811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!debug_data || !(debug_data->active_flags & msgFlags)) { 31911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* message is not wanted */ 32011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return false; 32111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 32211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 32311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert va_list argptr; 32411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert va_start(argptr, format); 32511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char *str; 32611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (-1 == vasprintf(&str, format, argptr)) { 32711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* on failure, glibc vasprintf leaves str undefined */ 32811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert str = nullptr; 32911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 33011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert va_end(argptr); 33111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert bool result = debug_report_log_msg(debug_data, msgFlags, objectType, srcObject, location, msgCode, pLayerPrefix, 33211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert str ? str : "Allocation failure"); 33311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert free(str); 33411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return result; 33511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 33611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 33711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic inline VKAPI_ATTR VkBool32 VKAPI_CALL log_callback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, 33811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert size_t location, int32_t msgCode, const char *pLayerPrefix, 33911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const char *pMsg, void *pUserData) { 34011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char msg_flags[30]; 34111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 34211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert print_msg_flags(msgFlags, msg_flags); 34311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 34411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert fprintf((FILE *)pUserData, "%s(%s): object: 0x%" PRIx64 " type: %d location: %lu msgCode: %d: %s\n", pLayerPrefix, msg_flags, 34511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert srcObject, objType, (unsigned long)location, msgCode, pMsg); 34611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert fflush((FILE *)pUserData); 34711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 34811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return false; 34911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 35011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 35111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic inline VKAPI_ATTR VkBool32 VKAPI_CALL win32_debug_output_msg(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType, 35211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert uint64_t srcObject, size_t location, int32_t msgCode, 35311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const char *pLayerPrefix, const char *pMsg, void *pUserData) { 35411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#ifdef WIN32 35511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char msg_flags[30]; 35611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char buf[2048]; 35711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 35811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert print_msg_flags(msgFlags, msg_flags); 35911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert _snprintf(buf, sizeof(buf) - 1, 36011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert "%s (%s): object: 0x%" PRIxPTR " type: %d location: " PRINTF_SIZE_T_SPECIFIER " msgCode: %d: %s\n", pLayerPrefix, 36111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert msg_flags, (size_t)srcObject, objType, location, msgCode, pMsg); 36211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 36311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert OutputDebugString(buf); 36411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif 36511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 36611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return false; 36711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 36811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 36911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif // LAYER_LOGGING_H 370