blob: 2110b52b90532b1fef7359a39281711cf28d227b [file] [log] [blame]
Courtney Goeltzenleuchter41fa5b02015-06-11 15:58:51 -06001/*
2 * Vulkan
3 *
4 * Copyright (C) 2014 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Courtney Goeltzenleuchter <courtney@lunarg.com>
26 */
27
28#ifndef LAYER_LOGGING_H
29#define LAYER_LOGGING_H
30
31#include <stdio.h>
32#include <stdbool.h>
33#include <unordered_map>
34#include "vkLayer.h"
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -060035#include "layer_data.h"
Courtney Goeltzenleuchter41fa5b02015-06-11 15:58:51 -060036#include "layers_table.h"
37
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -060038typedef struct debug_report_data {
Courtney Goeltzenleuchter41fa5b02015-06-11 15:58:51 -060039 VkLayerDbgFunctionNode *g_pDbgFunctionHead;
40 bool g_DEBUG_REPORT;
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -060041} data_rec;
Courtney Goeltzenleuchter41fa5b02015-06-11 15:58:51 -060042
43static std::unordered_map<void *, struct debug_report_data *> debug_report_data_map;
44
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -060045template data_rec *get_my_data_ptr<data_rec>(
46 void *data_key,
47 std::unordered_map<void *, struct debug_report_data *> data_map);
Courtney Goeltzenleuchter41fa5b02015-06-11 15:58:51 -060048
49static inline void debug_report_init_instance_extension_dispatch_table(
50 VkLayerInstanceDispatchTable *table,
51 PFN_vkGetInstanceProcAddr gpa,
52 VkInstance inst)
53{
54 table->DbgCreateMsgCallback = (PFN_vkDbgCreateMsgCallback) gpa(inst, "vkDbgCreateMsgCallback");
55 table->DbgDestroyMsgCallback = (PFN_vkDbgDestroyMsgCallback) gpa(inst, "vkDbgDestroyMsgCallback");
56}
57
58// Utility function to handle reporting
59static void debug_report_log_msg(
60 struct debug_report_data *debug_data,
61 VkFlags msgFlags,
62 VkObjectType objectType,
63 VkObject srcObject,
64 size_t location,
65 int32_t msgCode,
66 const char* pLayerPrefix,
67 const char* pMsg)
68{
69 VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead;
70 while (pTrav) {
71 if (pTrav->msgFlags & msgFlags) {
72 pTrav->pfnMsgCallback(msgFlags,
73 objectType, srcObject,
74 location,
75 msgCode,
76 pLayerPrefix,
77 pMsg,
78 (void *) pTrav->pUserData);
79 }
80 pTrav = pTrav->pNext;
81 }
82}
83
84static inline void debug_report_create_instance(
85 VkLayerInstanceDispatchTable *instance_dispatch_ptr,
86 uint32_t extension_count,
87 const VkExtensionProperties* pEnabledExtensions) // layer or extension name to be enabled
88{
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -060089 data_rec *debug_data = get_my_data_ptr(instance_dispatch_ptr);
Courtney Goeltzenleuchter41fa5b02015-06-11 15:58:51 -060090
91 for (uint32_t i = 0; i < extension_count; i++) {
92 /* TODO: Check other property fields */
93 if (strcmp(pEnabledExtensions[i].name, DEBUG_REPORT_EXTENSION_NAME) == 0) {
94 debug_data->g_DEBUG_REPORT = true;
95 }
96 }
97}
98
99static inline void layer_debug_report_destroy_instance(VkInstance instance)
100{
101 VkLayerInstanceDispatchTable *instance_key = instance_dispatch_table(instance);
102 struct debug_report_data *debug_data =
103 get_debug_data_ptr(instance_dispatch_table(instance));
104 VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead;
105 VkLayerDbgFunctionNode *pTravNext;
106
107 /* Clear out any leftover callbacks */
108 while (pTrav) {
109 pTravNext = pTrav->pNext;
110
111 debug_report_log_msg(
112 debug_data, VK_DBG_REPORT_WARN_BIT,
113 VK_OBJECT_TYPE_INSTANCE, instance,
114 0, DEBUG_REPORT_CALLBACK_REF,
115 "DebugReport",
116 "Debug Report callbacks not removed before DestroyInstance");
117
118 free(pTrav);
119 pTrav = pTravNext;
120 }
121 debug_data->g_pDbgFunctionHead = NULL;
122 debug_report_data_map.erase((void *) instance_key);
123 tableInstanceMap.erase((void *) instance);
124}
125
126static inline void layer_debug_report_create_device(
127 VkLayerInstanceDispatchTable *instance_dispatch_ptr,
128 VkDevice device)
129{
130 std::unordered_map<void *, struct debug_report_data *>::const_iterator got;
131
132 got = debug_report_data_map.find((void *) instance_dispatch_ptr);
133
134 if ( got == debug_report_data_map.end() ) {
135 // If we get here something is wrong
136 // We should always be able to find the instance key
137 assert(true);
138 } else {
139 VkLayerDispatchTable *device_key = device_dispatch_table(device);
140 debug_report_data_map[(void *) device_key ] = got->second;
141 }
142}
143
144static inline void layer_debug_report_destroy_device(VkDevice device)
145{
146 VkLayerDispatchTable *device_key = device_dispatch_table(device);
147 debug_report_data_map.erase((void *) device_key);
148 tableMap.erase((void *) device);
149}
150
151static inline VkResult layer_create_msg_callback(
152 VkInstance instance,
153 VkLayerInstanceDispatchTable *nextTable,
154 VkFlags msgFlags,
155 const PFN_vkDbgMsgCallback pfnMsgCallback,
156 void *pUserData,
157 VkDbgMsgCallback *pMsgCallback)
158{
159 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode*)malloc(sizeof(VkLayerDbgFunctionNode));
160 if (!pNewDbgFuncNode)
161 return VK_ERROR_OUT_OF_HOST_MEMORY;
162
163 VkResult result = nextTable->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
164
165 if (result == VK_SUCCESS) {
166 struct debug_report_data *debug_data =
167 get_debug_data_ptr(instance_dispatch_table(instance));
168
169 pNewDbgFuncNode->msgCallback = *pMsgCallback;
170 pNewDbgFuncNode->pfnMsgCallback = pfnMsgCallback;
171 pNewDbgFuncNode->msgFlags = msgFlags;
172 pNewDbgFuncNode->pUserData = pUserData;
173 pNewDbgFuncNode->pNext = debug_data->g_pDbgFunctionHead;
174
175 debug_data->g_pDbgFunctionHead = pNewDbgFuncNode;
176
177 debug_report_log_msg(
178 debug_data, VK_DBG_REPORT_DEBUG_BIT,
179 VK_OBJECT_TYPE_INSTANCE, instance,
180 0, DEBUG_REPORT_CALLBACK_REF,
181 "DebugReport",
182 "Added callback");
183 } else {
184 free(pNewDbgFuncNode);
185 }
186 return result;
187}
188
189static VkResult layer_destroy_msg_callback(
190 VkInstance instance,
191 VkLayerInstanceDispatchTable *nextTable,
192 VkDbgMsgCallback msg_callback)
193{
194 struct debug_report_data *debug_data =
195 get_debug_data_ptr(instance_dispatch_table(instance));
196 VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead;
197 VkLayerDbgFunctionNode *pPrev = pTrav;
198
199 VkResult result = nextTable->DbgDestroyMsgCallback(instance, msg_callback);
200
201 while (pTrav) {
202 if (pTrav->msgCallback == msg_callback) {
203 pPrev->pNext = pTrav->pNext;
204 if (debug_data->g_pDbgFunctionHead == pTrav) {
205 debug_data->g_pDbgFunctionHead = pTrav->pNext;
206 }
207 free(pTrav);
208 debug_report_log_msg(
209 debug_data, VK_DBG_REPORT_DEBUG_BIT,
210 VK_OBJECT_TYPE_INSTANCE, instance,
211 0, DEBUG_REPORT_CALLBACK_REF,
212 "DebugReport",
213 "Removed callback");
214 break;
215 }
216 pPrev = pTrav;
217 pTrav = pTrav->pNext;
218 }
219
220 return result;
221}
222
223static void* debug_report_get_instance_proc_addr(
224 VkInstance instance,
225 const char *funcName)
226{
227 struct debug_report_data *debug_data =
228 get_debug_data_ptr(instance_dispatch_table(instance));
229 if (!debug_data->g_DEBUG_REPORT) {
230 return NULL;
231 }
232
233 if (!strcmp(funcName, "vkDbgCreateMsgCallback")) {
234 return (void *) vkDbgCreateMsgCallback;
235 }
236 if (!strcmp(funcName, "vkDbgDestroyMsgCallback")) {
237 return (void *) vkDbgDestroyMsgCallback;
238 }
239
240 return NULL;
241}
242
243/*
244 * Devices, Queue, SwapChain and Command buffers all
245 * use the same device dispatch table.
246 */
247static void device_log_msg(
248 VkObject object,
249 VkFlags msgFlags,
250 VkObjectType objectType,
251 VkObject srcObject,
252 size_t location,
253 int32_t msgCode,
254 const char* pLayerPrefix,
255 const char* pMsg)
256{
257 struct debug_report_data *debug_data;
258 debug_data = get_device_debug_data_ptr(device_dispatch_table(object));
259 debug_report_log_msg(debug_data, msgFlags, objectType,
260 srcObject, location, msgCode,
261 pLayerPrefix, pMsg);
262}
263
264static void instance_log_msg(
265 VkInstance instance,
266 VkFlags msgFlags,
267 VkObjectType objectType,
268 VkObject srcObject,
269 size_t location,
270 int32_t msgCode,
271 const char* pLayerPrefix,
272 const char* pMsg)
273{
274 struct debug_report_data *debug_data;
275
276 debug_data = get_instance_debug_data_ptr(instance_dispatch_table(instance));
277 debug_report_log_msg(debug_data, msgFlags, objectType,
278 srcObject, location, msgCode,
279 pLayerPrefix, pMsg);
280}
281
282#endif // LAYER_LOGGING_H
283