1 /*
2 * Copyright © 2021 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * 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 DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "vk_log.h"
25 #include "vk_debug_utils.h"
26 #include "vk_debug_report.h"
27
28 #include "vk_command_buffer.h"
29 #include "vk_enum_to_str.h"
30 #include "vk_queue.h"
31 #include "vk_device.h"
32 #include "vk_physical_device.h"
33
34 #include "ralloc.h"
35
36 #include "log.h"
37
38 static struct vk_device *
vk_object_to_device(struct vk_object_base * obj)39 vk_object_to_device(struct vk_object_base *obj)
40 {
41 assert(obj->device);
42 return obj->device;
43 }
44
45 static struct vk_physical_device *
vk_object_to_physical_device(struct vk_object_base * obj)46 vk_object_to_physical_device(struct vk_object_base *obj)
47 {
48 switch (obj->type) {
49 case VK_OBJECT_TYPE_INSTANCE:
50 unreachable("Unsupported object type");
51 case VK_OBJECT_TYPE_PHYSICAL_DEVICE:
52 return container_of(obj, struct vk_physical_device, base);
53 case VK_OBJECT_TYPE_SURFACE_KHR:
54 case VK_OBJECT_TYPE_DISPLAY_KHR:
55 case VK_OBJECT_TYPE_DISPLAY_MODE_KHR:
56 case VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT:
57 case VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT:
58 unreachable("Unsupported object type");
59 default:
60 return vk_object_to_device(obj)->physical;
61 }
62 }
63
64 static struct vk_instance *
vk_object_to_instance(struct vk_object_base * obj)65 vk_object_to_instance(struct vk_object_base *obj)
66 {
67 if (obj == NULL)
68 return NULL;
69
70 if (obj->type == VK_OBJECT_TYPE_INSTANCE) {
71 return container_of(obj, struct vk_instance, base);
72 } else {
73 return vk_object_to_physical_device(obj)->instance;
74 }
75 }
76
77 void
__vk_log_impl(VkDebugUtilsMessageSeverityFlagBitsEXT severity,VkDebugUtilsMessageTypeFlagsEXT types,int object_count,const void ** objects_or_instance,const char * file,int line,const char * format,...)78 __vk_log_impl(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
79 VkDebugUtilsMessageTypeFlagsEXT types,
80 int object_count,
81 const void **objects_or_instance,
82 const char *file,
83 int line,
84 const char *format,
85 ...)
86 {
87 struct vk_instance *instance = NULL;
88 struct vk_object_base **objects = NULL;
89 if (object_count == 0) {
90 instance = (struct vk_instance *) objects_or_instance;
91 } else {
92 objects = (struct vk_object_base **) objects_or_instance;
93 instance = vk_object_to_instance(objects[0]);
94 assert(instance->base.client_visible);
95 }
96
97 #ifndef DEBUG
98 if (unlikely(!instance) ||
99 (likely(list_is_empty(&instance->debug_utils.callbacks)) &&
100 likely(list_is_empty(&instance->debug_report.callbacks))))
101 return;
102 #endif
103
104 va_list va;
105 char *message = NULL;
106
107 va_start(va, format);
108 message = ralloc_vasprintf(NULL, format, va);
109 va_end(va);
110
111 char *message_idname = ralloc_asprintf(NULL, "%s:%d", file, line);
112
113 #if DEBUG
114 switch (severity) {
115 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
116 mesa_logd("%s: %s", message_idname, message);
117 break;
118 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
119 mesa_logi("%s: %s", message_idname, message);
120 break;
121 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
122 if (types & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)
123 mesa_logw("%s: PERF: %s", message_idname, message);
124 else
125 mesa_logw("%s: %s", message_idname, message);
126 break;
127 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
128 mesa_loge("%s: %s", message_idname, message);
129 break;
130 default:
131 unreachable("Invalid debug message severity");
132 break;
133 }
134
135 if (!instance) {
136 ralloc_free(message);
137 ralloc_free(message_idname);
138 return;
139 }
140 #endif
141
142 if (!instance->base.client_visible) {
143 vk_debug_message_instance(instance, severity, types,
144 message_idname, 0, message);
145 ralloc_free(message);
146 ralloc_free(message_idname);
147 return;
148 }
149
150 /* If VK_EXT_debug_utils messengers have been set up, form the
151 * message */
152 if (!list_is_empty(&instance->debug_utils.callbacks)) {
153 VkDebugUtilsMessengerCallbackDataEXT cb_data = {
154 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT,
155 .pMessageIdName = message_idname,
156 .messageIdNumber = 0,
157 .pMessage = message,
158 };
159
160 VkDebugUtilsObjectNameInfoEXT *object_name_infos =
161 ralloc_array(NULL, VkDebugUtilsObjectNameInfoEXT, object_count);
162
163 ASSERTED int cmdbuf_n = 0, queue_n = 0;
164 for (int i = 0; i < object_count; i++) {
165 struct vk_object_base *base = objects[i];
166 assert(base->client_visible);
167
168 switch (base->type) {
169 case VK_OBJECT_TYPE_COMMAND_BUFFER: {
170 /* We allow at most one command buffer to be submitted at a time */
171 assert(++cmdbuf_n <= 1);
172 struct vk_command_buffer *cmd_buffer =
173 (struct vk_command_buffer *)base;
174 if (cmd_buffer->labels.size > 0) {
175 cb_data.cmdBufLabelCount = util_dynarray_num_elements(
176 &cmd_buffer->labels, VkDebugUtilsLabelEXT);
177 cb_data.pCmdBufLabels = cmd_buffer->labels.data;
178 }
179 break;
180 }
181
182 case VK_OBJECT_TYPE_QUEUE: {
183 /* We allow at most one queue to be submitted at a time */
184 assert(++queue_n <= 1);
185 struct vk_queue *queue = (struct vk_queue *)base;
186 if (queue->labels.size > 0) {
187 cb_data.queueLabelCount =
188 util_dynarray_num_elements(&queue->labels, VkDebugUtilsLabelEXT);
189 cb_data.pQueueLabels = queue->labels.data;
190 }
191 break;
192 }
193 default:
194 break;
195 }
196
197 object_name_infos[i] = (VkDebugUtilsObjectNameInfoEXT){
198 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
199 .pNext = NULL,
200 .objectType = base->type,
201 .objectHandle = (uint64_t)(uintptr_t)base,
202 .pObjectName = base->object_name,
203 };
204 }
205 cb_data.objectCount = object_count;
206 cb_data.pObjects = object_name_infos;
207
208 vk_debug_message(instance, severity, types, &cb_data);
209
210 ralloc_free(object_name_infos);
211 }
212
213 /* If VK_EXT_debug_report callbacks also have been set up, forward
214 * the message there as well */
215 if (!list_is_empty(&instance->debug_report.callbacks)) {
216 VkDebugReportFlagsEXT flags = 0;
217
218 switch (severity) {
219 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
220 flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
221 break;
222 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
223 flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
224 break;
225 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
226 if (types & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)
227 flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
228 else
229 flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
230 break;
231 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
232 flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
233 break;
234 default:
235 unreachable("Invalid debug message severity");
236 break;
237 }
238
239 /* VK_EXT_debug_report-provided callback accepts only one object
240 * related to the message. Since they are given to us in
241 * decreasing order of importance, we're forwarding the first
242 * one.
243 */
244 vk_debug_report(instance, flags, object_count ? objects[0] : NULL, 0,
245 0, message_idname, message);
246 }
247
248 ralloc_free(message);
249 ralloc_free(message_idname);
250 }
251
252 static struct vk_object_base *
vk_object_for_error(struct vk_object_base * obj,VkResult error)253 vk_object_for_error(struct vk_object_base *obj, VkResult error)
254 {
255 if (obj == NULL)
256 return NULL;
257
258 switch (error) {
259 case VK_ERROR_OUT_OF_HOST_MEMORY:
260 case VK_ERROR_LAYER_NOT_PRESENT:
261 case VK_ERROR_EXTENSION_NOT_PRESENT:
262 case VK_ERROR_UNKNOWN:
263 return &vk_object_to_instance(obj)->base;
264 case VK_ERROR_FEATURE_NOT_PRESENT:
265 return &vk_object_to_physical_device(obj)->base;
266 case VK_ERROR_OUT_OF_DEVICE_MEMORY:
267 case VK_ERROR_MEMORY_MAP_FAILED:
268 case VK_ERROR_TOO_MANY_OBJECTS:
269 return &vk_object_to_device(obj)->base;
270 default:
271 return obj;
272 }
273 }
274
275 VkResult
__vk_errorv(const void * _obj,VkResult error,const char * file,int line,const char * format,va_list va)276 __vk_errorv(const void *_obj, VkResult error,
277 const char *file, int line,
278 const char *format, va_list va)
279 {
280 struct vk_object_base *object = (struct vk_object_base *)_obj;
281 struct vk_instance *instance = vk_object_to_instance(object);
282 object = vk_object_for_error(object, error);
283
284 /* If object->client_visible isn't set then the object hasn't been fully
285 * constructed and we shouldn't hand it back to the client. This typically
286 * happens if an error is thrown during object construction. This is safe
287 * to do as long as vk_object_base_init() has already been called.
288 */
289 if (object && !object->client_visible)
290 object = NULL;
291
292 const char *error_str = vk_Result_to_str(error);
293
294 if (format) {
295 char *message = ralloc_vasprintf(NULL, format, va);
296
297 if (object) {
298 __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
299 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT,
300 VK_LOG_OBJS(object), file, line,
301 "%s (%s)", message, error_str);
302 } else {
303 __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
304 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT,
305 VK_LOG_NO_OBJS(instance), file, line,
306 "%s (%s)", message, error_str);
307 }
308 } else {
309 if (object) {
310 __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
311 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT,
312 VK_LOG_OBJS(object), file, line,
313 "%s", error_str);
314 } else {
315 __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
316 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT,
317 VK_LOG_NO_OBJS(instance), file, line,
318 "%s", error_str);
319 }
320 }
321
322 return error;
323 }
324
325 VkResult
__vk_errorf(const void * _obj,VkResult error,const char * file,int line,const char * format,...)326 __vk_errorf(const void *_obj, VkResult error,
327 const char *file, int line,
328 const char *format, ...)
329 {
330 va_list va;
331
332 va_start(va, format);
333 VkResult result = __vk_errorv(_obj, error, file, line, format, va);
334 va_end(va);
335
336 return result;
337 }
338