blob: b7f77c4a6e1b0814b0885bf33805b91b00912893 [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"
35#include "layers_table.h"
36
37struct debug_report_data {
38 VkLayerDbgFunctionNode *g_pDbgFunctionHead;
39 bool g_DEBUG_REPORT;
40};
41
42static std::unordered_map<void *, struct debug_report_data *> debug_report_data_map;
43
44static struct debug_report_data *get_debug_data_ptr(
45 void *data_key)
46{
47 struct debug_report_data *debug_data;
48 std::unordered_map<void *, struct debug_report_data *>::const_iterator got;
49
50 got = debug_report_data_map.find(data_key);
51
52 if ( got == debug_report_data_map.end() ) {
53 debug_data = new struct debug_report_data;
54 memset(debug_data, 0, sizeof(*debug_data));
55 debug_report_data_map[(void *) data_key] = debug_data;
56 } else {
57 debug_data = got->second;
58 }
59
60 return debug_data;
61}
62
63static struct debug_report_data *get_device_debug_data_ptr(
64 VkLayerDispatchTable *device_dispatch_ptr)
65{
66 return get_debug_data_ptr((void *) device_dispatch_ptr);
67}
68
69static struct debug_report_data *get_instance_debug_data_ptr(
70 VkLayerInstanceDispatchTable *instance_dispatch_ptr)
71{
72 return get_debug_data_ptr((void *) instance_dispatch_ptr);
73}
74
75static inline void debug_report_init_instance_extension_dispatch_table(
76 VkLayerInstanceDispatchTable *table,
77 PFN_vkGetInstanceProcAddr gpa,
78 VkInstance inst)
79{
80 table->DbgCreateMsgCallback = (PFN_vkDbgCreateMsgCallback) gpa(inst, "vkDbgCreateMsgCallback");
81 table->DbgDestroyMsgCallback = (PFN_vkDbgDestroyMsgCallback) gpa(inst, "vkDbgDestroyMsgCallback");
82}
83
84// Utility function to handle reporting
85static void debug_report_log_msg(
86 struct debug_report_data *debug_data,
87 VkFlags msgFlags,
88 VkObjectType objectType,
89 VkObject srcObject,
90 size_t location,
91 int32_t msgCode,
92 const char* pLayerPrefix,
93 const char* pMsg)
94{
95 VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead;
96 while (pTrav) {
97 if (pTrav->msgFlags & msgFlags) {
98 pTrav->pfnMsgCallback(msgFlags,
99 objectType, srcObject,
100 location,
101 msgCode,
102 pLayerPrefix,
103 pMsg,
104 (void *) pTrav->pUserData);
105 }
106 pTrav = pTrav->pNext;
107 }
108}
109
110static inline void debug_report_create_instance(
111 VkLayerInstanceDispatchTable *instance_dispatch_ptr,
112 uint32_t extension_count,
113 const VkExtensionProperties* pEnabledExtensions) // layer or extension name to be enabled
114{
115 struct debug_report_data *debug_data = get_debug_data_ptr(instance_dispatch_ptr);
116
117 for (uint32_t i = 0; i < extension_count; i++) {
118 /* TODO: Check other property fields */
119 if (strcmp(pEnabledExtensions[i].name, DEBUG_REPORT_EXTENSION_NAME) == 0) {
120 debug_data->g_DEBUG_REPORT = true;
121 }
122 }
123}
124
125static inline void layer_debug_report_destroy_instance(VkInstance instance)
126{
127 VkLayerInstanceDispatchTable *instance_key = instance_dispatch_table(instance);
128 struct debug_report_data *debug_data =
129 get_debug_data_ptr(instance_dispatch_table(instance));
130 VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead;
131 VkLayerDbgFunctionNode *pTravNext;
132
133 /* Clear out any leftover callbacks */
134 while (pTrav) {
135 pTravNext = pTrav->pNext;
136
137 debug_report_log_msg(
138 debug_data, VK_DBG_REPORT_WARN_BIT,
139 VK_OBJECT_TYPE_INSTANCE, instance,
140 0, DEBUG_REPORT_CALLBACK_REF,
141 "DebugReport",
142 "Debug Report callbacks not removed before DestroyInstance");
143
144 free(pTrav);
145 pTrav = pTravNext;
146 }
147 debug_data->g_pDbgFunctionHead = NULL;
148 debug_report_data_map.erase((void *) instance_key);
149 tableInstanceMap.erase((void *) instance);
150}
151
152static inline void layer_debug_report_create_device(
153 VkLayerInstanceDispatchTable *instance_dispatch_ptr,
154 VkDevice device)
155{
156 std::unordered_map<void *, struct debug_report_data *>::const_iterator got;
157
158 got = debug_report_data_map.find((void *) instance_dispatch_ptr);
159
160 if ( got == debug_report_data_map.end() ) {
161 // If we get here something is wrong
162 // We should always be able to find the instance key
163 assert(true);
164 } else {
165 VkLayerDispatchTable *device_key = device_dispatch_table(device);
166 debug_report_data_map[(void *) device_key ] = got->second;
167 }
168}
169
170static inline void layer_debug_report_destroy_device(VkDevice device)
171{
172 VkLayerDispatchTable *device_key = device_dispatch_table(device);
173 debug_report_data_map.erase((void *) device_key);
174 tableMap.erase((void *) device);
175}
176
177static inline VkResult layer_create_msg_callback(
178 VkInstance instance,
179 VkLayerInstanceDispatchTable *nextTable,
180 VkFlags msgFlags,
181 const PFN_vkDbgMsgCallback pfnMsgCallback,
182 void *pUserData,
183 VkDbgMsgCallback *pMsgCallback)
184{
185 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode*)malloc(sizeof(VkLayerDbgFunctionNode));
186 if (!pNewDbgFuncNode)
187 return VK_ERROR_OUT_OF_HOST_MEMORY;
188
189 VkResult result = nextTable->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
190
191 if (result == VK_SUCCESS) {
192 struct debug_report_data *debug_data =
193 get_debug_data_ptr(instance_dispatch_table(instance));
194
195 pNewDbgFuncNode->msgCallback = *pMsgCallback;
196 pNewDbgFuncNode->pfnMsgCallback = pfnMsgCallback;
197 pNewDbgFuncNode->msgFlags = msgFlags;
198 pNewDbgFuncNode->pUserData = pUserData;
199 pNewDbgFuncNode->pNext = debug_data->g_pDbgFunctionHead;
200
201 debug_data->g_pDbgFunctionHead = pNewDbgFuncNode;
202
203 debug_report_log_msg(
204 debug_data, VK_DBG_REPORT_DEBUG_BIT,
205 VK_OBJECT_TYPE_INSTANCE, instance,
206 0, DEBUG_REPORT_CALLBACK_REF,
207 "DebugReport",
208 "Added callback");
209 } else {
210 free(pNewDbgFuncNode);
211 }
212 return result;
213}
214
215static VkResult layer_destroy_msg_callback(
216 VkInstance instance,
217 VkLayerInstanceDispatchTable *nextTable,
218 VkDbgMsgCallback msg_callback)
219{
220 struct debug_report_data *debug_data =
221 get_debug_data_ptr(instance_dispatch_table(instance));
222 VkLayerDbgFunctionNode *pTrav = debug_data->g_pDbgFunctionHead;
223 VkLayerDbgFunctionNode *pPrev = pTrav;
224
225 VkResult result = nextTable->DbgDestroyMsgCallback(instance, msg_callback);
226
227 while (pTrav) {
228 if (pTrav->msgCallback == msg_callback) {
229 pPrev->pNext = pTrav->pNext;
230 if (debug_data->g_pDbgFunctionHead == pTrav) {
231 debug_data->g_pDbgFunctionHead = pTrav->pNext;
232 }
233 free(pTrav);
234 debug_report_log_msg(
235 debug_data, VK_DBG_REPORT_DEBUG_BIT,
236 VK_OBJECT_TYPE_INSTANCE, instance,
237 0, DEBUG_REPORT_CALLBACK_REF,
238 "DebugReport",
239 "Removed callback");
240 break;
241 }
242 pPrev = pTrav;
243 pTrav = pTrav->pNext;
244 }
245
246 return result;
247}
248
249static void* debug_report_get_instance_proc_addr(
250 VkInstance instance,
251 const char *funcName)
252{
253 struct debug_report_data *debug_data =
254 get_debug_data_ptr(instance_dispatch_table(instance));
255 if (!debug_data->g_DEBUG_REPORT) {
256 return NULL;
257 }
258
259 if (!strcmp(funcName, "vkDbgCreateMsgCallback")) {
260 return (void *) vkDbgCreateMsgCallback;
261 }
262 if (!strcmp(funcName, "vkDbgDestroyMsgCallback")) {
263 return (void *) vkDbgDestroyMsgCallback;
264 }
265
266 return NULL;
267}
268
269/*
270 * Devices, Queue, SwapChain and Command buffers all
271 * use the same device dispatch table.
272 */
273static void device_log_msg(
274 VkObject object,
275 VkFlags msgFlags,
276 VkObjectType objectType,
277 VkObject srcObject,
278 size_t location,
279 int32_t msgCode,
280 const char* pLayerPrefix,
281 const char* pMsg)
282{
283 struct debug_report_data *debug_data;
284 debug_data = get_device_debug_data_ptr(device_dispatch_table(object));
285 debug_report_log_msg(debug_data, msgFlags, objectType,
286 srcObject, location, msgCode,
287 pLayerPrefix, pMsg);
288}
289
290static void instance_log_msg(
291 VkInstance instance,
292 VkFlags msgFlags,
293 VkObjectType objectType,
294 VkObject srcObject,
295 size_t location,
296 int32_t msgCode,
297 const char* pLayerPrefix,
298 const char* pMsg)
299{
300 struct debug_report_data *debug_data;
301
302 debug_data = get_instance_debug_data_ptr(instance_dispatch_table(instance));
303 debug_report_log_msg(debug_data, msgFlags, objectType,
304 srcObject, location, msgCode,
305 pLayerPrefix, pMsg);
306}
307
308#endif // LAYER_LOGGING_H
309