blob: 3ab70e6f8fe14b2ecadd331c48c9e132727567d7 [file] [log] [blame]
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001/*
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002 *
Courtney Goeltzenleuchterfcbe16f2015-10-29 13:50:34 -06003 * Copyright (C) 2015 Valve Corporation
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 * Jon Ashburn <jon@lunarg.com>
25 * Courtney Goeltzenleuchter <courtney@lunarg.com>
26 */
27
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -060028#define _GNU_SOURCE
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -060029#include <stdio.h>
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060030#include <string.h>
31#include <stdlib.h>
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -060032#include <inttypes.h>
Tony Barbour1d825c72015-06-18 16:29:32 -060033#ifndef WIN32
Courtney Goeltzenleuchter03663d02015-07-22 11:01:53 -060034#include <signal.h>
35#else
Tony Barbour1d825c72015-06-18 16:29:32 -060036#endif
Jon Ashburn480a50a2015-08-28 14:58:46 -070037#include "vk_loader_platform.h"
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060038#include "debug_report.h"
Tobin Ehlis0c6f9ee2015-07-03 09:42:57 -060039#include "vk_layer.h"
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060040
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -060041typedef void (VKAPI *PFN_stringCallback)(char *message);
42
Jon Ashburn5c042ea2015-08-04 11:14:18 -060043static const VkExtensionProperties debug_report_extension_info = {
Chia-I Wu3432a0c2015-10-27 18:04:07 +080044 .extensionName = VK_DEBUG_REPORT_EXTENSION_NAME,
Ian Elliott464e0b52015-09-04 14:14:35 -060045 .specVersion = VK_DEBUG_REPORT_EXTENSION_REVISION,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060046};
47
48void debug_report_add_instance_extensions(
Jon Ashburne39a4f82015-08-28 13:38:21 -060049 const struct loader_instance *inst,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060050 struct loader_extension_list *ext_list)
51{
Jon Ashburne39a4f82015-08-28 13:38:21 -060052 loader_add_to_ext_list(inst, ext_list, 1, &debug_report_extension_info);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060053}
54
55void debug_report_create_instance(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060056 struct loader_instance *ptr_instance,
57 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060058{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060059 ptr_instance->debug_report_enabled = false;
60
Chia-I Wud50a7d72015-10-26 20:48:51 +080061 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionNameCount; i++) {
Courtney Goeltzenleuchter05159a92015-07-30 11:32:46 -060062 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_DEBUG_REPORT_EXTENSION_NAME) == 0) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060063 ptr_instance->debug_report_enabled = true;
64 return;
65 }
66 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060067}
68
69static VkResult debug_report_DbgCreateMsgCallback(
70 VkInstance instance,
71 VkFlags msgFlags,
72 const PFN_vkDbgMsgCallback pfnMsgCallback,
73 void* pUserData,
74 VkDbgMsgCallback* pMsgCallback)
75{
Chia-I Wu3432a0c2015-10-27 18:04:07 +080076 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *) loader_heap_alloc((struct loader_instance *)instance, sizeof(VkLayerDbgFunctionNode), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060077 if (!pNewDbgFuncNode)
78 return VK_ERROR_OUT_OF_HOST_MEMORY;
79
Jon Ashburne0e64572015-09-30 12:56:42 -060080 struct loader_instance *inst = loader_get_instance(instance);
Jon Ashburn6301a0f2015-05-29 13:15:39 -060081 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060082 VkResult result = inst->disp->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
83 if (result == VK_SUCCESS) {
84 pNewDbgFuncNode->msgCallback = *pMsgCallback;
85 pNewDbgFuncNode->pfnMsgCallback = pfnMsgCallback;
86 pNewDbgFuncNode->msgFlags = msgFlags;
87 pNewDbgFuncNode->pUserData = pUserData;
88 pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
89 inst->DbgFunctionHead = pNewDbgFuncNode;
90 } else {
Jon Ashburne39a4f82015-08-28 13:38:21 -060091 loader_heap_free((struct loader_instance *) instance, pNewDbgFuncNode);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060092 }
Jon Ashburn6301a0f2015-05-29 13:15:39 -060093 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060094 return result;
95}
96
97static VkResult debug_report_DbgDestroyMsgCallback(
98 VkInstance instance,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060099 VkDbgMsgCallback msg_callback)
100{
Jon Ashburne0e64572015-09-30 12:56:42 -0600101 struct loader_instance *inst = loader_get_instance(instance);
Jon Ashburn6301a0f2015-05-29 13:15:39 -0600102 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600103 VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
104 VkLayerDbgFunctionNode *pPrev = pTrav;
105
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -0600106 VkResult result = inst->disp->DbgDestroyMsgCallback(instance, msg_callback);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600107
108 while (pTrav) {
Chia-I Wue2fc5522015-10-26 20:04:44 +0800109 if (pTrav->msgCallback == msg_callback) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600110 pPrev->pNext = pTrav->pNext;
111 if (inst->DbgFunctionHead == pTrav)
112 inst->DbgFunctionHead = pTrav->pNext;
Jon Ashburne39a4f82015-08-28 13:38:21 -0600113 loader_heap_free((struct loader_instance *) instance, pTrav);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600114 break;
115 }
116 pPrev = pTrav;
117 pTrav = pTrav->pNext;
118 }
119
Jon Ashburn6301a0f2015-05-29 13:15:39 -0600120 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600121 return result;
122}
123
124
125/*
126 * This is the instance chain terminator function
127 * for DbgCreateMsgCallback
128 */
Tony Barbour1d2cd3f2015-07-03 10:33:54 -0600129
Dan Ginsburg78556e82015-07-23 13:15:00 -0400130VkResult VKAPI loader_DbgCreateMsgCallback(
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600131 VkInstance instance,
132 VkFlags msgFlags,
133 const PFN_vkDbgMsgCallback pfnMsgCallback,
Jon Ashburne67741a2015-08-06 13:56:43 -0600134 void* pUserData,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600135 VkDbgMsgCallback* pMsgCallback)
136{
137 VkDbgMsgCallback *icd_info;
138 const struct loader_icd *icd;
139 struct loader_instance *inst;
140 VkResult res;
141 uint32_t storage_idx;
142
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600143 for (inst = loader.instances; inst; inst = inst->next) {
144 if ((VkInstance) inst == instance)
145 break;
146 }
147
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600148 icd_info = calloc(sizeof(VkDbgMsgCallback), inst->total_icd_count);
149 if (!icd_info) {
150 return VK_ERROR_OUT_OF_HOST_MEMORY;
151 }
152
153 storage_idx = 0;
154 for (icd = inst->icds; icd; icd = icd->next) {
155 if (!icd->DbgCreateMsgCallback) {
156 continue;
157 }
158
159 res = icd->DbgCreateMsgCallback(
160 icd->instance,
161 msgFlags,
162 pfnMsgCallback,
163 pUserData,
164 &icd_info[storage_idx]);
165
166 if (res != VK_SUCCESS) {
167 break;
168 }
169 storage_idx++;
170 }
171
172 /* roll back on errors */
173 if (icd) {
174 storage_idx = 0;
175 for (icd = inst->icds; icd; icd = icd->next) {
Chia-I Wue2fc5522015-10-26 20:04:44 +0800176 if (icd_info[storage_idx]) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600177 icd->DbgDestroyMsgCallback(
178 icd->instance,
179 icd_info[storage_idx]);
180 }
181 storage_idx++;
182 }
183
184 return res;
185 }
186
Tony Barbour1d2cd3f2015-07-03 10:33:54 -0600187 *(VkDbgMsgCallback **)pMsgCallback = icd_info;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600188
189 return VK_SUCCESS;
190}
191
192/*
193 * This is the instance chain terminator function
194 * for DbgDestroyMsgCallback
195 */
Dan Ginsburg78556e82015-07-23 13:15:00 -0400196VkResult VKAPI loader_DbgDestroyMsgCallback(
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600197 VkInstance instance,
198 VkDbgMsgCallback msgCallback)
199{
200 uint32_t storage_idx;
201 VkDbgMsgCallback *icd_info;
202 const struct loader_icd *icd;
203 VkResult res = VK_SUCCESS;
204 struct loader_instance *inst;
205
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600206 for (inst = loader.instances; inst; inst = inst->next) {
207 if ((VkInstance) inst == instance)
208 break;
209 }
210
Tony Barbour1d2cd3f2015-07-03 10:33:54 -0600211 icd_info = *(VkDbgMsgCallback **) &msgCallback;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600212 storage_idx = 0;
213 for (icd = inst->icds; icd; icd = icd->next) {
Chia-I Wue2fc5522015-10-26 20:04:44 +0800214 if (icd_info[storage_idx]) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600215 icd->DbgDestroyMsgCallback(
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -0600216 icd->instance,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600217 icd_info[storage_idx]);
218 }
219 storage_idx++;
220 }
221 return res;
222}
223
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600224static void print_msg_flags(VkFlags msgFlags, char *msg_flags)
225{
226 bool separator = false;
227
228 msg_flags[0] = 0;
229 if (msgFlags & VK_DBG_REPORT_DEBUG_BIT) {
230 strcat(msg_flags, "DEBUG");
231 separator = true;
232 }
233 if (msgFlags & VK_DBG_REPORT_INFO_BIT) {
234 if (separator) strcat(msg_flags, ",");
235 strcat(msg_flags, "INFO");
236 separator = true;
237 }
238 if (msgFlags & VK_DBG_REPORT_WARN_BIT) {
239 if (separator) strcat(msg_flags, ",");
240 strcat(msg_flags, "WARN");
241 separator = true;
242 }
243 if (msgFlags & VK_DBG_REPORT_PERF_WARN_BIT) {
244 if (separator) strcat(msg_flags, ",");
245 strcat(msg_flags, "PERF");
246 separator = true;
247 }
248 if (msgFlags & VK_DBG_REPORT_ERROR_BIT) {
249 if (separator) strcat(msg_flags, ",");
250 strcat(msg_flags, "ERROR");
251 }
252}
253
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600254// DebugReport utility callback functions
255static void VKAPI StringCallback(
256 VkFlags msgFlags,
Tony Barbour1d2cd3f2015-07-03 10:33:54 -0600257 VkDbgObjectType objType,
258 uint64_t srcObject,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600259 size_t location,
260 int32_t msgCode,
261 const char* pLayerPrefix,
262 const char* pMsg,
263 void* pUserData)
264{
Jon Ashburn7242c672015-06-30 14:44:13 -0700265 size_t buf_size;
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600266 char *buf;
267 char msg_flags[30];
268 PFN_stringCallback callback = (PFN_stringCallback) pUserData;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600269
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600270 print_msg_flags(msgFlags, msg_flags);
271
272 buf_size = strlen(msg_flags) + /* ReportFlags: i.e. (DEBUG,INFO,WARN,PERF,ERROR) */
273 20 + /* objType */
274 20 + /* srcObject */
275 20 + /* location */
276 20 + /* msgCode */
277 strlen(pLayerPrefix) +
278 strlen(pMsg) +
279 50 /* other / whitespace */;
Jon Ashburn48091a32015-08-27 13:06:58 -0600280 buf = loader_stack_alloc(buf_size);
281
Courtney Goeltzenleuchter22d8d792015-10-07 17:03:42 -0600282 snprintf(buf, buf_size, "%s (%s): object: 0x%" PRIxLEAST64 " type: %d location: " PRINTF_SIZE_T_SPECIFIER " msgCode : %d : %s",
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600283 pLayerPrefix, msg_flags, srcObject, objType, location, msgCode, pMsg);
284 callback(buf);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600285}
286
287static void VKAPI StdioCallback(
288 VkFlags msgFlags,
Tony Barbour1d2cd3f2015-07-03 10:33:54 -0600289 VkDbgObjectType objType,
290 uint64_t srcObject,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600291 size_t location,
292 int32_t msgCode,
293 const char* pLayerPrefix,
294 const char* pMsg,
295 void* pUserData)
296{
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600297 char msg_flags[30];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600298
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600299 print_msg_flags(msgFlags, msg_flags);
300
Courtney Goeltzenleuchter22d8d792015-10-07 17:03:42 -0600301 fprintf((FILE *)pUserData, "%s(%s): object: 0x%" PRIxLEAST64 " type: %d location: " PRINTF_SIZE_T_SPECIFIER " msgCode : %d : %s",
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600302 pLayerPrefix, msg_flags, srcObject, objType, location, msgCode, pMsg);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600303}
304
305static void VKAPI BreakCallback(
306 VkFlags msgFlags,
Tony Barbour1d2cd3f2015-07-03 10:33:54 -0600307 VkDbgObjectType objType,
308 uint64_t srcObject,
Courtney Goeltzenleuchterf579fa62015-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 Goeltzenleuchter03663d02015-07-22 11:01:53 -0600315#ifndef WIN32
316 raise(SIGTRAP);
317#else
318 DebugBreak();
319#endif
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600320}
321
Jon Ashburnf7a48db2015-10-01 12:03:17 -0600322bool debug_report_instance_gpa(
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600323 struct loader_instance *ptr_instance,
Jon Ashburnf7a48db2015-10-01 12:03:17 -0600324 const char* name,
325 void **addr)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600326{
Jon Ashburnf7a48db2015-10-01 12:03:17 -0600327 *addr = NULL;
328 if (ptr_instance == VK_NULL_HANDLE)
329 return false;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600330
Jon Ashburnf7a48db2015-10-01 12:03:17 -0600331 if (!strcmp("vkDbgCreateMsgCallback", name)) {
332 *addr = ptr_instance->debug_report_enabled ? (void *) debug_report_DbgCreateMsgCallback : NULL;
333 return true;
334 }
335 if (!strcmp("vkDbgDestroyMsgCallback", name)) {
336 *addr = ptr_instance->debug_report_enabled ? (void *) debug_report_DbgDestroyMsgCallback : NULL;
337 return true;
338 }
339 if (!strcmp("vkDbgStringCallback", name)) {
340 *addr = ptr_instance->debug_report_enabled ? (void *) StringCallback : NULL;
341 return true;
342 }
343 if (!strcmp("vkDbgStdioCallback", name)) {
344 *addr = ptr_instance->debug_report_enabled ? (void *) StdioCallback : NULL;
345 return true;
346 }
347 if (!strcmp("vkDbgBreakCallback", name)) {
348 *addr = ptr_instance->debug_report_enabled ? (void *) BreakCallback : NULL;
349 return true;
350 }
351 return false;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600352}