blob: f73929addbf900cc00e02e859b4ec2321dcd67b1 [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
Jon Ashburn6fb9a532015-08-28 14:58:46 -070038#include "vk_loader_platform.h"
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
Jon Ashburnc4748dc2015-08-04 11:14:18 -060044static const VkExtensionProperties debug_report_extension_info = {
Courtney Goeltzenleuchter846298c2015-07-30 11:32:46 -060045 .extName = VK_DEBUG_REPORT_EXTENSION_NAME,
Ian Elliottd5b6e892015-09-04 14:14:35 -060046 .specVersion = VK_DEBUG_REPORT_EXTENSION_REVISION,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060047};
48
49void debug_report_add_instance_extensions(
Jon Ashburne58f1a32015-08-28 13:38:21 -060050 const struct loader_instance *inst,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060051 struct loader_extension_list *ext_list)
52{
Jon Ashburne58f1a32015-08-28 13:38:21 -060053 loader_add_to_ext_list(inst, ext_list, 1, &debug_report_extension_info);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060054}
55
56void debug_report_create_instance(
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -060057 struct loader_instance *ptr_instance,
58 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060059{
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -060060 ptr_instance->debug_report_enabled = false;
61
62 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
Courtney Goeltzenleuchter846298c2015-07-30 11:32:46 -060063 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_DEBUG_REPORT_EXTENSION_NAME) == 0) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -060064 ptr_instance->debug_report_enabled = true;
65 return;
66 }
67 }
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060068}
69
70static VkResult debug_report_DbgCreateMsgCallback(
71 VkInstance instance,
72 VkFlags msgFlags,
73 const PFN_vkDbgMsgCallback pfnMsgCallback,
74 void* pUserData,
75 VkDbgMsgCallback* pMsgCallback)
76{
Jon Ashburne58f1a32015-08-28 13:38:21 -060077 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *) loader_heap_alloc((struct loader_instance *)instance, sizeof(VkLayerDbgFunctionNode), VK_SYSTEM_ALLOC_TYPE_INTERNAL);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060078 if (!pNewDbgFuncNode)
79 return VK_ERROR_OUT_OF_HOST_MEMORY;
80
Jon Ashburn0c5eea22015-09-30 12:56:42 -060081 struct loader_instance *inst = loader_get_instance(instance);
Jon Ashburnb40f2562015-05-29 13:15:39 -060082 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060083 VkResult result = inst->disp->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
84 if (result == VK_SUCCESS) {
85 pNewDbgFuncNode->msgCallback = *pMsgCallback;
86 pNewDbgFuncNode->pfnMsgCallback = pfnMsgCallback;
87 pNewDbgFuncNode->msgFlags = msgFlags;
88 pNewDbgFuncNode->pUserData = pUserData;
89 pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
90 inst->DbgFunctionHead = pNewDbgFuncNode;
91 } else {
Jon Ashburne58f1a32015-08-28 13:38:21 -060092 loader_heap_free((struct loader_instance *) instance, pNewDbgFuncNode);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060093 }
Jon Ashburnb40f2562015-05-29 13:15:39 -060094 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060095 return result;
96}
97
98static VkResult debug_report_DbgDestroyMsgCallback(
99 VkInstance instance,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600100 VkDbgMsgCallback msg_callback)
101{
Jon Ashburn0c5eea22015-09-30 12:56:42 -0600102 struct loader_instance *inst = loader_get_instance(instance);
Jon Ashburnb40f2562015-05-29 13:15:39 -0600103 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600104 VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
105 VkLayerDbgFunctionNode *pPrev = pTrav;
106
Courtney Goeltzenleuchter3d8dc1f2015-06-08 15:09:22 -0600107 VkResult result = inst->disp->DbgDestroyMsgCallback(instance, msg_callback);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600108
109 while (pTrav) {
Tony Barbourde4124d2015-07-03 10:33:54 -0600110 if (pTrav->msgCallback.handle == msg_callback.handle) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600111 pPrev->pNext = pTrav->pNext;
112 if (inst->DbgFunctionHead == pTrav)
113 inst->DbgFunctionHead = pTrav->pNext;
Jon Ashburne58f1a32015-08-28 13:38:21 -0600114 loader_heap_free((struct loader_instance *) instance, pTrav);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600115 break;
116 }
117 pPrev = pTrav;
118 pTrav = pTrav->pNext;
119 }
120
Jon Ashburnb40f2562015-05-29 13:15:39 -0600121 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600122 return result;
123}
124
125
126/*
127 * This is the instance chain terminator function
128 * for DbgCreateMsgCallback
129 */
Tony Barbourde4124d2015-07-03 10:33:54 -0600130
Dan Ginsburgf99e4102015-07-23 13:15:00 -0400131VkResult VKAPI loader_DbgCreateMsgCallback(
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600132 VkInstance instance,
133 VkFlags msgFlags,
134 const PFN_vkDbgMsgCallback pfnMsgCallback,
Jon Ashburnf9136f42015-08-06 13:56:43 -0600135 void* pUserData,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600136 VkDbgMsgCallback* pMsgCallback)
137{
138 VkDbgMsgCallback *icd_info;
139 const struct loader_icd *icd;
140 struct loader_instance *inst;
141 VkResult res;
142 uint32_t storage_idx;
143
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600144 for (inst = loader.instances; inst; inst = inst->next) {
145 if ((VkInstance) inst == instance)
146 break;
147 }
148
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600149 icd_info = calloc(sizeof(VkDbgMsgCallback), inst->total_icd_count);
150 if (!icd_info) {
151 return VK_ERROR_OUT_OF_HOST_MEMORY;
152 }
153
154 storage_idx = 0;
155 for (icd = inst->icds; icd; icd = icd->next) {
156 if (!icd->DbgCreateMsgCallback) {
157 continue;
158 }
159
160 res = icd->DbgCreateMsgCallback(
161 icd->instance,
162 msgFlags,
163 pfnMsgCallback,
164 pUserData,
165 &icd_info[storage_idx]);
166
167 if (res != VK_SUCCESS) {
168 break;
169 }
170 storage_idx++;
171 }
172
173 /* roll back on errors */
174 if (icd) {
175 storage_idx = 0;
176 for (icd = inst->icds; icd; icd = icd->next) {
Tony Barbourde4124d2015-07-03 10:33:54 -0600177 if (icd_info[storage_idx].handle) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600178 icd->DbgDestroyMsgCallback(
179 icd->instance,
180 icd_info[storage_idx]);
181 }
182 storage_idx++;
183 }
184
185 return res;
186 }
187
Tony Barbourde4124d2015-07-03 10:33:54 -0600188 *(VkDbgMsgCallback **)pMsgCallback = icd_info;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600189
190 return VK_SUCCESS;
191}
192
193/*
194 * This is the instance chain terminator function
195 * for DbgDestroyMsgCallback
196 */
Dan Ginsburgf99e4102015-07-23 13:15:00 -0400197VkResult VKAPI loader_DbgDestroyMsgCallback(
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600198 VkInstance instance,
199 VkDbgMsgCallback msgCallback)
200{
201 uint32_t storage_idx;
202 VkDbgMsgCallback *icd_info;
203 const struct loader_icd *icd;
204 VkResult res = VK_SUCCESS;
205 struct loader_instance *inst;
206
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600207 for (inst = loader.instances; inst; inst = inst->next) {
208 if ((VkInstance) inst == instance)
209 break;
210 }
211
Tony Barbourde4124d2015-07-03 10:33:54 -0600212 icd_info = *(VkDbgMsgCallback **) &msgCallback;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600213 storage_idx = 0;
214 for (icd = inst->icds; icd; icd = icd->next) {
Tony Barbourde4124d2015-07-03 10:33:54 -0600215 if (icd_info[storage_idx].handle) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600216 icd->DbgDestroyMsgCallback(
Courtney Goeltzenleuchter3d8dc1f2015-06-08 15:09:22 -0600217 icd->instance,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600218 icd_info[storage_idx]);
219 }
220 storage_idx++;
221 }
222 return res;
223}
224
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600225static void print_msg_flags(VkFlags msgFlags, char *msg_flags)
226{
227 bool separator = false;
228
229 msg_flags[0] = 0;
230 if (msgFlags & VK_DBG_REPORT_DEBUG_BIT) {
231 strcat(msg_flags, "DEBUG");
232 separator = true;
233 }
234 if (msgFlags & VK_DBG_REPORT_INFO_BIT) {
235 if (separator) strcat(msg_flags, ",");
236 strcat(msg_flags, "INFO");
237 separator = true;
238 }
239 if (msgFlags & VK_DBG_REPORT_WARN_BIT) {
240 if (separator) strcat(msg_flags, ",");
241 strcat(msg_flags, "WARN");
242 separator = true;
243 }
244 if (msgFlags & VK_DBG_REPORT_PERF_WARN_BIT) {
245 if (separator) strcat(msg_flags, ",");
246 strcat(msg_flags, "PERF");
247 separator = true;
248 }
249 if (msgFlags & VK_DBG_REPORT_ERROR_BIT) {
250 if (separator) strcat(msg_flags, ",");
251 strcat(msg_flags, "ERROR");
252 }
253}
254
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600255// DebugReport utility callback functions
256static void VKAPI StringCallback(
257 VkFlags msgFlags,
Tony Barbourde4124d2015-07-03 10:33:54 -0600258 VkDbgObjectType objType,
259 uint64_t srcObject,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600260 size_t location,
261 int32_t msgCode,
262 const char* pLayerPrefix,
263 const char* pMsg,
264 void* pUserData)
265{
Jon Ashburncab27b32015-06-30 14:44:13 -0700266 size_t buf_size;
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600267 char *buf;
268 char msg_flags[30];
269 PFN_stringCallback callback = (PFN_stringCallback) pUserData;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600270
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600271 print_msg_flags(msgFlags, msg_flags);
272
273 buf_size = strlen(msg_flags) + /* ReportFlags: i.e. (DEBUG,INFO,WARN,PERF,ERROR) */
274 20 + /* objType */
275 20 + /* srcObject */
276 20 + /* location */
277 20 + /* msgCode */
278 strlen(pLayerPrefix) +
279 strlen(pMsg) +
280 50 /* other / whitespace */;
Jon Ashburne5c48722015-08-27 13:06:58 -0600281 buf = loader_stack_alloc(buf_size);
282
Courtney Goeltzenleuchterb5738ca2015-10-07 17:03:42 -0600283 snprintf(buf, buf_size, "%s (%s): object: 0x%" PRIxLEAST64 " type: %d location: " PRINTF_SIZE_T_SPECIFIER " msgCode : %d : %s",
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600284 pLayerPrefix, msg_flags, srcObject, objType, location, msgCode, pMsg);
285 callback(buf);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600286}
287
288static void VKAPI StdioCallback(
289 VkFlags msgFlags,
Tony Barbourde4124d2015-07-03 10:33:54 -0600290 VkDbgObjectType objType,
291 uint64_t srcObject,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600292 size_t location,
293 int32_t msgCode,
294 const char* pLayerPrefix,
295 const char* pMsg,
296 void* pUserData)
297{
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600298 char msg_flags[30];
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600299
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600300 print_msg_flags(msgFlags, msg_flags);
301
Courtney Goeltzenleuchterb5738ca2015-10-07 17:03:42 -0600302 fprintf((FILE *)pUserData, "%s(%s): object: 0x%" PRIxLEAST64 " type: %d location: " PRINTF_SIZE_T_SPECIFIER " msgCode : %d : %s",
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600303 pLayerPrefix, msg_flags, srcObject, objType, location, msgCode, pMsg);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600304}
305
306static void VKAPI BreakCallback(
307 VkFlags msgFlags,
Tony Barbourde4124d2015-07-03 10:33:54 -0600308 VkDbgObjectType objType,
309 uint64_t srcObject,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600310 size_t location,
311 int32_t msgCode,
312 const char* pLayerPrefix,
313 const char* pMsg,
314 void* pUserData)
315{
Courtney Goeltzenleuchterc3c1f012015-07-22 11:01:53 -0600316#ifndef WIN32
317 raise(SIGTRAP);
318#else
319 DebugBreak();
320#endif
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600321}
322
Jon Ashburn05b4ec62015-10-01 12:03:17 -0600323bool debug_report_instance_gpa(
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600324 struct loader_instance *ptr_instance,
Jon Ashburn05b4ec62015-10-01 12:03:17 -0600325 const char* name,
326 void **addr)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600327{
Jon Ashburn05b4ec62015-10-01 12:03:17 -0600328 *addr = NULL;
329 if (ptr_instance == VK_NULL_HANDLE)
330 return false;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600331
Jon Ashburn05b4ec62015-10-01 12:03:17 -0600332 if (!strcmp("vkDbgCreateMsgCallback", name)) {
333 *addr = ptr_instance->debug_report_enabled ? (void *) debug_report_DbgCreateMsgCallback : NULL;
334 return true;
335 }
336 if (!strcmp("vkDbgDestroyMsgCallback", name)) {
337 *addr = ptr_instance->debug_report_enabled ? (void *) debug_report_DbgDestroyMsgCallback : NULL;
338 return true;
339 }
340 if (!strcmp("vkDbgStringCallback", name)) {
341 *addr = ptr_instance->debug_report_enabled ? (void *) StringCallback : NULL;
342 return true;
343 }
344 if (!strcmp("vkDbgStdioCallback", name)) {
345 *addr = ptr_instance->debug_report_enabled ? (void *) StdioCallback : NULL;
346 return true;
347 }
348 if (!strcmp("vkDbgBreakCallback", name)) {
349 *addr = ptr_instance->debug_report_enabled ? (void *) BreakCallback : NULL;
350 return true;
351 }
352 return false;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600353}