• 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 "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