• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifdef VK_USE_PLATFORM_OHOS
40 #include "loader_hilog.h"
41 #endif
42 
43 uint32_t g_loader_debug = ~0u;
44 
loader_init_global_debug_level(void)45 void loader_init_global_debug_level(void) {
46     char *env, *orig;
47 
48     if (g_loader_debug > 0) return;
49 
50     g_loader_debug = 0;
51 
52     // Parse comma-separated debug options
53     orig = env = loader_getenv("VK_LOADER_DEBUG", NULL);
54     while (env) {
55         char *p = strchr(env, ',');
56         size_t len;
57 
58         if (p) {
59             len = p - env;
60         } else {
61             len = strlen(env);
62         }
63 
64         if (len > 0) {
65             if (strncmp(env, "all", len) == 0) {
66                 g_loader_debug = ~0u;
67             } else if (strncmp(env, "warn", len) == 0) {
68                 g_loader_debug |= VULKAN_LOADER_WARN_BIT;
69             } else if (strncmp(env, "info", len) == 0) {
70                 g_loader_debug |= VULKAN_LOADER_INFO_BIT;
71             } else if (strncmp(env, "perf", len) == 0) {
72                 g_loader_debug |= VULKAN_LOADER_PERF_BIT;
73             } else if (strncmp(env, "error", len) == 0) {
74                 g_loader_debug |= VULKAN_LOADER_ERROR_BIT;
75             } else if (strncmp(env, "debug", len) == 0) {
76                 g_loader_debug |= VULKAN_LOADER_DEBUG_BIT;
77             } else if (strncmp(env, "layer", len) == 0) {
78                 g_loader_debug |= VULKAN_LOADER_LAYER_BIT;
79             } else if (strncmp(env, "driver", len) == 0 || strncmp(env, "implem", len) == 0 || strncmp(env, "icd", len) == 0) {
80                 g_loader_debug |= VULKAN_LOADER_DRIVER_BIT;
81             }
82         }
83 
84         if (!p) break;
85 
86         env = p + 1;
87     }
88 
89     loader_free_getenv(orig, NULL);
90 }
91 
loader_set_global_debug_level(uint32_t new_loader_debug)92 void loader_set_global_debug_level(uint32_t new_loader_debug) { g_loader_debug = new_loader_debug; }
93 
generate_debug_flag_str(VkFlags msg_type,size_t cmd_line_size,char * cmd_line_msg)94 void generate_debug_flag_str(VkFlags msg_type, size_t cmd_line_size, char *cmd_line_msg) {
95     cmd_line_msg[0] = '\0';
96 
97     if ((msg_type & VULKAN_LOADER_ERROR_BIT) != 0) {
98         loader_strncat(cmd_line_msg, cmd_line_size, "ERROR", sizeof("ERROR"));
99     }
100     if ((msg_type & VULKAN_LOADER_WARN_BIT) != 0) {
101         if (strlen(cmd_line_msg) > 0) {
102             loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
103         }
104         loader_strncat(cmd_line_msg, cmd_line_size, "WARNING", sizeof("WARNING"));
105     }
106     if ((msg_type & VULKAN_LOADER_INFO_BIT) != 0) {
107         if (strlen(cmd_line_msg) > 0) {
108             loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
109         }
110         loader_strncat(cmd_line_msg, cmd_line_size, "INFO", sizeof("INFO"));
111     }
112     if ((msg_type & VULKAN_LOADER_DEBUG_BIT) != 0) {
113         if (strlen(cmd_line_msg) > 0) {
114             loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
115         }
116         loader_strncat(cmd_line_msg, cmd_line_size, "DEBUG", sizeof("DEBUG"));
117     }
118     if ((msg_type & VULKAN_LOADER_PERF_BIT) != 0) {
119         if (strlen(cmd_line_msg) > 0) {
120             loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
121         }
122         loader_strncat(cmd_line_msg, cmd_line_size, "PERF", sizeof("PERF"));
123     }
124     if ((msg_type & VULKAN_LOADER_DRIVER_BIT) != 0) {
125         if (strlen(cmd_line_msg) > 0) {
126             loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
127         }
128         loader_strncat(cmd_line_msg, cmd_line_size, "DRIVER", sizeof("DRIVER"));
129     }
130     if ((msg_type & VULKAN_LOADER_LAYER_BIT) != 0) {
131         if (strlen(cmd_line_msg) > 0) {
132             loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
133         }
134         loader_strncat(cmd_line_msg, cmd_line_size, "LAYER", sizeof("LAYER"));
135     }
136 
137 #undef STRNCAT_TO_BUFFER
138 }
139 
140 void DECORATE_PRINTF(4, 5)
loader_log(const struct loader_instance * inst,VkFlags msg_type,int32_t msg_code,const char * format,...)141     loader_log(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code, const char *format, ...) {
142     (void)msg_code;
143     char msg[512] = {0};
144 
145     va_list ap;
146     va_start(ap, format);
147     int ret = vsnprintf(msg, sizeof(msg), format, ap);
148     if ((ret >= (int)sizeof(msg)) || ret < 0) {
149         msg[sizeof(msg) - 1] = '\0';
150     }
151     va_end(ap);
152 
153     if (inst) {
154         VkDebugUtilsMessageSeverityFlagBitsEXT severity = 0;
155         VkDebugUtilsMessageTypeFlagsEXT type = 0;
156         VkDebugUtilsMessengerCallbackDataEXT callback_data = {0};
157         VkDebugUtilsObjectNameInfoEXT object_name = {0};
158 
159         if ((msg_type & VULKAN_LOADER_INFO_BIT) != 0) {
160             severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
161         } else if ((msg_type & VULKAN_LOADER_WARN_BIT) != 0) {
162             severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
163         } else if ((msg_type & VULKAN_LOADER_ERROR_BIT) != 0) {
164             severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
165         } else if ((msg_type & VULKAN_LOADER_DEBUG_BIT) != 0) {
166             severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
167         } else if ((msg_type & VULKAN_LOADER_LAYER_BIT) != 0 || (msg_type & VULKAN_LOADER_DRIVER_BIT) != 0) {
168             // Just driver or just layer bit should be treated as an info message in debug utils.
169             severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
170         }
171 
172         if ((msg_type & VULKAN_LOADER_PERF_BIT) != 0) {
173             type = VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
174         } else if ((msg_type & VULKAN_LOADER_VALIDATION_BIT) != 0) {
175             // For loader logging, if it's a validation message, we still want to also keep the general flag as well
176             // so messages of type validation can still be triggered for general message callbacks.
177             type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
178         } else {
179             type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
180         }
181 
182         callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
183         callback_data.pMessageIdName = "Loader Message";
184         callback_data.pMessage = msg;
185         callback_data.objectCount = 1;
186         callback_data.pObjects = &object_name;
187         object_name.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
188         object_name.objectType = VK_OBJECT_TYPE_INSTANCE;
189         object_name.objectHandle = (uint64_t)(uintptr_t)inst;
190 
191         util_SubmitDebugUtilsMessageEXT(inst, severity, type, &callback_data);
192     }
193 
194     // Always log to stderr if this is a fatal error
195     if (0 == (msg_type & VULKAN_LOADER_FATAL_ERROR_BIT)) {
196         if (inst && inst->settings.settings_active && inst->settings.debug_level > 0) {
197             // Exit early if the current instance settings have some debugging options but do match the current msg_type
198             if (0 == (msg_type & inst->settings.debug_level)) {
199                 return;
200             }
201             // Check the global settings and if that doesn't say to skip, check the environment variable
202         } else if (0 == (msg_type & g_loader_debug)) {
203             return;
204         }
205     }
206 
207 #if defined(DEBUG)
208     int debug_flag_mask =
209         msg_type & (VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DEBUG_BIT);
210     assert((debug_flag_mask == 0 || debug_flag_mask == VULKAN_LOADER_ERROR_BIT || debug_flag_mask == VULKAN_LOADER_WARN_BIT ||
211             debug_flag_mask == VULKAN_LOADER_INFO_BIT || debug_flag_mask == VULKAN_LOADER_DEBUG_BIT) &&
212            "This log has more than one exclusive debug flags (error, warn, info, debug) set");
213 #endif
214 
215     // Only need enough space to create the filter description header for log messages
216     // Also use the same header for all output
217     char cmd_line_msg[64] = {0};
218     size_t cmd_line_size = sizeof(cmd_line_msg);
219 
220     loader_strncat(cmd_line_msg, cmd_line_size, "[Vulkan Loader] ", sizeof("[Vulkan Loader] "));
221 
222     bool need_separator = false;
223     if ((msg_type & VULKAN_LOADER_ERROR_BIT) != 0) {
224         loader_strncat(cmd_line_msg, cmd_line_size, "ERROR", sizeof("ERROR"));
225         need_separator = true;
226     } else if ((msg_type & VULKAN_LOADER_WARN_BIT) != 0) {
227         loader_strncat(cmd_line_msg, cmd_line_size, "WARNING", sizeof("WARNING"));
228         need_separator = true;
229     } else if ((msg_type & VULKAN_LOADER_INFO_BIT) != 0) {
230         loader_strncat(cmd_line_msg, cmd_line_size, "INFO", sizeof("INFO"));
231         need_separator = true;
232     } else if ((msg_type & VULKAN_LOADER_DEBUG_BIT) != 0) {
233         loader_strncat(cmd_line_msg, cmd_line_size, "DEBUG", sizeof("DEBUG"));
234         need_separator = true;
235     }
236 
237     if ((msg_type & VULKAN_LOADER_PERF_BIT) != 0) {
238         if (need_separator) {
239             loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
240         }
241         loader_strncat(cmd_line_msg, cmd_line_size, "PERF", sizeof("PERF"));
242     } else if ((msg_type & VULKAN_LOADER_DRIVER_BIT) != 0) {
243         if (need_separator) {
244             loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
245         }
246         loader_strncat(cmd_line_msg, cmd_line_size, "DRIVER", sizeof("DRIVER"));
247     } else if ((msg_type & VULKAN_LOADER_LAYER_BIT) != 0) {
248         if (need_separator) {
249             loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
250         }
251         loader_strncat(cmd_line_msg, cmd_line_size, "LAYER", sizeof("LAYER"));
252     }
253 
254     loader_strncat(cmd_line_msg, cmd_line_size, ": ", sizeof(": "));
255     size_t num_used = strlen(cmd_line_msg);
256 
257     // Justifies the output to at least 29 spaces
258     if (num_used < 32) {
259         const char space_buffer[] = "                                ";
260         // Only write (32 - num_used) spaces
261         loader_strncat(cmd_line_msg, cmd_line_size, space_buffer, sizeof(space_buffer) - 1 - num_used);
262     }
263     // Assert that we didn't write more than what is available in cmd_line_msg
264     assert(cmd_line_size > num_used);
265 
266 #if !defined (__OHOS__)
267     fputs(cmd_line_msg, stderr);
268     fputs(msg, stderr);
269     fputc('\n', stderr);
270 #endif
271 #if defined(WIN32)
272     OutputDebugString(cmd_line_msg);
273     OutputDebugString(msg);
274     OutputDebugString("\n");
275 #endif
276 
277 #if defined(__OHOS__)
278     char result[512 + 64];
279     strcpy(result, cmd_line_msg);
280     strcat(result, msg);
281     OpenHarmonyLog(msg_type, result);
282 #endif
283 }
284 
loader_log_asm_function_not_supported(const struct loader_instance * inst,VkFlags msg_type,int32_t msg_code,const char * func_name)285 void loader_log_asm_function_not_supported(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code,
286                                            const char *func_name) {
287     loader_log(inst, msg_type, msg_code, "Function %s not supported for this physical device", func_name);
288 }
289