Coverage Report

Created: 2024-09-08 07:41

/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
}