blob: 752ddff89df9b45b68d0d050215e8feb9a95bd17 [file] [log] [blame]
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001/*
2 * Vulkan
3 *
4 * Copyright (C) 2015 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 * Jon Ashburn <jon@lunarg.com>
26 * Courtney Goeltzenleuchter <courtney@lunarg.com>
27 */
28
Courtney Goeltzenleuchterb620ace2015-07-05 11:28:29 -060029#define _GNU_SOURCE
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -060030#include <stdio.h>
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060031#include <string.h>
32#include <stdlib.h>
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -060033#include <inttypes.h>
Tony Barbour69698512015-06-18 16:29:32 -060034#ifndef WIN32
Courtney Goeltzenleuchterc3c1f012015-07-22 11:01:53 -060035#include <signal.h>
36#else
Tony Barbour69698512015-06-18 16:29:32 -060037#endif
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060038#include "debug_report.h"
Tobin Ehlis2d1d9702015-07-03 09:42:57 -060039#include "vk_layer.h"
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060040
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -060041typedef void (VKAPI *PFN_stringCallback)(char *message);
42
Jon Ashburnc4748dc2015-08-04 11:14:18 -060043static const VkExtensionProperties debug_report_extension_info = {
Courtney Goeltzenleuchter846298c2015-07-30 11:32:46 -060044 .extName = VK_DEBUG_REPORT_EXTENSION_NAME,
Ian Elliottd5b6e892015-09-04 14:14:35 -060045 .specVersion = VK_DEBUG_REPORT_EXTENSION_REVISION,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060046};
47
48void debug_report_add_instance_extensions(
49 struct loader_extension_list *ext_list)
50{
51 loader_add_to_ext_list(ext_list, 1, &debug_report_extension_info);
52}
53
54void debug_report_create_instance(
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -060055 struct loader_instance *ptr_instance,
56 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060057{
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -060058 ptr_instance->debug_report_enabled = false;
59
60 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
Courtney Goeltzenleuchter846298c2015-07-30 11:32:46 -060061 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_DEBUG_REPORT_EXTENSION_NAME) == 0) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -060062 ptr_instance->debug_report_enabled = true;
63 return;
64 }
65 }
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060066}
67
68static VkResult debug_report_DbgCreateMsgCallback(
69 VkInstance instance,
70 VkFlags msgFlags,
71 const PFN_vkDbgMsgCallback pfnMsgCallback,
72 void* pUserData,
73 VkDbgMsgCallback* pMsgCallback)
74{
75 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *) malloc(sizeof(VkLayerDbgFunctionNode));
76 if (!pNewDbgFuncNode)
77 return VK_ERROR_OUT_OF_HOST_MEMORY;
78
Courtney Goeltzenleuchter8afefb52015-06-08 15:04:02 -060079 struct loader_instance *inst = loader_instance(instance);
Jon Ashburnb40f2562015-05-29 13:15:39 -060080 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060081 VkResult result = inst->disp->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
82 if (result == VK_SUCCESS) {
83 pNewDbgFuncNode->msgCallback = *pMsgCallback;
84 pNewDbgFuncNode->pfnMsgCallback = pfnMsgCallback;
85 pNewDbgFuncNode->msgFlags = msgFlags;
86 pNewDbgFuncNode->pUserData = pUserData;
87 pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
88 inst->DbgFunctionHead = pNewDbgFuncNode;
89 } else {
90 free(pNewDbgFuncNode);
91 }
Jon Ashburnb40f2562015-05-29 13:15:39 -060092 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060093 return result;
94}
95
96static VkResult debug_report_DbgDestroyMsgCallback(
97 VkInstance instance,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060098 VkDbgMsgCallback msg_callback)
99{
Courtney Goeltzenleuchter8afefb52015-06-08 15:04:02 -0600100 struct loader_instance *inst = loader_instance(instance);
Jon Ashburnb40f2562015-05-29 13:15:39 -0600101 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600102 VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
103 VkLayerDbgFunctionNode *pPrev = pTrav;
104
Courtney Goeltzenleuchter3d8dc1f2015-06-08 15:09:22 -0600105 VkResult result = inst->disp->DbgDestroyMsgCallback(instance, msg_callback);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600106
107 while (pTrav) {
Tony Barbourde4124d2015-07-03 10:33:54 -0600108 if (pTrav->msgCallback.handle == msg_callback.handle) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600109 pPrev->pNext = pTrav->pNext;
110 if (inst->DbgFunctionHead == pTrav)
111 inst->DbgFunctionHead = pTrav->pNext;
112 free(pTrav);
113 break;
114 }
115 pPrev = pTrav;
116 pTrav = pTrav->pNext;
117 }
118
Jon Ashburnb40f2562015-05-29 13:15:39 -0600119 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600120 return result;
121}
122
123
124/*
125 * This is the instance chain terminator function
126 * for DbgCreateMsgCallback
127 */
Tony Barbourde4124d2015-07-03 10:33:54 -0600128
Dan Ginsburgf99e4102015-07-23 13:15:00 -0400129VkResult VKAPI loader_DbgCreateMsgCallback(
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600130 VkInstance instance,
131 VkFlags msgFlags,
132 const PFN_vkDbgMsgCallback pfnMsgCallback,
Jon Ashburnf9136f42015-08-06 13:56:43 -0600133 void* pUserData,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600134 VkDbgMsgCallback* pMsgCallback)
135{
136 VkDbgMsgCallback *icd_info;
137 const struct loader_icd *icd;
138 struct loader_instance *inst;
139 VkResult res;
140 uint32_t storage_idx;
141
142 if (instance == VK_NULL_HANDLE)
143 return VK_ERROR_INVALID_HANDLE;
144
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600145 for (inst = loader.instances; inst; inst = inst->next) {
146 if ((VkInstance) inst == instance)
147 break;
148 }
149
150 if (inst == VK_NULL_HANDLE)
151 return VK_ERROR_INVALID_HANDLE;
152
153 icd_info = calloc(sizeof(VkDbgMsgCallback), inst->total_icd_count);
154 if (!icd_info) {
155 return VK_ERROR_OUT_OF_HOST_MEMORY;
156 }
157
158 storage_idx = 0;
159 for (icd = inst->icds; icd; icd = icd->next) {
160 if (!icd->DbgCreateMsgCallback) {
161 continue;
162 }
163
164 res = icd->DbgCreateMsgCallback(
165 icd->instance,
166 msgFlags,
167 pfnMsgCallback,
168 pUserData,
169 &icd_info[storage_idx]);
170
171 if (res != VK_SUCCESS) {
172 break;
173 }
174 storage_idx++;
175 }
176
177 /* roll back on errors */
178 if (icd) {
179 storage_idx = 0;
180 for (icd = inst->icds; icd; icd = icd->next) {
Tony Barbourde4124d2015-07-03 10:33:54 -0600181 if (icd_info[storage_idx].handle) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600182 icd->DbgDestroyMsgCallback(
183 icd->instance,
184 icd_info[storage_idx]);
185 }
186 storage_idx++;
187 }
188
189 return res;
190 }
191
Tony Barbourde4124d2015-07-03 10:33:54 -0600192 *(VkDbgMsgCallback **)pMsgCallback = icd_info;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600193
194 return VK_SUCCESS;
195}
196
197/*
198 * This is the instance chain terminator function
199 * for DbgDestroyMsgCallback
200 */
Dan Ginsburgf99e4102015-07-23 13:15:00 -0400201VkResult VKAPI loader_DbgDestroyMsgCallback(
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600202 VkInstance instance,
203 VkDbgMsgCallback msgCallback)
204{
205 uint32_t storage_idx;
206 VkDbgMsgCallback *icd_info;
207 const struct loader_icd *icd;
208 VkResult res = VK_SUCCESS;
209 struct loader_instance *inst;
210
211 if (instance == VK_NULL_HANDLE)
212 return VK_ERROR_INVALID_HANDLE;
213
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600214 for (inst = loader.instances; inst; inst = inst->next) {
215 if ((VkInstance) inst == instance)
216 break;
217 }
218
219 if (inst == VK_NULL_HANDLE)
220 return VK_ERROR_INVALID_HANDLE;
221
Tony Barbourde4124d2015-07-03 10:33:54 -0600222 icd_info = *(VkDbgMsgCallback **) &msgCallback;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600223 storage_idx = 0;
224 for (icd = inst->icds; icd; icd = icd->next) {
Tony Barbourde4124d2015-07-03 10:33:54 -0600225 if (icd_info[storage_idx].handle) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600226 icd->DbgDestroyMsgCallback(
Courtney Goeltzenleuchter3d8dc1f2015-06-08 15:09:22 -0600227 icd->instance,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600228 icd_info[storage_idx]);
229 }
230 storage_idx++;
231 }
232 return res;
233}
234
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600235static void print_msg_flags(VkFlags msgFlags, char *msg_flags)
236{
237 bool separator = false;
238
239 msg_flags[0] = 0;
240 if (msgFlags & VK_DBG_REPORT_DEBUG_BIT) {
241 strcat(msg_flags, "DEBUG");
242 separator = true;
243 }
244 if (msgFlags & VK_DBG_REPORT_INFO_BIT) {
245 if (separator) strcat(msg_flags, ",");
246 strcat(msg_flags, "INFO");
247 separator = true;
248 }
249 if (msgFlags & VK_DBG_REPORT_WARN_BIT) {
250 if (separator) strcat(msg_flags, ",");
251 strcat(msg_flags, "WARN");
252 separator = true;
253 }
254 if (msgFlags & VK_DBG_REPORT_PERF_WARN_BIT) {
255 if (separator) strcat(msg_flags, ",");
256 strcat(msg_flags, "PERF");
257 separator = true;
258 }
259 if (msgFlags & VK_DBG_REPORT_ERROR_BIT) {
260 if (separator) strcat(msg_flags, ",");
261 strcat(msg_flags, "ERROR");
262 }
263}
264
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600265// DebugReport utility callback functions
266static void VKAPI StringCallback(
267 VkFlags msgFlags,
Tony Barbourde4124d2015-07-03 10:33:54 -0600268 VkDbgObjectType objType,
269 uint64_t srcObject,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600270 size_t location,
271 int32_t msgCode,
272 const char* pLayerPrefix,
273 const char* pMsg,
274 void* pUserData)
275{
Jon Ashburncab27b32015-06-30 14:44:13 -0700276 size_t buf_size;
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600277 char *buf;
278 char msg_flags[30];
279 PFN_stringCallback callback = (PFN_stringCallback) pUserData;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600280
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600281 print_msg_flags(msgFlags, msg_flags);
282
283 buf_size = strlen(msg_flags) + /* ReportFlags: i.e. (DEBUG,INFO,WARN,PERF,ERROR) */
284 20 + /* objType */
285 20 + /* srcObject */
286 20 + /* location */
287 20 + /* msgCode */
288 strlen(pLayerPrefix) +
289 strlen(pMsg) +
290 50 /* other / whitespace */;
Jon Ashburne5c48722015-08-27 13:06:58 -0600291 buf = loader_stack_alloc(buf_size);
292
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600293 snprintf(buf, buf_size, "%s (%s): object: 0x%" PRIxLEAST64 " type: %d location: %zu msgCode: %d: %s",
294 pLayerPrefix, msg_flags, srcObject, objType, location, msgCode, pMsg);
295 callback(buf);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600296}
297
298static void VKAPI StdioCallback(
299 VkFlags msgFlags,
Tony Barbourde4124d2015-07-03 10:33:54 -0600300 VkDbgObjectType objType,
301 uint64_t srcObject,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600302 size_t location,
303 int32_t msgCode,
304 const char* pLayerPrefix,
305 const char* pMsg,
306 void* pUserData)
307{
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600308 char msg_flags[30];
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600309
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600310 print_msg_flags(msgFlags, msg_flags);
311
312 fprintf((FILE *) pUserData, "%s(%s): object: 0x%" PRIxLEAST64 " type: %d location: %zu msgCode: %d: %s",
313 pLayerPrefix, msg_flags, srcObject, objType, location, msgCode, pMsg);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600314}
315
316static void VKAPI BreakCallback(
317 VkFlags msgFlags,
Tony Barbourde4124d2015-07-03 10:33:54 -0600318 VkDbgObjectType objType,
319 uint64_t srcObject,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600320 size_t location,
321 int32_t msgCode,
322 const char* pLayerPrefix,
323 const char* pMsg,
324 void* pUserData)
325{
Courtney Goeltzenleuchterc3c1f012015-07-22 11:01:53 -0600326#ifndef WIN32
327 raise(SIGTRAP);
328#else
329 DebugBreak();
330#endif
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600331}
332
333void *debug_report_instance_gpa(
334 struct loader_instance *ptr_instance,
335 const char* name)
336{
337 if (ptr_instance == VK_NULL_HANDLE || !ptr_instance->debug_report_enabled)
338 return NULL;
339
340 if (!strcmp("vkDbgCreateMsgCallback", name))
341 return (void *) debug_report_DbgCreateMsgCallback;
342 else if (!strcmp("vkDbgDestroyMsgCallback", name))
343 return (void *) debug_report_DbgDestroyMsgCallback;
Jon Ashburnb843f0b2015-05-26 13:56:43 -0600344 else if (!strcmp("vkDbgStringCallback", name))
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600345 return (void *) StringCallback;
Jon Ashburnb843f0b2015-05-26 13:56:43 -0600346 else if (!strcmp("vkDbgStdioCallback", name))
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600347 return (void *) StdioCallback;
Jon Ashburnb843f0b2015-05-26 13:56:43 -0600348 else if (!strcmp("vkDbgBreakCallback", name))
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600349 return (void *) BreakCallback;
350
351 return NULL;
352}