blob: 4d6314a9bb33e6ba53032f11fdaccdb07e2b6c45 [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>
Tony Barbour69698512015-06-18 16:29:32 -060036#endif
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060037#include "debug_report.h"
Tobin Ehlis2d1d9702015-07-03 09:42:57 -060038#include "vk_layer.h"
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060039
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -060040typedef void (VKAPI *PFN_stringCallback)(char *message);
41
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060042static const struct loader_extension_property debug_report_extension_info = {
43 .info = {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -060044 .extName = DEBUG_REPORT_EXTENSION_NAME,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060045 .version = VK_DEBUG_REPORT_EXTENSION_VERSION,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -060046 .specVersion = VK_API_VERSION,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060047 },
48 .origin = VK_EXTENSION_ORIGIN_LOADER,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060049};
50
51void debug_report_add_instance_extensions(
52 struct loader_extension_list *ext_list)
53{
54 loader_add_to_ext_list(ext_list, 1, &debug_report_extension_info);
55}
56
57void debug_report_create_instance(
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -060058 struct loader_instance *ptr_instance,
59 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060060{
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -060061 ptr_instance->debug_report_enabled = false;
62
63 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
64 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], DEBUG_REPORT_EXTENSION_NAME) == 0) {
65 ptr_instance->debug_report_enabled = true;
66 return;
67 }
68 }
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060069}
70
71static VkResult debug_report_DbgCreateMsgCallback(
72 VkInstance instance,
73 VkFlags msgFlags,
74 const PFN_vkDbgMsgCallback pfnMsgCallback,
75 void* pUserData,
76 VkDbgMsgCallback* pMsgCallback)
77{
78 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *) malloc(sizeof(VkLayerDbgFunctionNode));
79 if (!pNewDbgFuncNode)
80 return VK_ERROR_OUT_OF_HOST_MEMORY;
81
Courtney Goeltzenleuchter8afefb52015-06-08 15:04:02 -060082 struct loader_instance *inst = loader_instance(instance);
Jon Ashburnb40f2562015-05-29 13:15:39 -060083 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060084 VkResult result = inst->disp->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
85 if (result == VK_SUCCESS) {
86 pNewDbgFuncNode->msgCallback = *pMsgCallback;
87 pNewDbgFuncNode->pfnMsgCallback = pfnMsgCallback;
88 pNewDbgFuncNode->msgFlags = msgFlags;
89 pNewDbgFuncNode->pUserData = pUserData;
90 pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
91 inst->DbgFunctionHead = pNewDbgFuncNode;
92 } else {
93 free(pNewDbgFuncNode);
94 }
Jon Ashburnb40f2562015-05-29 13:15:39 -060095 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060096 return result;
97}
98
99static VkResult debug_report_DbgDestroyMsgCallback(
100 VkInstance instance,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600101 VkDbgMsgCallback msg_callback)
102{
Courtney Goeltzenleuchter8afefb52015-06-08 15:04:02 -0600103 struct loader_instance *inst = loader_instance(instance);
Jon Ashburnb40f2562015-05-29 13:15:39 -0600104 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600105 VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
106 VkLayerDbgFunctionNode *pPrev = pTrav;
107
Courtney Goeltzenleuchter3d8dc1f2015-06-08 15:09:22 -0600108 VkResult result = inst->disp->DbgDestroyMsgCallback(instance, msg_callback);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600109
110 while (pTrav) {
Tony Barbourde4124d2015-07-03 10:33:54 -0600111 if (pTrav->msgCallback.handle == msg_callback.handle) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600112 pPrev->pNext = pTrav->pNext;
113 if (inst->DbgFunctionHead == pTrav)
114 inst->DbgFunctionHead = pTrav->pNext;
115 free(pTrav);
116 break;
117 }
118 pPrev = pTrav;
119 pTrav = pTrav->pNext;
120 }
121
Jon Ashburnb40f2562015-05-29 13:15:39 -0600122 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600123 return result;
124}
125
126
127/*
128 * This is the instance chain terminator function
129 * for DbgCreateMsgCallback
130 */
Tony Barbourde4124d2015-07-03 10:33:54 -0600131
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600132VkResult loader_DbgCreateMsgCallback(
133 VkInstance instance,
134 VkFlags msgFlags,
135 const PFN_vkDbgMsgCallback pfnMsgCallback,
136 const void* pUserData,
137 VkDbgMsgCallback* pMsgCallback)
138{
139 VkDbgMsgCallback *icd_info;
140 const struct loader_icd *icd;
141 struct loader_instance *inst;
142 VkResult res;
143 uint32_t storage_idx;
144
145 if (instance == VK_NULL_HANDLE)
146 return VK_ERROR_INVALID_HANDLE;
147
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600148 for (inst = loader.instances; inst; inst = inst->next) {
149 if ((VkInstance) inst == instance)
150 break;
151 }
152
153 if (inst == VK_NULL_HANDLE)
154 return VK_ERROR_INVALID_HANDLE;
155
156 icd_info = calloc(sizeof(VkDbgMsgCallback), inst->total_icd_count);
157 if (!icd_info) {
158 return VK_ERROR_OUT_OF_HOST_MEMORY;
159 }
160
161 storage_idx = 0;
162 for (icd = inst->icds; icd; icd = icd->next) {
163 if (!icd->DbgCreateMsgCallback) {
164 continue;
165 }
166
167 res = icd->DbgCreateMsgCallback(
168 icd->instance,
169 msgFlags,
170 pfnMsgCallback,
171 pUserData,
172 &icd_info[storage_idx]);
173
174 if (res != VK_SUCCESS) {
175 break;
176 }
177 storage_idx++;
178 }
179
180 /* roll back on errors */
181 if (icd) {
182 storage_idx = 0;
183 for (icd = inst->icds; icd; icd = icd->next) {
Tony Barbourde4124d2015-07-03 10:33:54 -0600184 if (icd_info[storage_idx].handle) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600185 icd->DbgDestroyMsgCallback(
186 icd->instance,
187 icd_info[storage_idx]);
188 }
189 storage_idx++;
190 }
191
192 return res;
193 }
194
Tony Barbourde4124d2015-07-03 10:33:54 -0600195 *(VkDbgMsgCallback **)pMsgCallback = icd_info;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600196
197 return VK_SUCCESS;
198}
199
200/*
201 * This is the instance chain terminator function
202 * for DbgDestroyMsgCallback
203 */
204VkResult loader_DbgDestroyMsgCallback(
205 VkInstance instance,
206 VkDbgMsgCallback msgCallback)
207{
208 uint32_t storage_idx;
209 VkDbgMsgCallback *icd_info;
210 const struct loader_icd *icd;
211 VkResult res = VK_SUCCESS;
212 struct loader_instance *inst;
213
214 if (instance == VK_NULL_HANDLE)
215 return VK_ERROR_INVALID_HANDLE;
216
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600217 for (inst = loader.instances; inst; inst = inst->next) {
218 if ((VkInstance) inst == instance)
219 break;
220 }
221
222 if (inst == VK_NULL_HANDLE)
223 return VK_ERROR_INVALID_HANDLE;
224
Tony Barbourde4124d2015-07-03 10:33:54 -0600225 icd_info = *(VkDbgMsgCallback **) &msgCallback;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600226 storage_idx = 0;
227 for (icd = inst->icds; icd; icd = icd->next) {
Tony Barbourde4124d2015-07-03 10:33:54 -0600228 if (icd_info[storage_idx].handle) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600229 icd->DbgDestroyMsgCallback(
Courtney Goeltzenleuchter3d8dc1f2015-06-08 15:09:22 -0600230 icd->instance,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600231 icd_info[storage_idx]);
232 }
233 storage_idx++;
234 }
235 return res;
236}
237
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600238static void print_msg_flags(VkFlags msgFlags, char *msg_flags)
239{
240 bool separator = false;
241
242 msg_flags[0] = 0;
243 if (msgFlags & VK_DBG_REPORT_DEBUG_BIT) {
244 strcat(msg_flags, "DEBUG");
245 separator = true;
246 }
247 if (msgFlags & VK_DBG_REPORT_INFO_BIT) {
248 if (separator) strcat(msg_flags, ",");
249 strcat(msg_flags, "INFO");
250 separator = true;
251 }
252 if (msgFlags & VK_DBG_REPORT_WARN_BIT) {
253 if (separator) strcat(msg_flags, ",");
254 strcat(msg_flags, "WARN");
255 separator = true;
256 }
257 if (msgFlags & VK_DBG_REPORT_PERF_WARN_BIT) {
258 if (separator) strcat(msg_flags, ",");
259 strcat(msg_flags, "PERF");
260 separator = true;
261 }
262 if (msgFlags & VK_DBG_REPORT_ERROR_BIT) {
263 if (separator) strcat(msg_flags, ",");
264 strcat(msg_flags, "ERROR");
265 }
266}
267
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600268// DebugReport utility callback functions
269static void VKAPI StringCallback(
270 VkFlags msgFlags,
Tony Barbourde4124d2015-07-03 10:33:54 -0600271 VkDbgObjectType objType,
272 uint64_t srcObject,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600273 size_t location,
274 int32_t msgCode,
275 const char* pLayerPrefix,
276 const char* pMsg,
277 void* pUserData)
278{
Jon Ashburncab27b32015-06-30 14:44:13 -0700279 size_t buf_size;
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600280 char *buf;
281 char msg_flags[30];
282 PFN_stringCallback callback = (PFN_stringCallback) pUserData;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600283
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600284 print_msg_flags(msgFlags, msg_flags);
285
286 buf_size = strlen(msg_flags) + /* ReportFlags: i.e. (DEBUG,INFO,WARN,PERF,ERROR) */
287 20 + /* objType */
288 20 + /* srcObject */
289 20 + /* location */
290 20 + /* msgCode */
291 strlen(pLayerPrefix) +
292 strlen(pMsg) +
293 50 /* other / whitespace */;
Tony Barbour69698512015-06-18 16:29:32 -0600294#ifdef WIN32
295 buf = _alloca(buf_size);
296#else
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600297 buf = alloca(buf_size);
Tony Barbour69698512015-06-18 16:29:32 -0600298#endif
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600299 snprintf(buf, buf_size, "%s (%s): object: 0x%" PRIxLEAST64 " type: %d location: %zu msgCode: %d: %s",
300 pLayerPrefix, msg_flags, srcObject, objType, location, msgCode, pMsg);
301 callback(buf);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600302}
303
304static void VKAPI StdioCallback(
305 VkFlags msgFlags,
Tony Barbourde4124d2015-07-03 10:33:54 -0600306 VkDbgObjectType objType,
307 uint64_t srcObject,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600308 size_t location,
309 int32_t msgCode,
310 const char* pLayerPrefix,
311 const char* pMsg,
312 void* pUserData)
313{
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600314 char msg_flags[30];
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600315
Courtney Goeltzenleuchterf1eb2492015-06-11 16:01:11 -0600316 print_msg_flags(msgFlags, msg_flags);
317
318 fprintf((FILE *) pUserData, "%s(%s): object: 0x%" PRIxLEAST64 " type: %d location: %zu msgCode: %d: %s",
319 pLayerPrefix, msg_flags, srcObject, objType, location, msgCode, pMsg);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600320}
321
322static void VKAPI BreakCallback(
323 VkFlags msgFlags,
Tony Barbourde4124d2015-07-03 10:33:54 -0600324 VkDbgObjectType objType,
325 uint64_t srcObject,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600326 size_t location,
327 int32_t msgCode,
328 const char* pLayerPrefix,
329 const char* pMsg,
330 void* pUserData)
331{
332
333}
334
335void *debug_report_instance_gpa(
336 struct loader_instance *ptr_instance,
337 const char* name)
338{
339 if (ptr_instance == VK_NULL_HANDLE || !ptr_instance->debug_report_enabled)
340 return NULL;
341
342 if (!strcmp("vkDbgCreateMsgCallback", name))
343 return (void *) debug_report_DbgCreateMsgCallback;
344 else if (!strcmp("vkDbgDestroyMsgCallback", name))
345 return (void *) debug_report_DbgDestroyMsgCallback;
Jon Ashburnb843f0b2015-05-26 13:56:43 -0600346 else if (!strcmp("vkDbgStringCallback", name))
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600347 return (void *) StringCallback;
Jon Ashburnb843f0b2015-05-26 13:56:43 -0600348 else if (!strcmp("vkDbgStdioCallback", name))
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600349 return (void *) StdioCallback;
Jon Ashburnb843f0b2015-05-26 13:56:43 -0600350 else if (!strcmp("vkDbgBreakCallback", name))
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600351 return (void *) BreakCallback;
352
353 return NULL;
354}