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 "get_environment.h"
36 #ifdef VK_USE_PLATFORM_OHOS
37 #include "loader_hilog.h"
38 #endif
39
40 uint32_t g_loader_debug = ~0u;
41
loader_debug_init(void)42 void loader_debug_init(void) {
43 char *env, *orig;
44
45 if (g_loader_debug > 0) return;
46
47 g_loader_debug = 0;
48
49 // Parse comma-separated debug options
50 orig = env = loader_getenv("VK_LOADER_DEBUG", NULL);
51 while (env) {
52 char *p = strchr(env, ',');
53 size_t len;
54
55 if (p) {
56 len = p - env;
57 } else {
58 len = strlen(env);
59 }
60
61 if (len > 0) {
62 if (strncmp(env, "all", len) == 0) {
63 g_loader_debug = ~0u;
64 } else if (strncmp(env, "warn", len) == 0) {
65 g_loader_debug |= VULKAN_LOADER_WARN_BIT;
66 } else if (strncmp(env, "info", len) == 0) {
67 g_loader_debug |= VULKAN_LOADER_INFO_BIT;
68 } else if (strncmp(env, "perf", len) == 0) {
69 g_loader_debug |= VULKAN_LOADER_PERF_BIT;
70 } else if (strncmp(env, "error", len) == 0) {
71 g_loader_debug |= VULKAN_LOADER_ERROR_BIT;
72 } else if (strncmp(env, "debug", len) == 0) {
73 g_loader_debug |= VULKAN_LOADER_DEBUG_BIT;
74 } else if (strncmp(env, "layer", len) == 0) {
75 g_loader_debug |= VULKAN_LOADER_LAYER_BIT;
76 } else if (strncmp(env, "driver", len) == 0 || strncmp(env, "implem", len) == 0 || strncmp(env, "icd", len) == 0) {
77 g_loader_debug |= VULKAN_LOADER_DRIVER_BIT;
78 }
79 }
80
81 if (!p) break;
82
83 env = p + 1;
84 }
85
86 loader_free_getenv(orig, NULL);
87 }
88
loader_get_debug_level(void)89 uint32_t loader_get_debug_level(void) { return g_loader_debug; }
90
loader_log(const struct loader_instance * inst,VkFlags msg_type,int32_t msg_code,const char * format,...)91 void loader_log(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code, const char *format, ...) {
92 char msg[512];
93 char cmd_line_msg[512];
94 size_t cmd_line_size = sizeof(cmd_line_msg);
95 size_t num_used = 0;
96 va_list ap;
97 int ret;
98
99 va_start(ap, format);
100 ret = vsnprintf(msg, sizeof(msg), format, ap);
101 if ((ret >= (int)sizeof(msg)) || ret < 0) {
102 msg[sizeof(msg) - 1] = '\0';
103 }
104 va_end(ap);
105
106 if (inst) {
107 VkDebugUtilsMessageSeverityFlagBitsEXT severity = 0;
108 VkDebugUtilsMessageTypeFlagsEXT type;
109 VkDebugUtilsMessengerCallbackDataEXT callback_data;
110 VkDebugUtilsObjectNameInfoEXT object_name;
111
112 if ((msg_type & VULKAN_LOADER_INFO_BIT) != 0) {
113 severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
114 } else if ((msg_type & VULKAN_LOADER_WARN_BIT) != 0) {
115 severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
116 } else if ((msg_type & VULKAN_LOADER_ERROR_BIT) != 0) {
117 severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
118 } else if ((msg_type & VULKAN_LOADER_DEBUG_BIT) != 0) {
119 severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
120 } else if ((msg_type & VULKAN_LOADER_LAYER_BIT) != 0 || (msg_type & VULKAN_LOADER_DRIVER_BIT) != 0) {
121 // Just driver or just layer bit should be treated as an info message in debug utils.
122 severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
123 }
124
125 if ((msg_type & VULKAN_LOADER_PERF_BIT) != 0) {
126 type = VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
127 } else if ((msg_type & VULKAN_LOADER_VALIDATION_BIT) != 0) {
128 // For loader logging, if it's a validation message, we still want to also keep the general flag as well
129 // so messages of type validation can still be triggered for general message callbacks.
130 type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
131 } else {
132 type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
133 }
134
135 callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
136 callback_data.pNext = NULL;
137 callback_data.flags = 0;
138 callback_data.pMessageIdName = "Loader Message";
139 callback_data.messageIdNumber = 0;
140 callback_data.pMessage = msg;
141 callback_data.queueLabelCount = 0;
142 callback_data.pQueueLabels = NULL;
143 callback_data.cmdBufLabelCount = 0;
144 callback_data.pCmdBufLabels = NULL;
145 callback_data.objectCount = 1;
146 callback_data.pObjects = &object_name;
147 object_name.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
148 object_name.pNext = NULL;
149 object_name.objectType = VK_OBJECT_TYPE_INSTANCE;
150 object_name.objectHandle = (uint64_t)(uintptr_t)inst;
151 object_name.pObjectName = NULL;
152
153 util_SubmitDebugUtilsMessageEXT(inst, severity, type, &callback_data);
154 }
155
156 uint32_t filtered_msg_type = (msg_type & g_loader_debug);
157 if (0 == filtered_msg_type) {
158 return;
159 }
160
161 cmd_line_msg[0] = '\0';
162 cmd_line_size -= 1;
163 num_used = 1;
164
165 if ((msg_type & VULKAN_LOADER_ERROR_BIT) != 0) {
166 strncat(cmd_line_msg, "ERROR", cmd_line_size - num_used);
167 num_used += 5;
168 } else if ((msg_type & VULKAN_LOADER_WARN_BIT) != 0) {
169 strncat(cmd_line_msg, "WARNING", cmd_line_size - num_used);
170 num_used += 7;
171 } else if ((msg_type & VULKAN_LOADER_INFO_BIT) != 0) {
172 strncat(cmd_line_msg, "INFO", cmd_line_size - num_used);
173 num_used += 4;
174 } else if ((msg_type & VULKAN_LOADER_DEBUG_BIT) != 0) {
175 strncat(cmd_line_msg, "DEBUG", cmd_line_size - num_used);
176 num_used += 5;
177 }
178 // For the remaining messages, we only want to add any tags that are
179 // explicitly enabled by the tools.
180 if ((filtered_msg_type & VULKAN_LOADER_PERF_BIT) != 0) {
181 if (num_used > 1) {
182 strncat(cmd_line_msg, " | ", cmd_line_size - num_used);
183 num_used += 3;
184 }
185 strncat(cmd_line_msg, "PERF", cmd_line_size - num_used);
186 num_used += 4;
187 }
188 if ((filtered_msg_type & VULKAN_LOADER_DRIVER_BIT) != 0) {
189 if (num_used > 1) {
190 strncat(cmd_line_msg, " | ", cmd_line_size - num_used);
191 num_used += 3;
192 }
193 strncat(cmd_line_msg, "DRIVER", cmd_line_size - num_used);
194 num_used += 6;
195 }
196 if ((filtered_msg_type & VULKAN_LOADER_LAYER_BIT) != 0) {
197 if (num_used > 1) {
198 strncat(cmd_line_msg, " | ", cmd_line_size - num_used);
199 num_used += 3;
200 }
201 strncat(cmd_line_msg, "LAYER", cmd_line_size - num_used);
202 num_used += 5;
203 }
204 // Add any preceeding spaces so we can have clean output
205 if (num_used > 1) {
206 strncat(cmd_line_msg, ": ", cmd_line_size - num_used);
207 num_used += 2;
208 }
209 while (num_used < 19) {
210 strncat(cmd_line_msg, " ", cmd_line_size - num_used);
211 num_used++;
212 }
213
214 size_t available_space = cmd_line_size - num_used;
215 if (available_space > 0) {
216 // If the message is too long, trim it down
217 if (strlen(msg) > available_space) {
218 msg[available_space - 1] = '\0';
219 }
220 strncat(cmd_line_msg, msg, cmd_line_size);
221
222 #if defined(WIN32)
223 OutputDebugString(cmd_line_msg);
224 OutputDebugString("\n");
225 #endif
226
227 #if defined(VK_USE_PLATFORM_OHOS)
228 OpenHarmonyLog(msg_type, cmd_line_msg);
229 #endif
230
231 fputs(cmd_line_msg, stderr);
232 fputc('\n', stderr);
233 } else {
234 // Shouldn't get here, but check to make sure if we've already overrun
235 // the string boundary
236 assert(false);
237 }
238 }
239