blob: 2ad0782e5b38f05a4876fa7849745d376909fe25 [file] [log] [blame]
Courtney Goeltzenleuchterf579fa62015-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 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 Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -060034#include <alloca.h>
Tony Barbour1d825c72015-06-18 16:29:32 -060035#endif
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060036#include "debug_report.h"
Tobin Ehlis0c6f9ee2015-07-03 09:42:57 -060037#include "vk_layer.h"
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060038
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -060039typedef void (VKAPI *PFN_stringCallback)(char *message);
40
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060041static const struct loader_extension_property debug_report_extension_info = {
42 .info = {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060043 .extName = DEBUG_REPORT_EXTENSION_NAME,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060044 .version = VK_DEBUG_REPORT_EXTENSION_VERSION,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060045 .specVersion = VK_API_VERSION,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060046 },
47 .origin = VK_EXTENSION_ORIGIN_LOADER,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060048};
49
50void debug_report_add_instance_extensions(
51 struct loader_extension_list *ext_list)
52{
53 loader_add_to_ext_list(ext_list, 1, &debug_report_extension_info);
54}
55
56void debug_report_create_instance(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060057 struct loader_instance *ptr_instance,
58 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060059{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060060 ptr_instance->debug_report_enabled = false;
61
62 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
63 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], DEBUG_REPORT_EXTENSION_NAME) == 0) {
64 ptr_instance->debug_report_enabled = true;
65 return;
66 }
67 }
Courtney Goeltzenleuchterf579fa62015-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{
77 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *) malloc(sizeof(VkLayerDbgFunctionNode));
78 if (!pNewDbgFuncNode)
79 return VK_ERROR_OUT_OF_HOST_MEMORY;
80
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -060081 struct loader_instance *inst = loader_instance(instance);
Jon Ashburn6301a0f2015-05-29 13:15:39 -060082 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchterf579fa62015-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 {
92 free(pNewDbgFuncNode);
93 }
Jon Ashburn6301a0f2015-05-29 13:15:39 -060094 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060095 return result;
96}
97
98static VkResult debug_report_DbgDestroyMsgCallback(
99 VkInstance instance,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600100 VkDbgMsgCallback msg_callback)
101{
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -0600102 struct loader_instance *inst = loader_instance(instance);
Jon Ashburn6301a0f2015-05-29 13:15:39 -0600103 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600104 VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
105 VkLayerDbgFunctionNode *pPrev = pTrav;
106
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -0600107 VkResult result = inst->disp->DbgDestroyMsgCallback(instance, msg_callback);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600108
109 while (pTrav) {
110 if (pTrav->msgCallback == msg_callback) {
111 pPrev->pNext = pTrav->pNext;
112 if (inst->DbgFunctionHead == pTrav)
113 inst->DbgFunctionHead = pTrav->pNext;
114 free(pTrav);
115 break;
116 }
117 pPrev = pTrav;
118 pTrav = pTrav->pNext;
119 }
120
Jon Ashburn6301a0f2015-05-29 13:15:39 -0600121 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600122 return result;
123}
124
125
126/*
127 * This is the instance chain terminator function
128 * for DbgCreateMsgCallback
129 */
130VkResult loader_DbgCreateMsgCallback(
131 VkInstance instance,
132 VkFlags msgFlags,
133 const PFN_vkDbgMsgCallback pfnMsgCallback,
134 const void* pUserData,
135 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
143 if (instance == VK_NULL_HANDLE)
144 return VK_ERROR_INVALID_HANDLE;
145
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600146 for (inst = loader.instances; inst; inst = inst->next) {
147 if ((VkInstance) inst == instance)
148 break;
149 }
150
151 if (inst == VK_NULL_HANDLE)
152 return VK_ERROR_INVALID_HANDLE;
153
154 icd_info = calloc(sizeof(VkDbgMsgCallback), inst->total_icd_count);
155 if (!icd_info) {
156 return VK_ERROR_OUT_OF_HOST_MEMORY;
157 }
158
159 storage_idx = 0;
160 for (icd = inst->icds; icd; icd = icd->next) {
161 if (!icd->DbgCreateMsgCallback) {
162 continue;
163 }
164
165 res = icd->DbgCreateMsgCallback(
166 icd->instance,
167 msgFlags,
168 pfnMsgCallback,
169 pUserData,
170 &icd_info[storage_idx]);
171
172 if (res != VK_SUCCESS) {
173 break;
174 }
175 storage_idx++;
176 }
177
178 /* roll back on errors */
179 if (icd) {
180 storage_idx = 0;
181 for (icd = inst->icds; icd; icd = icd->next) {
182 if (icd_info[storage_idx]) {
183 icd->DbgDestroyMsgCallback(
184 icd->instance,
185 icd_info[storage_idx]);
186 }
187 storage_idx++;
188 }
189
190 return res;
191 }
192
193 *pMsgCallback = (VkDbgMsgCallback) icd_info;
194
195 return VK_SUCCESS;
196}
197
198/*
199 * This is the instance chain terminator function
200 * for DbgDestroyMsgCallback
201 */
202VkResult loader_DbgDestroyMsgCallback(
203 VkInstance instance,
204 VkDbgMsgCallback msgCallback)
205{
206 uint32_t storage_idx;
207 VkDbgMsgCallback *icd_info;
208 const struct loader_icd *icd;
209 VkResult res = VK_SUCCESS;
210 struct loader_instance *inst;
211
212 if (instance == VK_NULL_HANDLE)
213 return VK_ERROR_INVALID_HANDLE;
214
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600215 for (inst = loader.instances; inst; inst = inst->next) {
216 if ((VkInstance) inst == instance)
217 break;
218 }
219
220 if (inst == VK_NULL_HANDLE)
221 return VK_ERROR_INVALID_HANDLE;
222
223 icd_info = (VkDbgMsgCallback *) msgCallback;
224 storage_idx = 0;
225 for (icd = inst->icds; icd; icd = icd->next) {
226 if (icd_info[storage_idx]) {
227 icd->DbgDestroyMsgCallback(
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -0600228 icd->instance,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600229 icd_info[storage_idx]);
230 }
231 storage_idx++;
232 }
233 return res;
234}
235
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600236static void print_msg_flags(VkFlags msgFlags, char *msg_flags)
237{
238 bool separator = false;
239
240 msg_flags[0] = 0;
241 if (msgFlags & VK_DBG_REPORT_DEBUG_BIT) {
242 strcat(msg_flags, "DEBUG");
243 separator = true;
244 }
245 if (msgFlags & VK_DBG_REPORT_INFO_BIT) {
246 if (separator) strcat(msg_flags, ",");
247 strcat(msg_flags, "INFO");
248 separator = true;
249 }
250 if (msgFlags & VK_DBG_REPORT_WARN_BIT) {
251 if (separator) strcat(msg_flags, ",");
252 strcat(msg_flags, "WARN");
253 separator = true;
254 }
255 if (msgFlags & VK_DBG_REPORT_PERF_WARN_BIT) {
256 if (separator) strcat(msg_flags, ",");
257 strcat(msg_flags, "PERF");
258 separator = true;
259 }
260 if (msgFlags & VK_DBG_REPORT_ERROR_BIT) {
261 if (separator) strcat(msg_flags, ",");
262 strcat(msg_flags, "ERROR");
263 }
264}
265
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600266// DebugReport utility callback functions
267static void VKAPI StringCallback(
268 VkFlags msgFlags,
269 VkObjectType objType,
270 VkObject srcObject,
271 size_t location,
272 int32_t msgCode,
273 const char* pLayerPrefix,
274 const char* pMsg,
275 void* pUserData)
276{
Jon Ashburn7242c672015-06-30 14:44:13 -0700277 size_t buf_size;
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600278 char *buf;
279 char msg_flags[30];
280 PFN_stringCallback callback = (PFN_stringCallback) pUserData;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600281
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600282 print_msg_flags(msgFlags, msg_flags);
283
284 buf_size = strlen(msg_flags) + /* ReportFlags: i.e. (DEBUG,INFO,WARN,PERF,ERROR) */
285 20 + /* objType */
286 20 + /* srcObject */
287 20 + /* location */
288 20 + /* msgCode */
289 strlen(pLayerPrefix) +
290 strlen(pMsg) +
291 50 /* other / whitespace */;
Tony Barbour1d825c72015-06-18 16:29:32 -0600292#ifdef WIN32
293 buf = _alloca(buf_size);
294#else
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600295 buf = alloca(buf_size);
Tony Barbour1d825c72015-06-18 16:29:32 -0600296#endif
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600297 snprintf(buf, buf_size, "%s (%s): object: 0x%" PRIxLEAST64 " type: %d location: %zu msgCode: %d: %s",
298 pLayerPrefix, msg_flags, srcObject, objType, location, msgCode, pMsg);
299 callback(buf);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600300}
301
302static void VKAPI StdioCallback(
303 VkFlags msgFlags,
304 VkObjectType objType,
305 VkObject srcObject,
306 size_t location,
307 int32_t msgCode,
308 const char* pLayerPrefix,
309 const char* pMsg,
310 void* pUserData)
311{
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600312 char msg_flags[30];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600313
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600314 print_msg_flags(msgFlags, msg_flags);
315
316 fprintf((FILE *) pUserData, "%s(%s): object: 0x%" PRIxLEAST64 " type: %d location: %zu msgCode: %d: %s",
317 pLayerPrefix, msg_flags, srcObject, objType, location, msgCode, pMsg);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600318}
319
320static void VKAPI BreakCallback(
321 VkFlags msgFlags,
322 VkObjectType objType,
323 VkObject srcObject,
324 size_t location,
325 int32_t msgCode,
326 const char* pLayerPrefix,
327 const char* pMsg,
328 void* pUserData)
329{
330
331}
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 Ashburnc6aecd72015-05-26 13:56:43 -0600344 else if (!strcmp("vkDbgStringCallback", name))
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600345 return (void *) StringCallback;
Jon Ashburnc6aecd72015-05-26 13:56:43 -0600346 else if (!strcmp("vkDbgStdioCallback", name))
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600347 return (void *) StdioCallback;
Jon Ashburnc6aecd72015-05-26 13:56:43 -0600348 else if (!strcmp("vkDbgBreakCallback", name))
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600349 return (void *) BreakCallback;
350
351 return NULL;
352}