/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 | 273 | void loader_set_global_debug_level(uint32_t new_loader_debug) { g_loader_debug = new_loader_debug; } |
90 | | |
91 | 124k | void loader_log(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code, const char *format, ...) { |
92 | 124k | (void)msg_code; |
93 | 124k | char msg[512] = {0}; |
94 | | |
95 | 124k | va_list ap; |
96 | 124k | va_start(ap, format); |
97 | 124k | int ret = vsnprintf(msg, sizeof(msg), format, ap); |
98 | 124k | if ((ret >= (int)sizeof(msg)) || ret < 0) { |
99 | 194 | msg[sizeof(msg) - 1] = '\0'; |
100 | 194 | } |
101 | 124k | va_end(ap); |
102 | | |
103 | 124k | if (inst) { |
104 | 0 | VkDebugUtilsMessageSeverityFlagBitsEXT severity = 0; |
105 | 0 | VkDebugUtilsMessageTypeFlagsEXT type = 0; |
106 | 0 | VkDebugUtilsMessengerCallbackDataEXT callback_data = {0}; |
107 | 0 | VkDebugUtilsObjectNameInfoEXT object_name = {0}; |
108 | |
|
109 | 0 | if ((msg_type & VULKAN_LOADER_INFO_BIT) != 0) { |
110 | 0 | severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; |
111 | 0 | } else if ((msg_type & VULKAN_LOADER_WARN_BIT) != 0) { |
112 | 0 | severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; |
113 | 0 | } else if ((msg_type & VULKAN_LOADER_ERROR_BIT) != 0) { |
114 | 0 | severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; |
115 | 0 | } else if ((msg_type & VULKAN_LOADER_DEBUG_BIT) != 0) { |
116 | 0 | severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; |
117 | 0 | } else if ((msg_type & VULKAN_LOADER_LAYER_BIT) != 0 || (msg_type & VULKAN_LOADER_DRIVER_BIT) != 0) { |
118 | | // Just driver or just layer bit should be treated as an info message in debug utils. |
119 | 0 | severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; |
120 | 0 | } |
121 | |
|
122 | 0 | if ((msg_type & VULKAN_LOADER_PERF_BIT) != 0) { |
123 | 0 | type = VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; |
124 | 0 | } else if ((msg_type & VULKAN_LOADER_VALIDATION_BIT) != 0) { |
125 | | // For loader logging, if it's a validation message, we still want to also keep the general flag as well |
126 | | // so messages of type validation can still be triggered for general message callbacks. |
127 | 0 | type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; |
128 | 0 | } else { |
129 | 0 | type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; |
130 | 0 | } |
131 | |
|
132 | 0 | callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT; |
133 | 0 | callback_data.pMessageIdName = "Loader Message"; |
134 | 0 | callback_data.pMessage = msg; |
135 | 0 | callback_data.objectCount = 1; |
136 | 0 | callback_data.pObjects = &object_name; |
137 | 0 | object_name.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; |
138 | 0 | object_name.objectType = VK_OBJECT_TYPE_INSTANCE; |
139 | 0 | object_name.objectHandle = (uint64_t)(uintptr_t)inst; |
140 | |
|
141 | 0 | util_SubmitDebugUtilsMessageEXT(inst, severity, type, &callback_data); |
142 | 0 | } |
143 | | |
144 | | // Always log to stderr if this is a fatal error |
145 | 124k | if (0 == (msg_type & VULKAN_LOADER_FATAL_ERROR_BIT)) { |
146 | | // Exit early if the current instance settings do not ask for logging to stderr |
147 | 124k | if (inst && inst->settings.settings_active && 0 == (msg_type & inst->settings.debug_level)) { |
148 | 0 | return; |
149 | | // Check the global settings and if that doesn't say to skip, check the environment variable |
150 | 124k | } else if (0 == (msg_type & g_loader_debug)) { |
151 | 120k | return; |
152 | 120k | } |
153 | 124k | } |
154 | | |
155 | | // Only need enough space to create the filter description header for log messages |
156 | | // Also use the same header for all output |
157 | 4.18k | char cmd_line_msg[64]; |
158 | 4.18k | size_t cmd_line_size = sizeof(cmd_line_msg); |
159 | 4.18k | size_t num_used = 0; |
160 | | |
161 | 4.18k | cmd_line_msg[0] = '\0'; |
162 | | |
163 | | // Helper macro which strncat's the given string literal, then updates num_used & cmd_line_end |
164 | | // Assumes that we haven't used the entire buffer - must manually check this when adding new filter types |
165 | | // We concat at the end of cmd_line_msg, so that strncat isn't a victim of Schlemiel the Painter |
166 | | // We write to the end - 1 of cmd_line_msg, as the end is actually a null terminator |
167 | 4.18k | #define STRNCAT_TO_BUFFER(string_literal_to_cat) \ |
168 | 8.37k | loader_strncat(cmd_line_msg + num_used, cmd_line_size - num_used, string_literal_to_cat, sizeof(string_literal_to_cat)); \ |
169 | 8.37k | num_used += sizeof(string_literal_to_cat) - 1; // subtract one to remove the null terminator in the string literal |
170 | | |
171 | 4.18k | if ((msg_type & VULKAN_LOADER_ERROR_BIT) != 0) { |
172 | 221 | STRNCAT_TO_BUFFER("ERROR"); |
173 | 3.96k | } else if ((msg_type & VULKAN_LOADER_WARN_BIT) != 0) { |
174 | 0 | STRNCAT_TO_BUFFER("WARNING"); |
175 | 3.96k | } else if ((msg_type & VULKAN_LOADER_INFO_BIT) != 0) { |
176 | 20 | STRNCAT_TO_BUFFER("INFO"); |
177 | 3.94k | } else if ((msg_type & VULKAN_LOADER_DEBUG_BIT) != 0) { |
178 | 3.94k | STRNCAT_TO_BUFFER("DEBUG"); |
179 | 3.94k | } |
180 | | |
181 | 4.18k | if ((msg_type & VULKAN_LOADER_PERF_BIT) != 0) { |
182 | 0 | if (num_used > 1) { |
183 | 0 | STRNCAT_TO_BUFFER(" | "); |
184 | 0 | } |
185 | 0 | STRNCAT_TO_BUFFER("PERF"); |
186 | 0 | } |
187 | 4.18k | if ((msg_type & VULKAN_LOADER_DRIVER_BIT) != 0) { |
188 | 0 | if (num_used > 1) { |
189 | 0 | STRNCAT_TO_BUFFER(" | "); |
190 | 0 | } |
191 | 0 | STRNCAT_TO_BUFFER("DRIVER"); |
192 | 0 | } |
193 | 4.18k | if ((msg_type & VULKAN_LOADER_LAYER_BIT) != 0) { |
194 | 0 | if (num_used > 1) { |
195 | 0 | STRNCAT_TO_BUFFER(" | "); |
196 | 0 | } |
197 | 0 | STRNCAT_TO_BUFFER("LAYER"); |
198 | 0 | } |
199 | | |
200 | | // Add a ": " to separate the filters from the message |
201 | 4.18k | STRNCAT_TO_BUFFER(": "); |
202 | 4.18k | #undef STRNCAT_TO_BUFFER |
203 | | |
204 | | // Justifies the output to at least 19 spaces |
205 | 4.18k | if (num_used < 19) { |
206 | 4.18k | const char *space_buffer = " "; |
207 | | // Only write (19 - num_used) spaces |
208 | 4.18k | loader_strncat(cmd_line_msg + num_used, cmd_line_size - num_used, space_buffer, 19 - num_used); |
209 | 4.18k | num_used += sizeof(space_buffer) - 1 - num_used; |
210 | 4.18k | } |
211 | | // Assert that we didn't write more than what is available in cmd_line_msg |
212 | 4.18k | assert(cmd_line_size > num_used); |
213 | | |
214 | 4.18k | fputs(cmd_line_msg, stderr); |
215 | 4.18k | fputs(msg, stderr); |
216 | 4.18k | fputc('\n', stderr); |
217 | | #if defined(WIN32) |
218 | | OutputDebugString(cmd_line_msg); |
219 | | OutputDebugString(msg); |
220 | | OutputDebugString("\n"); |
221 | | #endif |
222 | 4.18k | } |
223 | | |
224 | | void loader_log_asm_function_not_supported(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code, |
225 | 0 | const char *func_name) { |
226 | 0 | loader_log(inst, msg_type, msg_code, "Function %s not supported for this physical device", func_name); |
227 | 0 | } |