1 /************************************************************************** 2 * 3 * Copyright 2014 Valve Software 4 * Copyright 2015 Google Inc. 5 * All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 * THE SOFTWARE. 24 * 25 * Author: Jon Ashburn <jon (at) lunarg.com> 26 * Author: Courtney Goeltzenleuchter <courtney (at) LunarG.com> 27 * Author: Tobin Ehlis <tobin (at) lunarg.com> 28 **************************************************************************/ 29 #include <fstream> 30 #include <string> 31 #include <map> 32 #include <string.h> 33 #include <vulkan/vk_layer.h> 34 #include <iostream> 35 #include "vk_layer_config.h" 36 #include "vulkan/vk_sdk_platform.h" 37 38 #define MAX_CHARS_PER_LINE 4096 39 40 class ConfigFile { 41 public: 42 ConfigFile(); 43 ~ConfigFile(); 44 45 const char *getOption(const std::string &_option); 46 void setOption(const std::string &_option, const std::string &_val); 47 48 private: 49 bool m_fileIsParsed; 50 std::map<std::string, std::string> m_valueMap; 51 52 void parseFile(const char *filename); 53 }; 54 55 static ConfigFile g_configFileObj; 56 57 static VkLayerDbgAction stringToDbgAction(const char *_enum) { 58 // only handles single enum values 59 if (!strcmp(_enum, "VK_DBG_LAYER_ACTION_IGNORE")) 60 return VK_DBG_LAYER_ACTION_IGNORE; 61 else if (!strcmp(_enum, "VK_DBG_LAYER_ACTION_LOG_MSG")) 62 return VK_DBG_LAYER_ACTION_LOG_MSG; 63 #ifdef WIN32 64 else if (!strcmp(_enum, "VK_DBG_LAYER_ACTION_DEBUG_OUTPUT")) 65 return VK_DBG_LAYER_ACTION_DEBUG_OUTPUT; 66 #endif 67 else if (!strcmp(_enum, "VK_DBG_LAYER_ACTION_BREAK")) 68 return VK_DBG_LAYER_ACTION_BREAK; 69 return (VkLayerDbgAction)0; 70 } 71 72 static VkFlags stringToDbgReportFlags(const char *_enum) { 73 // only handles single enum values 74 if (!strcmp(_enum, "VK_DEBUG_REPORT_INFO")) 75 return VK_DEBUG_REPORT_INFORMATION_BIT_EXT; 76 else if (!strcmp(_enum, "VK_DEBUG_REPORT_WARN")) 77 return VK_DEBUG_REPORT_WARNING_BIT_EXT; 78 else if (!strcmp(_enum, "VK_DEBUG_REPORT_PERF_WARN")) 79 return VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; 80 else if (!strcmp(_enum, "VK_DEBUG_REPORT_ERROR")) 81 return VK_DEBUG_REPORT_ERROR_BIT_EXT; 82 else if (!strcmp(_enum, "VK_DEBUG_REPORT_DEBUG")) 83 return VK_DEBUG_REPORT_DEBUG_BIT_EXT; 84 return (VkFlags)0; 85 } 86 87 static unsigned int convertStringEnumVal(const char *_enum) { 88 unsigned int ret; 89 90 ret = stringToDbgAction(_enum); 91 if (ret) 92 return ret; 93 94 return stringToDbgReportFlags(_enum); 95 } 96 97 const char *getLayerOption(const char *_option) { return g_configFileObj.getOption(_option); } 98 99 // If option is NULL or stdout, return stdout, otherwise try to open option 100 // as a filename. If successful, return file handle, otherwise stdout 101 FILE *getLayerLogOutput(const char *_option, const char *layerName) { 102 FILE *log_output = NULL; 103 if (!_option || !strcmp("stdout", _option)) 104 log_output = stdout; 105 else { 106 log_output = fopen(_option, "w"); 107 if (log_output == NULL) { 108 if (_option) 109 std::cout << std::endl 110 << layerName << " ERROR: Bad output filename specified: " << _option << ". Writing to STDOUT instead" 111 << std::endl 112 << std::endl; 113 log_output = stdout; 114 } 115 } 116 return log_output; 117 } 118 119 VkDebugReportFlagsEXT getLayerOptionFlags(const char *_option, uint32_t optionDefault) { 120 VkDebugReportFlagsEXT flags = optionDefault; 121 const char *option = (g_configFileObj.getOption(_option)); 122 123 /* parse comma-separated options */ 124 while (option) { 125 const char *p = strchr(option, ','); 126 size_t len; 127 128 if (p) 129 len = p - option; 130 else 131 len = strlen(option); 132 133 if (len > 0) { 134 if (strncmp(option, "warn", len) == 0) { 135 flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT; 136 } else if (strncmp(option, "info", len) == 0) { 137 flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT; 138 } else if (strncmp(option, "perf", len) == 0) { 139 flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; 140 } else if (strncmp(option, "error", len) == 0) { 141 flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT; 142 } else if (strncmp(option, "debug", len) == 0) { 143 flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT; 144 } 145 } 146 147 if (!p) 148 break; 149 150 option = p + 1; 151 } 152 return flags; 153 } 154 155 bool getLayerOptionEnum(const char *_option, uint32_t *optionDefault) { 156 bool res; 157 const char *option = (g_configFileObj.getOption(_option)); 158 if (option != NULL) { 159 *optionDefault = convertStringEnumVal(option); 160 res = false; 161 } else { 162 res = true; 163 } 164 return res; 165 } 166 167 void setLayerOptionEnum(const char *_option, const char *_valEnum) { 168 unsigned int val = convertStringEnumVal(_valEnum); 169 char strVal[24]; 170 snprintf(strVal, 24, "%u", val); 171 g_configFileObj.setOption(_option, strVal); 172 } 173 174 void setLayerOption(const char *_option, const char *_val) { g_configFileObj.setOption(_option, _val); } 175 176 ConfigFile::ConfigFile() : m_fileIsParsed(false) {} 177 178 ConfigFile::~ConfigFile() {} 179 180 const char *ConfigFile::getOption(const std::string &_option) { 181 std::map<std::string, std::string>::const_iterator it; 182 if (!m_fileIsParsed) { 183 parseFile("vk_layer_settings.txt"); 184 } 185 186 if ((it = m_valueMap.find(_option)) == m_valueMap.end()) 187 return NULL; 188 else 189 return it->second.c_str(); 190 } 191 192 void ConfigFile::setOption(const std::string &_option, const std::string &_val) { 193 if (!m_fileIsParsed) { 194 parseFile("vk_layer_settings.txt"); 195 } 196 197 m_valueMap[_option] = _val; 198 } 199 200 void ConfigFile::parseFile(const char *filename) { 201 std::ifstream file; 202 char buf[MAX_CHARS_PER_LINE]; 203 204 m_fileIsParsed = true; 205 m_valueMap.clear(); 206 207 file.open(filename); 208 if (!file.good()) 209 return; 210 211 // read tokens from the file and form option, value pairs 212 file.getline(buf, MAX_CHARS_PER_LINE); 213 while (!file.eof()) { 214 char option[512]; 215 char value[512]; 216 217 char *pComment; 218 219 // discard any comments delimited by '#' in the line 220 pComment = strchr(buf, '#'); 221 if (pComment) 222 *pComment = '\0'; 223 224 if (sscanf(buf, " %511[^\n\t =] = %511[^\n \t]", option, value) == 2) { 225 std::string optStr(option); 226 std::string valStr(value); 227 m_valueMap[optStr] = valStr; 228 } 229 file.getline(buf, MAX_CHARS_PER_LINE); 230 } 231 } 232 233 void print_msg_flags(VkFlags msgFlags, char *msg_flags) { 234 bool separator = false; 235 236 msg_flags[0] = 0; 237 if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { 238 strcat(msg_flags, "DEBUG"); 239 separator = true; 240 } 241 if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { 242 if (separator) 243 strcat(msg_flags, ","); 244 strcat(msg_flags, "INFO"); 245 separator = true; 246 } 247 if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { 248 if (separator) 249 strcat(msg_flags, ","); 250 strcat(msg_flags, "WARN"); 251 separator = true; 252 } 253 if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) { 254 if (separator) 255 strcat(msg_flags, ","); 256 strcat(msg_flags, "PERF"); 257 separator = true; 258 } 259 if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { 260 if (separator) 261 strcat(msg_flags, ","); 262 strcat(msg_flags, "ERROR"); 263 } 264 } 265