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@lunarg.com>
26 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
27 * Author: Tobin Ehlis <tobin@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
stringToDbgAction(const char * _enum)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
stringToDbgReportFlags(const char * _enum)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
convertStringEnumVal(const char * _enum)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
getLayerOption(const char * _option)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
getLayerLogOutput(const char * _option,const char * layerName)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
getLayerOptionFlags(const char * _option,uint32_t optionDefault)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
getLayerOptionEnum(const char * _option,uint32_t * optionDefault)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
setLayerOptionEnum(const char * _option,const char * _valEnum)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
setLayerOption(const char * _option,const char * _val)174 void setLayerOption(const char *_option, const char *_val) { g_configFileObj.setOption(_option, _val); }
175
ConfigFile()176 ConfigFile::ConfigFile() : m_fileIsParsed(false) {}
177
~ConfigFile()178 ConfigFile::~ConfigFile() {}
179
getOption(const std::string & _option)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
setOption(const std::string & _option,const std::string & _val)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
parseFile(const char * filename)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
print_msg_flags(VkFlags msgFlags,char * msg_flags)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