blob: 5ef5c4910018a485e3850ba393206073dc884594 [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 Goeltzenleuchterf1eb2492015-06-11 16:01:11 -060035#include <alloca.h>
Courtney Goeltzenleuchterc3c1f012015-07-22 11:01:53 -060036#include <signal.h>
37#else
Tony Barbour69698512015-06-18 16:29:32 -060038#endif
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060039#include "debug_report.h"
Tobin Ehlis2d1d9702015-07-03 09:42:57 -060040#include "vk_layer.h"
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060041
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -060042typedef void (VKAPI *PFN_stringCallback)(char *message);
43
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060044static const struct loader_extension_property debug_report_extension_info = {
45 .info = {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -060046 .extName = DEBUG_REPORT_EXTENSION_NAME,
Courtney Goeltzenleuchter73a21d32015-07-12 13:20:05 -060047 .specVersion = VK_DEBUG_REPORT_EXTENSION_VERSION,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060048 },
49 .origin = VK_EXTENSION_ORIGIN_LOADER,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060050};
51
52void debug_report_add_instance_extensions(
53 struct loader_extension_list *ext_list)
54{
55 loader_add_to_ext_list(ext_list, 1, &debug_report_extension_info);
56}
57
58void debug_report_create_instance(
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -060059 struct loader_instance *ptr_instance,
60 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060061{
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -060062 ptr_instance->debug_report_enabled = false;
63
64 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
65 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], DEBUG_REPORT_EXTENSION_NAME) == 0) {
66 ptr_instance->debug_report_enabled = true;
67 return;
68 }
69 }
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060070}
71
72static VkResult debug_report_DbgCreateMsgCallback(
73 VkInstance instance,
74 VkFlags msgFlags,
75 const PFN_vkDbgMsgCallback pfnMsgCallback,
76 void* pUserData,
77 VkDbgMsgCallback* pMsgCallback)
78{
79 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *) malloc(sizeof(VkLayerDbgFunctionNode));
80 if (!pNewDbgFuncNode)
81 return VK_ERROR_OUT_OF_HOST_MEMORY;
82
Courtney Goeltzenleuchter8afefb52015-06-08 15:04:02 -060083 struct loader_instance *inst = loader_instance(instance);
Jon Ashburnb40f2562015-05-29 13:15:39 -060084 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060085 VkResult result = inst->disp->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
86 if (result == VK_SUCCESS) {
87 pNewDbgFuncNode->msgCallback = *pMsgCallback;
88 pNewDbgFuncNode->pfnMsgCallback = pfnMsgCallback;
89 pNewDbgFuncNode->msgFlags = msgFlags;
90 pNewDbgFuncNode->pUserData = pUserData;
91 pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
92 inst->DbgFunctionHead = pNewDbgFuncNode;
93 } else {
94 free(pNewDbgFuncNode);
95 }
Jon Ashburnb40f2562015-05-29 13:15:39 -060096 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060097 return result;
98}
99
100static VkResult debug_report_DbgDestroyMsgCallback(
101 VkInstance instance,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600102 VkDbgMsgCallback msg_callback)
103{
Courtney Goeltzenleuchter8afefb52015-06-08 15:04:02 -0600104 struct loader_instance *inst = loader_instance(instance);
Jon Ashburnb40f2562015-05-29 13:15:39 -0600105 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600106 VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
107 VkLayerDbgFunctionNode *pPrev = pTrav;
108
Courtney Goeltzenleuchter3d8dc1f2015-06-08 15:09:22 -0600109 VkResult result = inst->disp->DbgDestroyMsgCallback(instance, msg_callback);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600110
111 while (pTrav) {
Tony Barbourde4124d2015-07-03 10:33:54 -0600112 if (pTrav->msgCallback.handle == msg_callback.handle) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600113 pPrev->pNext = pTrav->pNext;
114 if (inst->DbgFunctionHead == pTrav)
115 inst->DbgFunctionHead = pTrav->pNext;
116 free(pTrav);
117 break;
118 }
119 pPrev = pTrav;
120 pTrav = pTrav->pNext;
121 }
122
Jon Ashburnb40f2562015-05-29 13:15:39 -0600123 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600124 return result;
125}
126
127
128/*
129 * This is the instance chain terminator function
130 * for DbgCreateMsgCallback
131 */
Tony Barbourde4124d2015-07-03 10:33:54 -0600132
Dan Ginsburgf99e4102015-07-23 13:15:00 -0400133VkResult VKAPI loader_DbgCreateMsgCallback(
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600134 VkInstance instance,
135 VkFlags msgFlags,
136 const PFN_vkDbgMsgCallback pfnMsgCallback,
137 const void* pUserData,
138 VkDbgMsgCallback* pMsgCallback)
139{
140 VkDbgMsgCallback *icd_info;
141 const struct loader_icd *icd;
142 struct loader_instance *inst;
143 VkResult res;
144 uint32_t storage_idx;
145
146 if (instance == VK_NULL_HANDLE)
147 return VK_ERROR_INVALID_HANDLE;
148
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600149 for (inst = loader.instances; inst; inst = inst->next) {
150 if ((VkInstance) inst == instance)
151 break;
152 }
153
154 if (inst == VK_NULL_HANDLE)
155 return VK_ERROR_INVALID_HANDLE;
156
157 icd_info = calloc(sizeof(VkDbgMsgCallback), inst->total_icd_count);
158 if (!icd_info) {
159 return VK_ERROR_OUT_OF_HOST_MEMORY;
160 }
161
162 storage_idx = 0;
163 for (icd = inst->icds; icd; icd = icd->next) {
164 if (!icd->DbgCreateMsgCallback) {
165 continue;
166 }
167
168 res = icd->DbgCreateMsgCallback(
169 icd->instance,
170 msgFlags,
171 pfnMsgCallback,
172 pUserData,
173 &icd_info[storage_idx]);
174
175 if (res != VK_SUCCESS) {
176 break;
177 }
178 storage_idx++;
179 }
180
181 /* roll back on errors */
182 if (icd) {
183 storage_idx = 0;
184 for (icd = inst->icds; icd; icd = icd->next) {
Tony Barbourde4124d2015-07-03 10:33:54 -0600185 if (icd_info[storage_idx].handle) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600186 icd->DbgDestroyMsgCallback(
187 icd->instance,
188 icd_info[storage_idx]);
189 }
190 storage_idx++;
191 }
192
193 return res;
194 }
195
Tony Barbourde4124d2015-07-03 10:33:54 -0600196 *(VkDbgMsgCallback **)pMsgCallback = icd_info;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600197
198 return VK_SUCCESS;
199}
200
201/*
202 * This is the instance chain terminator function
203 * for DbgDestroyMsgCallback
204 */
Dan Ginsburgf99e4102015-07-23 13:15:00 -0400205VkResult VKAPI loader_DbgDestroyMsgCallback(
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600206 VkInstance instance,
207 VkDbgMsgCallback msgCallback)
208{
209 uint32_t storage_idx;
210 VkDbgMsgCallback *icd_info;
211 const struct loader_icd *icd;
212 VkResult res = VK_SUCCESS;
213 struct loader_instance *inst;
214
215 if (instance == VK_NULL_HANDLE)
216 return VK_ERROR_INVALID_HANDLE;
217
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600218 for (inst = loader.instances; inst; inst = inst->next) {
219 if ((VkInstance) inst == instance)
220 break;
221 }
222
223 if (inst == VK_NULL_HANDLE)
224 return VK_ERROR_INVALID_HANDLE;
225
Tony Barbourde4124d2015-07-03 10:33:54 -0600226 icd_info = *(VkDbgMsgCallback **) &msgCallback;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600227 storage_idx = 0;
228 for (icd = inst->icds; icd; icd = icd->next) {
Tony Barbourde4124d2015-07-03 10:33:54 -0600229 if (icd_info[storage_idx].handle) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600230 icd->DbgDestroyMsgCallback(
Courtney Goeltzenleuchter3d8dc1f2015-06-08 15:09:22 -0600231 icd->instance,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600232 icd_info[storage_idx]);
233 }
234 storage_idx++;
235 }
236 return res;
237}
238
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600239static void print_msg_flags(VkFlags msgFlags, char *msg_flags)
240{
241 bool separator = false;
242
243 msg_flags[0] = 0;
244 if (msgFlags & VK_DBG_REPORT_DEBUG_BIT) {
245 strcat(msg_flags, "DEBUG");
246 separator = true;
247 }
248 if (msgFlags & VK_DBG_REPORT_INFO_BIT) {
249 if (separator) strcat(msg_flags, ",");
250 strcat(msg_flags, "INFO");
251 separator = true;
252 }
253 if (msgFlags & VK_DBG_REPORT_WARN_BIT) {
254 if (separator) strcat(msg_flags, ",");
255 strcat(msg_flags, "WARN");
256 separator = true;
257 }
258 if (msgFlags & VK_DBG_REPORT_PERF_WARN_BIT) {
259 if (separator) strcat(msg_flags, ",");
260 strcat(msg_flags, "PERF");
261 separator = true;
262 }
263 if (msgFlags & VK_DBG_REPORT_ERROR_BIT) {
264 if (separator) strcat(msg_flags, ",");
265 strcat(msg_flags, "ERROR");
266 }
267}
268
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600269// DebugReport utility callback functions
270static void VKAPI StringCallback(
271 VkFlags msgFlags,
Tony Barbourde4124d2015-07-03 10:33:54 -0600272 VkDbgObjectType objType,
273 uint64_t srcObject,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600274 size_t location,
275 int32_t msgCode,
276 const char* pLayerPrefix,
277 const char* pMsg,
278 void* pUserData)
279{
Jon Ashburncab27b32015-06-30 14:44:13 -0700280 size_t buf_size;
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600281 char *buf;
282 char msg_flags[30];
283 PFN_stringCallback callback = (PFN_stringCallback) pUserData;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600284
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600285 print_msg_flags(msgFlags, msg_flags);
286
287 buf_size = strlen(msg_flags) + /* ReportFlags: i.e. (DEBUG,INFO,WARN,PERF,ERROR) */
288 20 + /* objType */
289 20 + /* srcObject */
290 20 + /* location */
291 20 + /* msgCode */
292 strlen(pLayerPrefix) +
293 strlen(pMsg) +
294 50 /* other / whitespace */;
Tony Barbour69698512015-06-18 16:29:32 -0600295#ifdef WIN32
296 buf = _alloca(buf_size);
297#else
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600298 buf = alloca(buf_size);
Tony Barbour69698512015-06-18 16:29:32 -0600299#endif
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600300 snprintf(buf, buf_size, "%s (%s): object: 0x%" PRIxLEAST64 " type: %d location: %zu msgCode: %d: %s",
301 pLayerPrefix, msg_flags, srcObject, objType, location, msgCode, pMsg);
302 callback(buf);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600303}
304
305static void VKAPI StdioCallback(
306 VkFlags msgFlags,
Tony Barbourde4124d2015-07-03 10:33:54 -0600307 VkDbgObjectType objType,
308 uint64_t srcObject,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600309 size_t location,
310 int32_t msgCode,
311 const char* pLayerPrefix,
312 const char* pMsg,
313 void* pUserData)
314{
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600315 char msg_flags[30];
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600316
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600317 print_msg_flags(msgFlags, msg_flags);
318
319 fprintf((FILE *) pUserData, "%s(%s): object: 0x%" PRIxLEAST64 " type: %d location: %zu msgCode: %d: %s",
320 pLayerPrefix, msg_flags, srcObject, objType, location, msgCode, pMsg);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600321}
322
323static void VKAPI BreakCallback(
324 VkFlags msgFlags,
Tony Barbourde4124d2015-07-03 10:33:54 -0600325 VkDbgObjectType objType,
326 uint64_t srcObject,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600327 size_t location,
328 int32_t msgCode,
329 const char* pLayerPrefix,
330 const char* pMsg,
331 void* pUserData)
332{
Courtney Goeltzenleuchterc3c1f012015-07-22 11:01:53 -0600333#ifndef WIN32
334 raise(SIGTRAP);
335#else
336 DebugBreak();
337#endif
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600338}
339
340void *debug_report_instance_gpa(
341 struct loader_instance *ptr_instance,
342 const char* name)
343{
344 if (ptr_instance == VK_NULL_HANDLE || !ptr_instance->debug_report_enabled)
345 return NULL;
346
347 if (!strcmp("vkDbgCreateMsgCallback", name))
348 return (void *) debug_report_DbgCreateMsgCallback;
349 else if (!strcmp("vkDbgDestroyMsgCallback", name))
350 return (void *) debug_report_DbgDestroyMsgCallback;
Jon Ashburnb843f0b2015-05-26 13:56:43 -0600351 else if (!strcmp("vkDbgStringCallback", name))
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600352 return (void *) StringCallback;
Jon Ashburnb843f0b2015-05-26 13:56:43 -0600353 else if (!strcmp("vkDbgStdioCallback", name))
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600354 return (void *) StdioCallback;
Jon Ashburnb843f0b2015-05-26 13:56:43 -0600355 else if (!strcmp("vkDbgBreakCallback", name))
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600356 return (void *) BreakCallback;
357
358 return NULL;
359}