blob: 1d6a186ba4c8d2055d889ab372ab7affd18645b1 [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>
33#include <alloca.h>
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060034#include "debug_report.h"
35#include "vkLayer.h"
36
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -060037typedef void (VKAPI *PFN_stringCallback)(char *message);
38
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060039static const struct loader_extension_property debug_report_extension_info = {
40 .info = {
41 .sType = VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES,
42 .name = DEBUG_REPORT_EXTENSION_NAME,
43 .version = VK_DEBUG_REPORT_EXTENSION_VERSION,
44 .description = "loader: debug report extension",
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060045 },
46 .origin = VK_EXTENSION_ORIGIN_LOADER,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060047};
48
49void debug_report_add_instance_extensions(
50 struct loader_extension_list *ext_list)
51{
52 loader_add_to_ext_list(ext_list, 1, &debug_report_extension_info);
53}
54
55void debug_report_create_instance(
56 struct loader_instance *ptr_instance)
57{
58 ptr_instance->debug_report_enabled = has_vk_extension_property(
59 &debug_report_extension_info.info,
60 &ptr_instance->enabled_instance_extensions);
61}
62
63static VkResult debug_report_DbgCreateMsgCallback(
64 VkInstance instance,
65 VkFlags msgFlags,
66 const PFN_vkDbgMsgCallback pfnMsgCallback,
67 void* pUserData,
68 VkDbgMsgCallback* pMsgCallback)
69{
70 VkLayerDbgFunctionNode *pNewDbgFuncNode = (VkLayerDbgFunctionNode *) malloc(sizeof(VkLayerDbgFunctionNode));
71 if (!pNewDbgFuncNode)
72 return VK_ERROR_OUT_OF_HOST_MEMORY;
73
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -060074 struct loader_instance *inst = loader_instance(instance);
Jon Ashburn6301a0f2015-05-29 13:15:39 -060075 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060076 VkResult result = inst->disp->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
77 if (result == VK_SUCCESS) {
78 pNewDbgFuncNode->msgCallback = *pMsgCallback;
79 pNewDbgFuncNode->pfnMsgCallback = pfnMsgCallback;
80 pNewDbgFuncNode->msgFlags = msgFlags;
81 pNewDbgFuncNode->pUserData = pUserData;
82 pNewDbgFuncNode->pNext = inst->DbgFunctionHead;
83 inst->DbgFunctionHead = pNewDbgFuncNode;
84 } else {
85 free(pNewDbgFuncNode);
86 }
Jon Ashburn6301a0f2015-05-29 13:15:39 -060087 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060088 return result;
89}
90
91static VkResult debug_report_DbgDestroyMsgCallback(
92 VkInstance instance,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060093 VkDbgMsgCallback msg_callback)
94{
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -060095 struct loader_instance *inst = loader_instance(instance);
Jon Ashburn6301a0f2015-05-29 13:15:39 -060096 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060097 VkLayerDbgFunctionNode *pTrav = inst->DbgFunctionHead;
98 VkLayerDbgFunctionNode *pPrev = pTrav;
99
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -0600100 VkResult result = inst->disp->DbgDestroyMsgCallback(instance, msg_callback);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600101
102 while (pTrav) {
103 if (pTrav->msgCallback == msg_callback) {
104 pPrev->pNext = pTrav->pNext;
105 if (inst->DbgFunctionHead == pTrav)
106 inst->DbgFunctionHead = pTrav->pNext;
107 free(pTrav);
108 break;
109 }
110 pPrev = pTrav;
111 pTrav = pTrav->pNext;
112 }
113
Jon Ashburn6301a0f2015-05-29 13:15:39 -0600114 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600115 return result;
116}
117
118
119/*
120 * This is the instance chain terminator function
121 * for DbgCreateMsgCallback
122 */
123VkResult loader_DbgCreateMsgCallback(
124 VkInstance instance,
125 VkFlags msgFlags,
126 const PFN_vkDbgMsgCallback pfnMsgCallback,
127 const void* pUserData,
128 VkDbgMsgCallback* pMsgCallback)
129{
130 VkDbgMsgCallback *icd_info;
131 const struct loader_icd *icd;
132 struct loader_instance *inst;
133 VkResult res;
134 uint32_t storage_idx;
135
136 if (instance == VK_NULL_HANDLE)
137 return VK_ERROR_INVALID_HANDLE;
138
139 assert(loader.icds_scanned);
140
141 for (inst = loader.instances; inst; inst = inst->next) {
142 if ((VkInstance) inst == instance)
143 break;
144 }
145
146 if (inst == VK_NULL_HANDLE)
147 return VK_ERROR_INVALID_HANDLE;
148
149 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) {
177 if (icd_info[storage_idx]) {
178 icd->DbgDestroyMsgCallback(
179 icd->instance,
180 icd_info[storage_idx]);
181 }
182 storage_idx++;
183 }
184
185 return res;
186 }
187
188 *pMsgCallback = (VkDbgMsgCallback) icd_info;
189
190 return VK_SUCCESS;
191}
192
193/*
194 * This is the instance chain terminator function
195 * for DbgDestroyMsgCallback
196 */
197VkResult loader_DbgDestroyMsgCallback(
198 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
207 if (instance == VK_NULL_HANDLE)
208 return VK_ERROR_INVALID_HANDLE;
209
210 assert(loader.icds_scanned);
211
212 for (inst = loader.instances; inst; inst = inst->next) {
213 if ((VkInstance) inst == instance)
214 break;
215 }
216
217 if (inst == VK_NULL_HANDLE)
218 return VK_ERROR_INVALID_HANDLE;
219
220 icd_info = (VkDbgMsgCallback *) msgCallback;
221 storage_idx = 0;
222 for (icd = inst->icds; icd; icd = icd->next) {
223 if (icd_info[storage_idx]) {
224 icd->DbgDestroyMsgCallback(
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -0600225 icd->instance,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600226 icd_info[storage_idx]);
227 }
228 storage_idx++;
229 }
230 return res;
231}
232
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600233static void print_msg_flags(VkFlags msgFlags, char *msg_flags)
234{
235 bool separator = false;
236
237 msg_flags[0] = 0;
238 if (msgFlags & VK_DBG_REPORT_DEBUG_BIT) {
239 strcat(msg_flags, "DEBUG");
240 separator = true;
241 }
242 if (msgFlags & VK_DBG_REPORT_INFO_BIT) {
243 if (separator) strcat(msg_flags, ",");
244 strcat(msg_flags, "INFO");
245 separator = true;
246 }
247 if (msgFlags & VK_DBG_REPORT_WARN_BIT) {
248 if (separator) strcat(msg_flags, ",");
249 strcat(msg_flags, "WARN");
250 separator = true;
251 }
252 if (msgFlags & VK_DBG_REPORT_PERF_WARN_BIT) {
253 if (separator) strcat(msg_flags, ",");
254 strcat(msg_flags, "PERF");
255 separator = true;
256 }
257 if (msgFlags & VK_DBG_REPORT_ERROR_BIT) {
258 if (separator) strcat(msg_flags, ",");
259 strcat(msg_flags, "ERROR");
260 }
261}
262
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600263// DebugReport utility callback functions
264static void VKAPI StringCallback(
265 VkFlags msgFlags,
266 VkObjectType objType,
267 VkObject srcObject,
268 size_t location,
269 int32_t msgCode,
270 const char* pLayerPrefix,
271 const char* pMsg,
272 void* pUserData)
273{
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600274 uint32_t buf_size;
275 char *buf;
276 char msg_flags[30];
277 PFN_stringCallback callback = (PFN_stringCallback) pUserData;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600278
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600279 print_msg_flags(msgFlags, msg_flags);
280
281 buf_size = strlen(msg_flags) + /* ReportFlags: i.e. (DEBUG,INFO,WARN,PERF,ERROR) */
282 20 + /* objType */
283 20 + /* srcObject */
284 20 + /* location */
285 20 + /* msgCode */
286 strlen(pLayerPrefix) +
287 strlen(pMsg) +
288 50 /* other / whitespace */;
289 buf = alloca(buf_size);
290
291 snprintf(buf, buf_size, "%s (%s): object: 0x%" PRIxLEAST64 " type: %d location: %zu msgCode: %d: %s",
292 pLayerPrefix, msg_flags, srcObject, objType, location, msgCode, pMsg);
293 callback(buf);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600294}
295
296static void VKAPI StdioCallback(
297 VkFlags msgFlags,
298 VkObjectType objType,
299 VkObject srcObject,
300 size_t location,
301 int32_t msgCode,
302 const char* pLayerPrefix,
303 const char* pMsg,
304 void* pUserData)
305{
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600306 char msg_flags[30];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600307
Courtney Goeltzenleuchter7dcc6a72015-06-11 16:01:11 -0600308 print_msg_flags(msgFlags, msg_flags);
309
310 fprintf((FILE *) pUserData, "%s(%s): object: 0x%" PRIxLEAST64 " type: %d location: %zu msgCode: %d: %s",
311 pLayerPrefix, msg_flags, srcObject, objType, location, msgCode, pMsg);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600312}
313
314static void VKAPI BreakCallback(
315 VkFlags msgFlags,
316 VkObjectType objType,
317 VkObject srcObject,
318 size_t location,
319 int32_t msgCode,
320 const char* pLayerPrefix,
321 const char* pMsg,
322 void* pUserData)
323{
324
325}
326
327void *debug_report_instance_gpa(
328 struct loader_instance *ptr_instance,
329 const char* name)
330{
331 if (ptr_instance == VK_NULL_HANDLE || !ptr_instance->debug_report_enabled)
332 return NULL;
333
334 if (!strcmp("vkDbgCreateMsgCallback", name))
335 return (void *) debug_report_DbgCreateMsgCallback;
336 else if (!strcmp("vkDbgDestroyMsgCallback", name))
337 return (void *) debug_report_DbgDestroyMsgCallback;
Jon Ashburnc6aecd72015-05-26 13:56:43 -0600338 else if (!strcmp("vkDbgStringCallback", name))
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600339 return (void *) StringCallback;
Jon Ashburnc6aecd72015-05-26 13:56:43 -0600340 else if (!strcmp("vkDbgStdioCallback", name))
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600341 return (void *) StdioCallback;
Jon Ashburnc6aecd72015-05-26 13:56:43 -0600342 else if (!strcmp("vkDbgBreakCallback", name))
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600343 return (void *) BreakCallback;
344
345 return NULL;
346}