debug_report: Utilities for layers to use
authorCourtney Goeltzenleuchter <courtney@LunarG.com>
Thu, 11 Jun 2015 21:58:51 +0000 (15:58 -0600)
committerCourtney Goeltzenleuchter <courtney@LunarG.com>
Thu, 18 Jun 2015 16:22:55 +0000 (10:22 -0600)
This header is intended to be used by all validation
layers and provides the necessary functions to process
DEBUG_REPORT messages and generate callbacks.
This is intended for layers implementing per instance / device
storage.

layers/layer_logging.h [new file with mode: 0644]

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