15db71995Sopenharmony_ci/* 25db71995Sopenharmony_ci * 35db71995Sopenharmony_ci * Copyright (c) 2014-2022 The Khronos Group Inc. 45db71995Sopenharmony_ci * Copyright (c) 2014-2022 Valve Corporation 55db71995Sopenharmony_ci * Copyright (c) 2014-2022 LunarG, Inc. 65db71995Sopenharmony_ci * 75db71995Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 85db71995Sopenharmony_ci * you may not use this file except in compliance with the License. 95db71995Sopenharmony_ci * You may obtain a copy of the License at 105db71995Sopenharmony_ci * 115db71995Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 125db71995Sopenharmony_ci * 135db71995Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 145db71995Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 155db71995Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 165db71995Sopenharmony_ci * See the License for the specific language governing permissions and 175db71995Sopenharmony_ci * limitations under the License. 185db71995Sopenharmony_ci * 195db71995Sopenharmony_ci * Author: Jon Ashburn <jon@lunarg.com> 205db71995Sopenharmony_ci * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> 215db71995Sopenharmony_ci * Author: Chia-I Wu <olvaffe@gmail.com> 225db71995Sopenharmony_ci * Author: Chia-I Wu <olv@lunarg.com> 235db71995Sopenharmony_ci * Author: Mark Lobodzinski <mark@LunarG.com> 245db71995Sopenharmony_ci * Author: Lenny Komow <lenny@lunarg.com> 255db71995Sopenharmony_ci * Author: Charles Giessen <charles@lunarg.com> 265db71995Sopenharmony_ci * 275db71995Sopenharmony_ci */ 285db71995Sopenharmony_ci 295db71995Sopenharmony_ci#include "log.h" 305db71995Sopenharmony_ci 315db71995Sopenharmony_ci#include <stdio.h> 325db71995Sopenharmony_ci#include <stdarg.h> 335db71995Sopenharmony_ci 345db71995Sopenharmony_ci#include "debug_utils.h" 355db71995Sopenharmony_ci#include "loader_common.h" 365db71995Sopenharmony_ci#include "loader_environment.h" 375db71995Sopenharmony_ci#include "settings.h" 385db71995Sopenharmony_ci#include "vk_loader_platform.h" 395db71995Sopenharmony_ci#ifdef VK_USE_PLATFORM_OHOS 405db71995Sopenharmony_ci#include "loader_hilog.h" 415db71995Sopenharmony_ci#endif 425db71995Sopenharmony_ci 435db71995Sopenharmony_ciuint32_t g_loader_debug = ~0u; 445db71995Sopenharmony_ci 455db71995Sopenharmony_civoid loader_init_global_debug_level(void) { 465db71995Sopenharmony_ci char *env, *orig; 475db71995Sopenharmony_ci 485db71995Sopenharmony_ci if (g_loader_debug > 0) return; 495db71995Sopenharmony_ci 505db71995Sopenharmony_ci g_loader_debug = 0; 515db71995Sopenharmony_ci 525db71995Sopenharmony_ci // Parse comma-separated debug options 535db71995Sopenharmony_ci orig = env = loader_getenv("VK_LOADER_DEBUG", NULL); 545db71995Sopenharmony_ci while (env) { 555db71995Sopenharmony_ci char *p = strchr(env, ','); 565db71995Sopenharmony_ci size_t len; 575db71995Sopenharmony_ci 585db71995Sopenharmony_ci if (p) { 595db71995Sopenharmony_ci len = p - env; 605db71995Sopenharmony_ci } else { 615db71995Sopenharmony_ci len = strlen(env); 625db71995Sopenharmony_ci } 635db71995Sopenharmony_ci 645db71995Sopenharmony_ci if (len > 0) { 655db71995Sopenharmony_ci if (strncmp(env, "all", len) == 0) { 665db71995Sopenharmony_ci g_loader_debug = ~0u; 675db71995Sopenharmony_ci } else if (strncmp(env, "warn", len) == 0) { 685db71995Sopenharmony_ci g_loader_debug |= VULKAN_LOADER_WARN_BIT; 695db71995Sopenharmony_ci } else if (strncmp(env, "info", len) == 0) { 705db71995Sopenharmony_ci g_loader_debug |= VULKAN_LOADER_INFO_BIT; 715db71995Sopenharmony_ci } else if (strncmp(env, "perf", len) == 0) { 725db71995Sopenharmony_ci g_loader_debug |= VULKAN_LOADER_PERF_BIT; 735db71995Sopenharmony_ci } else if (strncmp(env, "error", len) == 0) { 745db71995Sopenharmony_ci g_loader_debug |= VULKAN_LOADER_ERROR_BIT; 755db71995Sopenharmony_ci } else if (strncmp(env, "debug", len) == 0) { 765db71995Sopenharmony_ci g_loader_debug |= VULKAN_LOADER_DEBUG_BIT; 775db71995Sopenharmony_ci } else if (strncmp(env, "layer", len) == 0) { 785db71995Sopenharmony_ci g_loader_debug |= VULKAN_LOADER_LAYER_BIT; 795db71995Sopenharmony_ci } else if (strncmp(env, "driver", len) == 0 || strncmp(env, "implem", len) == 0 || strncmp(env, "icd", len) == 0) { 805db71995Sopenharmony_ci g_loader_debug |= VULKAN_LOADER_DRIVER_BIT; 815db71995Sopenharmony_ci } 825db71995Sopenharmony_ci } 835db71995Sopenharmony_ci 845db71995Sopenharmony_ci if (!p) break; 855db71995Sopenharmony_ci 865db71995Sopenharmony_ci env = p + 1; 875db71995Sopenharmony_ci } 885db71995Sopenharmony_ci 895db71995Sopenharmony_ci loader_free_getenv(orig, NULL); 905db71995Sopenharmony_ci} 915db71995Sopenharmony_ci 925db71995Sopenharmony_civoid loader_set_global_debug_level(uint32_t new_loader_debug) { g_loader_debug = new_loader_debug; } 935db71995Sopenharmony_ci 945db71995Sopenharmony_civoid loader_log(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code, const char *format, ...) { 955db71995Sopenharmony_ci (void)msg_code; 965db71995Sopenharmony_ci char msg[512] = {0}; 975db71995Sopenharmony_ci 985db71995Sopenharmony_ci va_list ap; 995db71995Sopenharmony_ci va_start(ap, format); 1005db71995Sopenharmony_ci int ret = vsnprintf(msg, sizeof(msg), format, ap); 1015db71995Sopenharmony_ci if ((ret >= (int)sizeof(msg)) || ret < 0) { 1025db71995Sopenharmony_ci msg[sizeof(msg) - 1] = '\0'; 1035db71995Sopenharmony_ci } 1045db71995Sopenharmony_ci va_end(ap); 1055db71995Sopenharmony_ci 1065db71995Sopenharmony_ci if (inst) { 1075db71995Sopenharmony_ci VkDebugUtilsMessageSeverityFlagBitsEXT severity = 0; 1085db71995Sopenharmony_ci VkDebugUtilsMessageTypeFlagsEXT type = 0; 1095db71995Sopenharmony_ci VkDebugUtilsMessengerCallbackDataEXT callback_data = {0}; 1105db71995Sopenharmony_ci VkDebugUtilsObjectNameInfoEXT object_name = {0}; 1115db71995Sopenharmony_ci 1125db71995Sopenharmony_ci if ((msg_type & VULKAN_LOADER_INFO_BIT) != 0) { 1135db71995Sopenharmony_ci severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; 1145db71995Sopenharmony_ci } else if ((msg_type & VULKAN_LOADER_WARN_BIT) != 0) { 1155db71995Sopenharmony_ci severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; 1165db71995Sopenharmony_ci } else if ((msg_type & VULKAN_LOADER_ERROR_BIT) != 0) { 1175db71995Sopenharmony_ci severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; 1185db71995Sopenharmony_ci } else if ((msg_type & VULKAN_LOADER_DEBUG_BIT) != 0) { 1195db71995Sopenharmony_ci severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; 1205db71995Sopenharmony_ci } else if ((msg_type & VULKAN_LOADER_LAYER_BIT) != 0 || (msg_type & VULKAN_LOADER_DRIVER_BIT) != 0) { 1215db71995Sopenharmony_ci // Just driver or just layer bit should be treated as an info message in debug utils. 1225db71995Sopenharmony_ci severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; 1235db71995Sopenharmony_ci } 1245db71995Sopenharmony_ci 1255db71995Sopenharmony_ci if ((msg_type & VULKAN_LOADER_PERF_BIT) != 0) { 1265db71995Sopenharmony_ci type = VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; 1275db71995Sopenharmony_ci } else if ((msg_type & VULKAN_LOADER_VALIDATION_BIT) != 0) { 1285db71995Sopenharmony_ci // For loader logging, if it's a validation message, we still want to also keep the general flag as well 1295db71995Sopenharmony_ci // so messages of type validation can still be triggered for general message callbacks. 1305db71995Sopenharmony_ci type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; 1315db71995Sopenharmony_ci } else { 1325db71995Sopenharmony_ci type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; 1335db71995Sopenharmony_ci } 1345db71995Sopenharmony_ci 1355db71995Sopenharmony_ci callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT; 1365db71995Sopenharmony_ci callback_data.pMessageIdName = "Loader Message"; 1375db71995Sopenharmony_ci callback_data.pMessage = msg; 1385db71995Sopenharmony_ci callback_data.objectCount = 1; 1395db71995Sopenharmony_ci callback_data.pObjects = &object_name; 1405db71995Sopenharmony_ci object_name.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 1415db71995Sopenharmony_ci object_name.objectType = VK_OBJECT_TYPE_INSTANCE; 1425db71995Sopenharmony_ci object_name.objectHandle = (uint64_t)(uintptr_t)inst; 1435db71995Sopenharmony_ci 1445db71995Sopenharmony_ci util_SubmitDebugUtilsMessageEXT(inst, severity, type, &callback_data); 1455db71995Sopenharmony_ci } 1465db71995Sopenharmony_ci 1475db71995Sopenharmony_ci // Always log to stderr if this is a fatal error 1485db71995Sopenharmony_ci if (0 == (msg_type & VULKAN_LOADER_FATAL_ERROR_BIT)) { 1495db71995Sopenharmony_ci // Exit early if the current instance settings do not ask for logging to stderr 1505db71995Sopenharmony_ci if (inst && inst->settings.settings_active && 0 == (msg_type & inst->settings.debug_level)) { 1515db71995Sopenharmony_ci return; 1525db71995Sopenharmony_ci // Check the global settings and if that doesn't say to skip, check the environment variable 1535db71995Sopenharmony_ci } else if (0 == (msg_type & g_loader_debug)) { 1545db71995Sopenharmony_ci return; 1555db71995Sopenharmony_ci } 1565db71995Sopenharmony_ci } 1575db71995Sopenharmony_ci 1585db71995Sopenharmony_ci // Only need enough space to create the filter description header for log messages 1595db71995Sopenharmony_ci // Also use the same header for all output 1605db71995Sopenharmony_ci char cmd_line_msg[64]; 1615db71995Sopenharmony_ci size_t cmd_line_size = sizeof(cmd_line_msg); 1625db71995Sopenharmony_ci size_t num_used = 0; 1635db71995Sopenharmony_ci 1645db71995Sopenharmony_ci cmd_line_msg[0] = '\0'; 1655db71995Sopenharmony_ci 1665db71995Sopenharmony_ci// Helper macro which strncat's the given string literal, then updates num_used & cmd_line_end 1675db71995Sopenharmony_ci// Assumes that we haven't used the entire buffer - must manually check this when adding new filter types 1685db71995Sopenharmony_ci// We concat at the end of cmd_line_msg, so that strncat isn't a victim of Schlemiel the Painter 1695db71995Sopenharmony_ci// We write to the end - 1 of cmd_line_msg, as the end is actually a null terminator 1705db71995Sopenharmony_ci#define STRNCAT_TO_BUFFER(string_literal_to_cat) \ 1715db71995Sopenharmony_ci loader_strncat(cmd_line_msg + num_used, cmd_line_size - num_used, string_literal_to_cat, sizeof(string_literal_to_cat)); \ 1725db71995Sopenharmony_ci num_used += sizeof(string_literal_to_cat) - 1; // subtract one to remove the null terminator in the string literal 1735db71995Sopenharmony_ci 1745db71995Sopenharmony_ci if ((msg_type & VULKAN_LOADER_ERROR_BIT) != 0) { 1755db71995Sopenharmony_ci STRNCAT_TO_BUFFER("ERROR"); 1765db71995Sopenharmony_ci } else if ((msg_type & VULKAN_LOADER_WARN_BIT) != 0) { 1775db71995Sopenharmony_ci STRNCAT_TO_BUFFER("WARNING"); 1785db71995Sopenharmony_ci } else if ((msg_type & VULKAN_LOADER_INFO_BIT) != 0) { 1795db71995Sopenharmony_ci STRNCAT_TO_BUFFER("INFO"); 1805db71995Sopenharmony_ci } else if ((msg_type & VULKAN_LOADER_DEBUG_BIT) != 0) { 1815db71995Sopenharmony_ci STRNCAT_TO_BUFFER("DEBUG"); 1825db71995Sopenharmony_ci } 1835db71995Sopenharmony_ci 1845db71995Sopenharmony_ci if ((msg_type & VULKAN_LOADER_PERF_BIT) != 0) { 1855db71995Sopenharmony_ci if (num_used > 1) { 1865db71995Sopenharmony_ci STRNCAT_TO_BUFFER(" | "); 1875db71995Sopenharmony_ci } 1885db71995Sopenharmony_ci STRNCAT_TO_BUFFER("PERF"); 1895db71995Sopenharmony_ci } 1905db71995Sopenharmony_ci if ((msg_type & VULKAN_LOADER_DRIVER_BIT) != 0) { 1915db71995Sopenharmony_ci if (num_used > 1) { 1925db71995Sopenharmony_ci STRNCAT_TO_BUFFER(" | "); 1935db71995Sopenharmony_ci } 1945db71995Sopenharmony_ci STRNCAT_TO_BUFFER("DRIVER"); 1955db71995Sopenharmony_ci } 1965db71995Sopenharmony_ci if ((msg_type & VULKAN_LOADER_LAYER_BIT) != 0) { 1975db71995Sopenharmony_ci if (num_used > 1) { 1985db71995Sopenharmony_ci STRNCAT_TO_BUFFER(" | "); 1995db71995Sopenharmony_ci } 2005db71995Sopenharmony_ci STRNCAT_TO_BUFFER("LAYER"); 2015db71995Sopenharmony_ci } 2025db71995Sopenharmony_ci 2035db71995Sopenharmony_ci // Add a ": " to separate the filters from the message 2045db71995Sopenharmony_ci STRNCAT_TO_BUFFER(": "); 2055db71995Sopenharmony_ci#undef STRNCAT_TO_BUFFER 2065db71995Sopenharmony_ci 2075db71995Sopenharmony_ci // Justifies the output to at least 19 spaces 2085db71995Sopenharmony_ci if (num_used < 19) { 2095db71995Sopenharmony_ci const char *space_buffer = " "; 2105db71995Sopenharmony_ci // Only write (19 - num_used) spaces 2115db71995Sopenharmony_ci loader_strncat(cmd_line_msg + num_used, cmd_line_size - num_used, space_buffer, 19 - num_used); 2125db71995Sopenharmony_ci num_used += sizeof(space_buffer) - 1 - num_used; 2135db71995Sopenharmony_ci } 2145db71995Sopenharmony_ci // Assert that we didn't write more than what is available in cmd_line_msg 2155db71995Sopenharmony_ci assert(cmd_line_size > num_used); 2165db71995Sopenharmony_ci 2175db71995Sopenharmony_ci#if !defined (__OHOS__) 2185db71995Sopenharmony_ci fputs(cmd_line_msg, stderr); 2195db71995Sopenharmony_ci fputs(msg, stderr); 2205db71995Sopenharmony_ci fputc('\n', stderr); 2215db71995Sopenharmony_ci#endif 2225db71995Sopenharmony_ci#if defined(WIN32) 2235db71995Sopenharmony_ci OutputDebugString(cmd_line_msg); 2245db71995Sopenharmony_ci OutputDebugString(msg); 2255db71995Sopenharmony_ci OutputDebugString("\n"); 2265db71995Sopenharmony_ci#endif 2275db71995Sopenharmony_ci 2285db71995Sopenharmony_ci#if defined(__OHOS__) 2295db71995Sopenharmony_ci char result[512 + 64]; 2305db71995Sopenharmony_ci strcpy(result, cmd_line_msg); 2315db71995Sopenharmony_ci strcat(result, msg); 2325db71995Sopenharmony_ci OpenHarmonyLog(msg_type, result); 2335db71995Sopenharmony_ci#endif 2345db71995Sopenharmony_ci} 2355db71995Sopenharmony_ci 2365db71995Sopenharmony_civoid loader_log_asm_function_not_supported(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code, 2375db71995Sopenharmony_ci const char *func_name) { 2385db71995Sopenharmony_ci loader_log(inst, msg_type, msg_code, "Function %s not supported for this physical device", func_name); 2395db71995Sopenharmony_ci} 240