xref: /third_party/mesa3d/src/vulkan/runtime/vk_log.c (revision bf215546)
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
38static struct vk_device *
39vk_object_to_device(struct vk_object_base *obj)
40{
41   assert(obj->device);
42   return obj->device;
43}
44
45static struct vk_physical_device *
46vk_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
64static struct vk_instance *
65vk_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
77void
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
271static struct vk_object_base *
272vk_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
294VkResult
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
346VkResult
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