/src/vulkan-loader/loader/log.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * |
3 | | * Copyright (c) 2014-2022 The Khronos Group Inc. |
4 | | * Copyright (c) 2014-2022 Valve Corporation |
5 | | * Copyright (c) 2014-2022 LunarG, Inc. |
6 | | * |
7 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | * you may not use this file except in compliance with the License. |
9 | | * You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, software |
14 | | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | * See the License for the specific language governing permissions and |
17 | | * limitations under the License. |
18 | | * |
19 | | * Author: Jon Ashburn <jon@lunarg.com> |
20 | | * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> |
21 | | * Author: Chia-I Wu <olvaffe@gmail.com> |
22 | | * Author: Chia-I Wu <olv@lunarg.com> |
23 | | * Author: Mark Lobodzinski <mark@LunarG.com> |
24 | | * Author: Lenny Komow <lenny@lunarg.com> |
25 | | * Author: Charles Giessen <charles@lunarg.com> |
26 | | * |
27 | | */ |
28 | | |
29 | | #include "log.h" |
30 | | |
31 | | #include <stdio.h> |
32 | | #include <stdarg.h> |
33 | | |
34 | | #include "debug_utils.h" |
35 | | #include "loader_common.h" |
36 | | #include "loader_environment.h" |
37 | | #include "settings.h" |
38 | | #include "vk_loader_platform.h" |
39 | | |
40 | | uint32_t g_loader_debug = 0; |
41 | | |
42 | 2 | void loader_init_global_debug_level(void) { |
43 | 2 | char *env, *orig; |
44 | | |
45 | 2 | if (g_loader_debug > 0) return; |
46 | | |
47 | 2 | g_loader_debug = 0; |
48 | | |
49 | | // Parse comma-separated debug options |
50 | 2 | orig = env = loader_getenv("VK_LOADER_DEBUG", NULL); |
51 | 2 | while (env) { |
52 | 0 | char *p = strchr(env, ','); |
53 | 0 | size_t len; |
54 | |
|
55 | 0 | if (p) { |
56 | 0 | len = p - env; |
57 | 0 | } else { |
58 | 0 | len = strlen(env); |
59 | 0 | } |
60 | |
|
61 | 0 | if (len > 0) { |
62 | 0 | if (strncmp(env, "all", len) == 0) { |
63 | 0 | g_loader_debug = ~0u; |
64 | 0 | } else if (strncmp(env, "warn", len) == 0) { |
65 | 0 | g_loader_debug |= VULKAN_LOADER_WARN_BIT; |
66 | 0 | } else if (strncmp(env, "info", len) == 0) { |
67 | 0 | g_loader_debug |= VULKAN_LOADER_INFO_BIT; |
68 | 0 | } else if (strncmp(env, "perf", len) == 0) { |
69 | 0 | g_loader_debug |= VULKAN_LOADER_PERF_BIT; |
70 | 0 | } else if (strncmp(env, "error", len) == 0) { |
71 | 0 | g_loader_debug |= VULKAN_LOADER_ERROR_BIT; |
72 | 0 | } else if (strncmp(env, "debug", len) == 0) { |
73 | 0 | g_loader_debug |= VULKAN_LOADER_DEBUG_BIT; |
74 | 0 | } else if (strncmp(env, "layer", len) == 0) { |
75 | 0 | g_loader_debug |= VULKAN_LOADER_LAYER_BIT; |
76 | 0 | } else if (strncmp(env, "driver", len) == 0 || strncmp(env, "implem", len) == 0 || strncmp(env, "icd", len) == 0) { |
77 | 0 | g_loader_debug |= VULKAN_LOADER_DRIVER_BIT; |
78 | 0 | } |
79 | 0 | } |
80 | |
|
81 | 0 | if (!p) break; |
82 | | |
83 | 0 | env = p + 1; |
84 | 0 | } |
85 | | |
86 | 2 | loader_free_getenv(orig, NULL); |
87 | 2 | } |
88 | | |
89 | 146 | void loader_set_global_debug_level(uint32_t new_loader_debug) { g_loader_debug = new_loader_debug; } |
90 | | |
91 | 642 | void generate_debug_flag_str(VkFlags msg_type, size_t cmd_line_size, char *cmd_line_msg) { |
92 | 642 | cmd_line_msg[0] = '\0'; |
93 | | |
94 | 642 | if ((msg_type & VULKAN_LOADER_ERROR_BIT) != 0) { |
95 | 44 | loader_strncat(cmd_line_msg, cmd_line_size, "ERROR", sizeof("ERROR")); |
96 | 44 | } |
97 | 642 | if ((msg_type & VULKAN_LOADER_WARN_BIT) != 0) { |
98 | 62 | if (strlen(cmd_line_msg) > 0) { |
99 | 35 | loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | ")); |
100 | 35 | } |
101 | 62 | loader_strncat(cmd_line_msg, cmd_line_size, "WARNING", sizeof("WARNING")); |
102 | 62 | } |
103 | 642 | if ((msg_type & VULKAN_LOADER_INFO_BIT) != 0) { |
104 | 46 | if (strlen(cmd_line_msg) > 0) { |
105 | 32 | loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | ")); |
106 | 32 | } |
107 | 46 | loader_strncat(cmd_line_msg, cmd_line_size, "INFO", sizeof("INFO")); |
108 | 46 | } |
109 | 642 | if ((msg_type & VULKAN_LOADER_DEBUG_BIT) != 0) { |
110 | 50 | if (strlen(cmd_line_msg) > 0) { |
111 | 35 | loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | ")); |
112 | 35 | } |
113 | 50 | loader_strncat(cmd_line_msg, cmd_line_size, "DEBUG", sizeof("DEBUG")); |
114 | 50 | } |
115 | 642 | if ((msg_type & VULKAN_LOADER_PERF_BIT) != 0) { |
116 | 37 | if (strlen(cmd_line_msg) > 0) { |
117 | 25 | loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | ")); |
118 | 25 | } |
119 | 37 | loader_strncat(cmd_line_msg, cmd_line_size, "PERF", sizeof("PERF")); |
120 | 37 | } |
121 | 642 | if ((msg_type & VULKAN_LOADER_DRIVER_BIT) != 0) { |
122 | 35 | if (strlen(cmd_line_msg) > 0) { |
123 | 22 | loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | ")); |
124 | 22 | } |
125 | 35 | loader_strncat(cmd_line_msg, cmd_line_size, "DRIVER", sizeof("DRIVER")); |
126 | 35 | } |
127 | 642 | if ((msg_type & VULKAN_LOADER_LAYER_BIT) != 0) { |
128 | 41 | if (strlen(cmd_line_msg) > 0) { |
129 | 38 | loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | ")); |
130 | 38 | } |
131 | 41 | loader_strncat(cmd_line_msg, cmd_line_size, "LAYER", sizeof("LAYER")); |
132 | 41 | } |
133 | | |
134 | 642 | #undef STRNCAT_TO_BUFFER |
135 | 642 | } |
136 | | |
137 | | void DECORATE_PRINTF(4, 5) |
138 | 650k | loader_log(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code, const char *format, ...) { |
139 | 650k | (void)msg_code; |
140 | 650k | char msg[512] = {0}; |
141 | | |
142 | 650k | va_list ap; |
143 | 650k | va_start(ap, format); |
144 | 650k | int ret = vsnprintf(msg, sizeof(msg), format, ap); |
145 | 650k | if ((ret >= (int)sizeof(msg)) || ret < 0) { |
146 | 386 | msg[sizeof(msg) - 1] = '\0'; |
147 | 386 | } |
148 | 650k | va_end(ap); |
149 | | |
150 | 650k | if (inst) { |
151 | 0 | VkDebugUtilsMessageSeverityFlagBitsEXT severity = 0; |
152 | 0 | VkDebugUtilsMessageTypeFlagsEXT type = 0; |
153 | 0 | VkDebugUtilsMessengerCallbackDataEXT callback_data = {0}; |
154 | 0 | VkDebugUtilsObjectNameInfoEXT object_name = {0}; |
155 | |
|
156 | 0 | if ((msg_type & VULKAN_LOADER_INFO_BIT) != 0) { |
157 | 0 | severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; |
158 | 0 | } else if ((msg_type & VULKAN_LOADER_WARN_BIT) != 0) { |
159 | 0 | severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; |
160 | 0 | } else if ((msg_type & VULKAN_LOADER_ERROR_BIT) != 0) { |
161 | 0 | severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; |
162 | 0 | } else if ((msg_type & VULKAN_LOADER_DEBUG_BIT) != 0) { |
163 | 0 | severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; |
164 | 0 | } else if ((msg_type & VULKAN_LOADER_LAYER_BIT) != 0 || (msg_type & VULKAN_LOADER_DRIVER_BIT) != 0) { |
165 | | // Just driver or just layer bit should be treated as an info message in debug utils. |
166 | 0 | severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; |
167 | 0 | } |
168 | |
|
169 | 0 | if ((msg_type & VULKAN_LOADER_PERF_BIT) != 0) { |
170 | 0 | type = VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; |
171 | 0 | } else if ((msg_type & VULKAN_LOADER_VALIDATION_BIT) != 0) { |
172 | | // For loader logging, if it's a validation message, we still want to also keep the general flag as well |
173 | | // so messages of type validation can still be triggered for general message callbacks. |
174 | 0 | type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; |
175 | 0 | } else { |
176 | 0 | type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; |
177 | 0 | } |
178 | |
|
179 | 0 | callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT; |
180 | 0 | callback_data.pMessageIdName = "Loader Message"; |
181 | 0 | callback_data.pMessage = msg; |
182 | 0 | callback_data.objectCount = 1; |
183 | 0 | callback_data.pObjects = &object_name; |
184 | 0 | object_name.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; |
185 | 0 | object_name.objectType = VK_OBJECT_TYPE_INSTANCE; |
186 | 0 | object_name.objectHandle = (uint64_t)(uintptr_t)inst; |
187 | |
|
188 | 0 | util_SubmitDebugUtilsMessageEXT(inst, severity, type, &callback_data); |
189 | 0 | } |
190 | | |
191 | | // Always log to stderr if this is a fatal error |
192 | 650k | if (0 == (msg_type & VULKAN_LOADER_FATAL_ERROR_BIT)) { |
193 | 650k | if (inst && inst->settings.settings_active && inst->settings.debug_level > 0) { |
194 | | // Exit early if the current instance settings have some debugging options but do match the current msg_type |
195 | 0 | if (0 == (msg_type & inst->settings.debug_level)) { |
196 | 0 | return; |
197 | 0 | } |
198 | | // Check the global settings and if that doesn't say to skip, check the environment variable |
199 | 650k | } else if (0 == (msg_type & g_loader_debug)) { |
200 | 85.1k | return; |
201 | 85.1k | } |
202 | 650k | } |
203 | | |
204 | | #if defined(DEBUG) |
205 | | int debug_flag_mask = |
206 | | msg_type & (VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DEBUG_BIT); |
207 | | assert((debug_flag_mask == 0 || debug_flag_mask == VULKAN_LOADER_ERROR_BIT || debug_flag_mask == VULKAN_LOADER_WARN_BIT || |
208 | | debug_flag_mask == VULKAN_LOADER_INFO_BIT || debug_flag_mask == VULKAN_LOADER_DEBUG_BIT) && |
209 | | "This log has more than one exclusive debug flags (error, warn, info, debug) set"); |
210 | | #endif |
211 | | |
212 | | // Only need enough space to create the filter description header for log messages |
213 | | // Also use the same header for all output |
214 | 565k | char cmd_line_msg[64] = {0}; |
215 | 565k | size_t cmd_line_size = sizeof(cmd_line_msg); |
216 | | |
217 | 565k | loader_strncat(cmd_line_msg, cmd_line_size, "[Vulkan Loader] ", sizeof("[Vulkan Loader] ")); |
218 | | |
219 | 565k | bool need_separator = false; |
220 | 565k | if ((msg_type & VULKAN_LOADER_ERROR_BIT) != 0) { |
221 | 3.68k | loader_strncat(cmd_line_msg, cmd_line_size, "ERROR", sizeof("ERROR")); |
222 | 3.68k | need_separator = true; |
223 | 561k | } else if ((msg_type & VULKAN_LOADER_WARN_BIT) != 0) { |
224 | 0 | loader_strncat(cmd_line_msg, cmd_line_size, "WARNING", sizeof("WARNING")); |
225 | 0 | need_separator = true; |
226 | 561k | } else if ((msg_type & VULKAN_LOADER_INFO_BIT) != 0) { |
227 | 317 | loader_strncat(cmd_line_msg, cmd_line_size, "INFO", sizeof("INFO")); |
228 | 317 | need_separator = true; |
229 | 561k | } else if ((msg_type & VULKAN_LOADER_DEBUG_BIT) != 0) { |
230 | 561k | loader_strncat(cmd_line_msg, cmd_line_size, "DEBUG", sizeof("DEBUG")); |
231 | 561k | need_separator = true; |
232 | 561k | } |
233 | | |
234 | 565k | if ((msg_type & VULKAN_LOADER_PERF_BIT) != 0) { |
235 | 0 | if (need_separator) { |
236 | 0 | loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | ")); |
237 | 0 | } |
238 | 0 | loader_strncat(cmd_line_msg, cmd_line_size, "PERF", sizeof("PERF")); |
239 | 565k | } else if ((msg_type & VULKAN_LOADER_DRIVER_BIT) != 0) { |
240 | 0 | if (need_separator) { |
241 | 0 | loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | ")); |
242 | 0 | } |
243 | 0 | loader_strncat(cmd_line_msg, cmd_line_size, "DRIVER", sizeof("DRIVER")); |
244 | 565k | } else if ((msg_type & VULKAN_LOADER_LAYER_BIT) != 0) { |
245 | 0 | if (need_separator) { |
246 | 0 | loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | ")); |
247 | 0 | } |
248 | 0 | loader_strncat(cmd_line_msg, cmd_line_size, "LAYER", sizeof("LAYER")); |
249 | 0 | } |
250 | | |
251 | 565k | loader_strncat(cmd_line_msg, cmd_line_size, ": ", sizeof(": ")); |
252 | 565k | size_t num_used = strlen(cmd_line_msg); |
253 | | |
254 | | // Justifies the output to at least 29 spaces |
255 | 565k | if (num_used < 32) { |
256 | 565k | const char space_buffer[] = " "; |
257 | | // Only write (32 - num_used) spaces |
258 | 565k | loader_strncat(cmd_line_msg, cmd_line_size, space_buffer, sizeof(space_buffer) - 1 - num_used); |
259 | 565k | } |
260 | | // Assert that we didn't write more than what is available in cmd_line_msg |
261 | 565k | assert(cmd_line_size > num_used); |
262 | | |
263 | | //fputs(cmd_line_msg, stderr); |
264 | | //fputs(msg, stderr); |
265 | | //fputc('\n', stderr); |
266 | | #if defined(WIN32) |
267 | | OutputDebugString(cmd_line_msg); |
268 | | OutputDebugString(msg); |
269 | | OutputDebugString("\n"); |
270 | | #endif |
271 | 565k | } |
272 | | |
273 | | void loader_log_asm_function_not_supported(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code, |
274 | 0 | const char *func_name) { |
275 | 0 | loader_log(inst, msg_type, msg_code, "Function %s not supported for this physical device", func_name); |
276 | 0 | } |