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