• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
36 class 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 
51 static ConfigFile g_configFileObj;
52 
getEnvironment(const char * variable)53 std::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 
getLayerOption(const char * _option)72 const 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
getLayerLogOutput(const char * _option,const char * layerName)76 FILE *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
GetLayerOptionFlags(std::string _option,std::unordered_map<std::string,VkFlags> const & enum_data,uint32_t option_default)95 VkFlags 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 
setLayerOption(const char * _option,const char * _val)132 void 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.
ConfigFile()136 ConfigFile::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 
~ConfigFile()173 ConfigFile::~ConfigFile() {}
174 
getOption(const std::string & _option)175 const 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 
setOption(const std::string & _option,const std::string & _val)199 void 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 
parseFile(const char * filename)219 void 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 
print_msg_flags(VkFlags msgFlags,char * msg_flags)253 void 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