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