vk_log.c revision 7ec681f3
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      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
252static struct vk_object_base *
253vk_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
275VkResult
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
309      ralloc_free(message);
310   } else {
311      if (object) {
312         __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
313                  VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT,
314                  VK_LOG_OBJS(object), file, line,
315                  "%s", error_str);
316      } else {
317         __vk_log(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
318                  VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT,
319                  VK_LOG_NO_OBJS(instance), file, line,
320                  "%s", error_str);
321      }
322   }
323
324   return error;
325}
326
327VkResult
328__vk_errorf(const void *_obj, VkResult error,
329            const char *file, int line,
330            const char *format, ...)
331{
332   va_list va;
333
334   va_start(va, format);
335   VkResult result = __vk_errorv(_obj, error, file, line, format, va);
336   va_end(va);
337
338   return result;
339}
340