1/************************************************************************** 2 * 3 * Copyright 2014 Valve Software 4 * Copyright 2015 Google Inc. 5 * All Rights Reserved. 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: Tobin Ehlis <tobin@lunarg.com> 22 * Author: Mark Lobodzinski <mark@lunarg.com> 23 **************************************************************************/ 24#include "vk_layer_config.h" 25#include "vulkan/vk_sdk_platform.h" 26#include <fstream> 27#include <iostream> 28#include <map> 29#include <string.h> 30#include <string> 31#include <sys/stat.h> 32#include <vulkan/vk_layer.h> 33 34#define MAX_CHARS_PER_LINE 4096 35 36class ConfigFile { 37 public: 38 ConfigFile(); 39 ~ConfigFile(); 40 41 const char *getOption(const std::string &_option); 42 void setOption(const std::string &_option, const std::string &_val); 43 44 private: 45 bool m_fileIsParsed; 46 std::map<std::string, std::string> m_valueMap; 47 48 void parseFile(const char *filename); 49}; 50 51static ConfigFile g_configFileObj; 52 53std::string getEnvironment(const char *variable) { 54#if !defined(__ANDROID__) && !defined(_WIN32) 55 const char *output = getenv(variable); 56 return output == NULL ? "" : output; 57#elif defined(_WIN32) 58 int size = GetEnvironmentVariable(variable, NULL, 0); 59 if (size == 0) { 60 return ""; 61 } 62 char *buffer = new char[size]; 63 GetEnvironmentVariable(variable, buffer, size); 64 std::string output = buffer; 65 delete[] buffer; 66 return output; 67#else 68 return ""; 69#endif 70} 71 72const char *getLayerOption(const char *_option) { return g_configFileObj.getOption(_option); } 73 74// If option is NULL or stdout, return stdout, otherwise try to open option 75// as a filename. If successful, return file handle, otherwise stdout 76FILE *getLayerLogOutput(const char *_option, const char *layerName) { 77 FILE *log_output = NULL; 78 if (!_option || !strcmp("stdout", _option)) 79 log_output = stdout; 80 else { 81 log_output = fopen(_option, "w"); 82 if (log_output == NULL) { 83 if (_option) 84 std::cout << std::endl 85 << layerName << " ERROR: Bad output filename specified: " << _option << ". Writing to STDOUT instead" 86 << std::endl 87 << std::endl; 88 log_output = stdout; 89 } 90 } 91 return log_output; 92} 93 94// Map option strings to flag enum values 95VkFlags GetLayerOptionFlags(std::string _option, std::unordered_map<std::string, VkFlags> const &enum_data, 96 uint32_t option_default) { 97 VkDebugReportFlagsEXT flags = option_default; 98 std::string option_list = g_configFileObj.getOption(_option.c_str()); 99 100 while (option_list.length() != 0) { 101 102 // Find length of option string 103 std::size_t option_length = option_list.find(","); 104 if (option_length == option_list.npos) { 105 option_length = option_list.size(); 106 } 107 108 // Get first option in list 109 const std::string option = option_list.substr(0, option_length); 110 111 auto enum_value = enum_data.find(option); 112 if (enum_value != enum_data.end()) { 113 flags |= enum_value->second; 114 } 115 116 // Remove first option from option_list 117 option_list.erase(0, option_length); 118 // Remove possible comma separator 119 std::size_t char_position = option_list.find(","); 120 if (char_position == 0) { 121 option_list.erase(char_position, 1); 122 } 123 // Remove possible space 124 char_position = option_list.find(" "); 125 if (char_position == 0) { 126 option_list.erase(char_position, 1); 127 } 128 } 129 return flags; 130} 131 132void setLayerOption(const char *_option, const char *_val) { g_configFileObj.setOption(_option, _val); } 133 134// Constructor for ConfigFile. Initialize layers to log error messages to stdout by default. If a vk_layer_settings file is present, 135// its settings will override the defaults. 136ConfigFile::ConfigFile() : m_fileIsParsed(false) { 137 m_valueMap["lunarg_core_validation.report_flags"] = "error"; 138 m_valueMap["lunarg_image.report_flags"] = "error"; 139 m_valueMap["lunarg_object_tracker.report_flags"] = "error"; 140 m_valueMap["lunarg_parameter_validation.report_flags"] = "error"; 141 m_valueMap["lunarg_swapchain.report_flags"] = "error"; 142 m_valueMap["google_threading.report_flags"] = "error"; 143 m_valueMap["google_unique_objects.report_flags"] = "error"; 144 145#ifdef WIN32 146 // For Windows, enable message logging AND OutputDebugString 147 m_valueMap["lunarg_core_validation.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG,VK_DBG_LAYER_ACTION_DEBUG_OUTPUT"; 148 m_valueMap["lunarg_image.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG,VK_DBG_LAYER_ACTION_DEBUG_OUTPUT"; 149 m_valueMap["lunarg_object_tracker.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG,VK_DBG_LAYER_ACTION_DEBUG_OUTPUT"; 150 m_valueMap["lunarg_parameter_validation.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG,VK_DBG_LAYER_ACTION_DEBUG_OUTPUT"; 151 m_valueMap["lunarg_swapchain.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG,VK_DBG_LAYER_ACTION_DEBUG_OUTPUT"; 152 m_valueMap["google_threading.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG,VK_DBG_LAYER_ACTION_DEBUG_OUTPUT"; 153 m_valueMap["google_unique_objects.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG,VK_DBG_LAYER_ACTION_DEBUG_OUTPUT"; 154#else // WIN32 155 m_valueMap["lunarg_core_validation.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG"; 156 m_valueMap["lunarg_image.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG"; 157 m_valueMap["lunarg_object_tracker.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG"; 158 m_valueMap["lunarg_parameter_validation.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG"; 159 m_valueMap["lunarg_swapchain.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG"; 160 m_valueMap["google_threading.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG"; 161 m_valueMap["google_unique_objects.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG"; 162#endif // WIN32 163 164 m_valueMap["lunarg_core_validation.log_filename"] = "stdout"; 165 m_valueMap["lunarg_image.log_filename"] = "stdout"; 166 m_valueMap["lunarg_object_tracker.log_filename"] = "stdout"; 167 m_valueMap["lunarg_parameter_validation.log_filename"] = "stdout"; 168 m_valueMap["lunarg_swapchain.log_filename"] = "stdout"; 169 m_valueMap["google_threading.log_filename"] = "stdout"; 170 m_valueMap["google_unique_objects.log_filename"] = "stdout"; 171} 172 173ConfigFile::~ConfigFile() {} 174 175const char *ConfigFile::getOption(const std::string &_option) { 176 std::map<std::string, std::string>::const_iterator it; 177 if (!m_fileIsParsed) { 178 std::string envPath = getEnvironment("VK_LAYER_SETTINGS_PATH"); 179 180 // If the path exists use it, else use vk_layer_settings 181 struct stat info; 182 if (stat(envPath.c_str(), &info) == 0) { 183 // If this is a directory, look for vk_layer_settings within the directory 184 if (info.st_mode & S_IFDIR) { 185 envPath += "/vk_layer_settings.txt"; 186 } 187 parseFile(envPath.c_str()); 188 } else { 189 parseFile("vk_layer_settings.txt"); 190 } 191 } 192 193 if ((it = m_valueMap.find(_option)) == m_valueMap.end()) 194 return ""; 195 else 196 return it->second.c_str(); 197} 198 199void ConfigFile::setOption(const std::string &_option, const std::string &_val) { 200 if (!m_fileIsParsed) { 201 std::string envPath = getEnvironment("VK_LAYER_SETTINGS_PATH"); 202 203 // If the path exists use it, else use vk_layer_settings 204 struct stat info; 205 if (stat(envPath.c_str(), &info) == 0) { 206 // If this is a directory, look for vk_layer_settings within the directory 207 if (info.st_mode & S_IFDIR) { 208 envPath += "/vk_layer_settings.txt"; 209 } 210 parseFile(envPath.c_str()); 211 } else { 212 parseFile("vk_layer_settings.txt"); 213 } 214 } 215 216 m_valueMap[_option] = _val; 217} 218 219void ConfigFile::parseFile(const char *filename) { 220 std::ifstream file; 221 char buf[MAX_CHARS_PER_LINE]; 222 223 m_fileIsParsed = true; 224 225 file.open(filename); 226 if (!file.good()) { 227 return; 228 } 229 230 231 // read tokens from the file and form option, value pairs 232 file.getline(buf, MAX_CHARS_PER_LINE); 233 while (!file.eof()) { 234 char option[512]; 235 char value[512]; 236 237 char *pComment; 238 239 // discard any comments delimited by '#' in the line 240 pComment = strchr(buf, '#'); 241 if (pComment) 242 *pComment = '\0'; 243 244 if (sscanf(buf, " %511[^\n\t =] = %511[^\n \t]", option, value) == 2) { 245 std::string optStr(option); 246 std::string valStr(value); 247 m_valueMap[optStr] = valStr; 248 } 249 file.getline(buf, MAX_CHARS_PER_LINE); 250 } 251} 252 253void print_msg_flags(VkFlags msgFlags, char *msg_flags) { 254 bool separator = false; 255 256 msg_flags[0] = 0; 257 if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { 258 strcat(msg_flags, "DEBUG"); 259 separator = true; 260 } 261 if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { 262 if (separator) 263 strcat(msg_flags, ","); 264 strcat(msg_flags, "INFO"); 265 separator = true; 266 } 267 if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { 268 if (separator) 269 strcat(msg_flags, ","); 270 strcat(msg_flags, "WARN"); 271 separator = true; 272 } 273 if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) { 274 if (separator) 275 strcat(msg_flags, ","); 276 strcat(msg_flags, "PERF"); 277 separator = true; 278 } 279 if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { 280 if (separator) 281 strcat(msg_flags, ","); 282 strcat(msg_flags, "ERROR"); 283 } 284} 285