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