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 for (unsigned i = 0; i < object_count; i++) {
94 if (unlikely(objects[i] == NULL)) {
95 mesa_logw("vk_log*() called with NULL object\n");
96 continue;
97 }
98
99 if (unlikely(!objects[i]->client_visible)) {
100 mesa_logw("vk_log*() called with client-invisible object %p "
101 "of type %s", objects[i],
102 vk_ObjectType_to_str(objects[i]->type));
103 }
104
105 if (!instance) {
106 instance = vk_object_to_instance(objects[i]);
107 assert(instance->base.client_visible);
108 } else {
109 assert(vk_object_to_instance(objects[i]) == instance);
110 }
111 break;
112 }
113 }
114
115 #ifndef DEBUG
116 if (unlikely(!instance) ||
117 (likely(list_is_empty(&instance->debug_utils.callbacks)) &&
118 likely(list_is_empty(&instance->debug_report.callbacks))))
119 return;
120 #endif
121
122 va_list va;
123 char *message = NULL;
124
125 va_start(va, format);
126 message = ralloc_vasprintf(NULL, format, va);
127 va_end(va);
128
129 char *message_idname = ralloc_asprintf(NULL, "%s:%d", file, line);
130
131 #if DEBUG
132 switch (severity) {
133 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
134 mesa_logd("%s: %s", message_idname, message);
135 break;
136 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
137 mesa_logi("%s: %s", message_idname, message);
138 break;
139 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
140 if (types & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)
141 mesa_logw("%s: PERF: %s", message_idname, message);
142 else
143 mesa_logw("%s: %s", message_idname, message);
144 break;
145 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
146 mesa_loge("%s: %s", message_idname, message);
147 break;
148 default:
149 unreachable("Invalid debug message severity");
150 break;
151 }
152
153 if (!instance) {
154 ralloc_free(message);
155 ralloc_free(message_idname);
156 return;
157 }
158 #endif
159
160 if (!instance->base.client_visible) {
161 vk_debug_message_instance(instance, severity, types,
162 message_idname, 0, message);
163 ralloc_free(message);
164 ralloc_free(message_idname);
165 return;
166 }
167
168 /* If VK_EXT_debug_utils messengers have been set up, form the
169 * message */
170 if (!list_is_empty(&instance->debug_utils.callbacks)) {
171 VkDebugUtilsMessengerCallbackDataEXT cb_data = {
172 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT,
173 .pMessageIdName = message_idname,
174 .messageIdNumber = 0,
175 .pMessage = message,
176 };
177
178 VkDebugUtilsObjectNameInfoEXT *object_name_infos =
179 ralloc_array(NULL, VkDebugUtilsObjectNameInfoEXT, object_count);
180
181 ASSERTED int cmdbuf_n = 0, queue_n = 0, obj_n = 0;
182 for (int i = 0; i < object_count; i++) {
183 struct vk_object_base *base = objects[i];
184 if (base == NULL || !base->client_visible)
185 continue;
186
187 switch (base->type) {
188 case VK_OBJECT_TYPE_COMMAND_BUFFER: {
189 /* We allow at most one command buffer to be submitted at a time */
190 assert(++cmdbuf_n <= 1);
191 struct vk_command_buffer *cmd_buffer =
192 (struct vk_command_buffer *)base;
193 if (cmd_buffer->labels.size > 0) {
194 cb_data.cmdBufLabelCount = util_dynarray_num_elements(
195 &cmd_buffer->labels, VkDebugUtilsLabelEXT);
196 cb_data.pCmdBufLabels = cmd_buffer->labels.data;
197 }
198 break;
199 }
200
201 case VK_OBJECT_TYPE_QUEUE: {
202 /* We allow at most one queue to be submitted at a time */
203 assert(++queue_n <= 1);
204 struct vk_queue *queue = (struct vk_queue *)base;
205 if (queue->labels.size > 0) {
206 cb_data.queueLabelCount =
207 util_dynarray_num_elements(&queue->labels, VkDebugUtilsLabelEXT);
208 cb_data.pQueueLabels = queue->labels.data;
209 }
210 break;
211 }
212 default:
213 break;
214 }
215
216 object_name_infos[obj_n++] = (VkDebugUtilsObjectNameInfoEXT){
217 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
218 .pNext = NULL,
219 .objectType = base->type,
220 .objectHandle = (uint64_t)(uintptr_t)base,
221 .pObjectName = base->object_name,
222 };
223 }
224 cb_data.objectCount = obj_n;
225 cb_data.pObjects = object_name_infos;
226
227 vk_debug_message(instance, severity, types, &cb_data);
228
229 ralloc_free(object_name_infos);
230 }
231
232 /* If VK_EXT_debug_report callbacks also have been set up, forward
233 * the message there as well */
234 if (!list_is_empty(&instance->debug_report.callbacks)) {
235 VkDebugReportFlagsEXT flags = 0;
236
237 switch (severity) {
238 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
239 flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
240 break;
241 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
242 flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
243 break;
244 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
245 if (types & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)
246 flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
247 else
248 flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
249 break;
250 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
251 flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
252 break;
253 default:
254 unreachable("Invalid debug message severity");
255 break;
256 }
257
258 /* VK_EXT_debug_report-provided callback accepts only one object
259 * related to the message. Since they are given to us in
260 * decreasing order of importance, we're forwarding the first
261 * one.
262 */
263 vk_debug_report(instance, flags, object_count ? objects[0] : NULL, 0,
264 0, message_idname, message);
265 }
266
267 ralloc_free(message);
268 ralloc_free(message_idname);
269 }
270
271 static struct vk_object_base *
vk_object_for_error(struct vk_object_base * obj,VkResult error)272 vk_object_for_error(struct vk_object_base *obj, VkResult error)
273 {
274 if (obj == NULL)
275 return NULL;
276
277 switch (error) {
278 case VK_ERROR_OUT_OF_HOST_MEMORY:
279 case VK_ERROR_LAYER_NOT_PRESENT:
280 case VK_ERROR_EXTENSION_NOT_PRESENT:
281 case VK_ERROR_UNKNOWN:
282 return &vk_object_to_instance(obj)->base;
283 case VK_ERROR_FEATURE_NOT_PRESENT:
284 return &vk_object_to_physical_device(obj)->base;
285 case VK_ERROR_OUT_OF_DEVICE_MEMORY:
286 case VK_ERROR_MEMORY_MAP_FAILED:
287 case VK_ERROR_TOO_MANY_OBJECTS:
288 return &vk_object_to_device(obj)->base;
289 default:
290 return obj;
291 }
292 }
293
294 VkResult
__vk_errorv(const void * _obj,VkResult error,const char * file,int line,const char * format,va_list va)295 __vk_errorv(const void *_obj, VkResult error,
296 const char *file, int line,
297 const char *format, va_list va)
298 {
299 struct vk_object_base *object = (struct vk_object_base *)_obj;
300 struct vk_instance *instance = vk_object_to_instance(object);
301 object = vk_object_for_error(object, error);
302
303 /* If object->client_visible isn't set then the object hasn't been fully
304 * constructed and we shouldn't hand it back to the client. This typically
305 * happens if an error is thrown during object construction. This is safe
306 * to do as long as vk_object_base_init() has already been called.
307 */
308 if (object && !object->client_visible)
309 object = NULL;
310
311 const char *error_str = vk_Result_to_str(error);
312
313 if (format) {
314 char *message = ralloc_vasprintf(NULL, format, va);
315
316 if (object) {
317 __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
318 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT,
319 VK_LOG_OBJS(object), file, line,
320 "%s (%s)", message, error_str);
321 } else {
322 __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
323 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT,
324 VK_LOG_NO_OBJS(instance), file, line,
325 "%s (%s)", message, error_str);
326 }
327
328 ralloc_free(message);
329 } else {
330 if (object) {
331 __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
332 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT,
333 VK_LOG_OBJS(object), file, line,
334 "%s", error_str);
335 } else {
336 __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
337 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT,
338 VK_LOG_NO_OBJS(instance), file, line,
339 "%s", error_str);
340 }
341 }
342
343 return error;
344 }
345
346 VkResult
__vk_errorf(const void * _obj,VkResult error,const char * file,int line,const char * format,...)347 __vk_errorf(const void *_obj, VkResult error,
348 const char *file, int line,
349 const char *format, ...)
350 {
351 va_list va;
352
353 va_start(va, format);
354 VkResult result = __vk_errorv(_obj, error, file, line, format, va);
355 va_end(va);
356
357 return result;
358 }
359