blob: 0957511df686fd2b447f9c5e2db18e14dfada2b7 [file] [log] [blame]
Jon Ashburnbe582642014-12-22 12:04:40 -07001/**************************************************************************
2 *
Mark Lobodzinski2af57ec2019-03-20 09:17:56 -06003 * Copyright 2014-2019 Valve Software
4 * Copyright 2015-2019 Google Inc.
5 * Copyright 2019 LunarG, Inc.
Jon Ashburnbe582642014-12-22 12:04:40 -07006 * All Rights Reserved.
7 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -06008 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Jon Ashburnbe582642014-12-22 12:04:40 -070011 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -060012 * http://www.apache.org/licenses/LICENSE-2.0
Jon Ashburnbe582642014-12-22 12:04:40 -070013 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -060014 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
Jon Ashburnbe582642014-12-22 12:04:40 -070019 *
Jon Ashburne922f712015-11-03 13:41:23 -070020 * Author: Jon Ashburn <jon@lunarg.com>
21 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
22 * Author: Tobin Ehlis <tobin@lunarg.com>
Mark Lobodzinski97c4d512016-05-19 15:27:18 -060023 * Author: Mark Lobodzinski <mark@lunarg.com>
Jon Ashburnbe582642014-12-22 12:04:40 -070024 **************************************************************************/
Tobin Ehlisa0cb02e2015-07-03 10:15:26 -060025#include "vk_layer_config.h"
David Pinedo9316d3b2015-11-06 12:54:48 -070026#include "vulkan/vk_sdk_platform.h"
Lenny Komow807ebf02016-09-30 14:15:25 -060027#include <fstream>
28#include <iostream>
29#include <map>
Lenny Komow5c57fcb2018-10-02 09:18:51 -060030#include <sstream>
Lenny Komow807ebf02016-09-30 14:15:25 -060031#include <string.h>
32#include <string>
33#include <sys/stat.h>
34#include <vulkan/vk_layer.h>
Jon Ashburnbe582642014-12-22 12:04:40 -070035
Mark Lobodzinskid5aa8de2018-02-02 13:58:41 -070036#if defined(_WIN32)
Martin Herkt094130b2018-03-06 22:44:13 +010037#include <windows.h>
Mark Lobodzinskid5aa8de2018-02-02 13:58:41 -070038#endif
39
Jon Ashburnbe582642014-12-22 12:04:40 -070040#define MAX_CHARS_PER_LINE 4096
41
Jon Ashburn5484e0c2016-03-08 17:48:44 -070042class ConfigFile {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -070043 public:
Jon Ashburnbe582642014-12-22 12:04:40 -070044 ConfigFile();
45 ~ConfigFile();
46
47 const char *getOption(const std::string &_option);
Jon Ashburndec60512015-01-13 17:24:01 -070048 void setOption(const std::string &_option, const std::string &_val);
Mark Lobodzinski2af57ec2019-03-20 09:17:56 -060049 std::string vk_layer_disables_env_var{};
Jon Ashburndec60512015-01-13 17:24:01 -070050
Mark Lobodzinski64318ba2017-01-26 13:34:13 -070051 private:
Jon Ashburnbe582642014-12-22 12:04:40 -070052 bool m_fileIsParsed;
53 std::map<std::string, std::string> m_valueMap;
54
Lenny Komow5c57fcb2018-10-02 09:18:51 -060055 std::string FindSettings();
Jon Ashburnbe582642014-12-22 12:04:40 -070056 void parseFile(const char *filename);
57};
58
59static ConfigFile g_configFileObj;
Jon Ashburndec60512015-01-13 17:24:01 -070060
Lenny Komow807ebf02016-09-30 14:15:25 -060061std::string getEnvironment(const char *variable) {
62#if !defined(__ANDROID__) && !defined(_WIN32)
63 const char *output = getenv(variable);
64 return output == NULL ? "" : output;
65#elif defined(_WIN32)
66 int size = GetEnvironmentVariable(variable, NULL, 0);
67 if (size == 0) {
68 return "";
69 }
70 char *buffer = new char[size];
71 GetEnvironmentVariable(variable, buffer, size);
72 std::string output = buffer;
73 delete[] buffer;
74 return output;
75#else
76 return "";
77#endif
78}
79
Mark Lobodzinski07954a52018-02-01 12:14:30 -070080VK_LAYER_EXPORT const char *getLayerOption(const char *_option) { return g_configFileObj.getOption(_option); }
Mark Lobodzinski2af57ec2019-03-20 09:17:56 -060081VK_LAYER_EXPORT const char *GetLayerEnvVar(const char *_option) {
82 g_configFileObj.vk_layer_disables_env_var = getEnvironment(_option);
83 return g_configFileObj.vk_layer_disables_env_var.c_str();
84}
Jon Ashburnbe582642014-12-22 12:04:40 -070085
Tobin Ehlisb1df55e2015-09-15 09:55:54 -060086// If option is NULL or stdout, return stdout, otherwise try to open option
Mark Lobodzinski97c4d512016-05-19 15:27:18 -060087// as a filename. If successful, return file handle, otherwise stdout
Mark Lobodzinski07954a52018-02-01 12:14:30 -070088VK_LAYER_EXPORT FILE *getLayerLogOutput(const char *_option, const char *layerName) {
Jon Ashburn5484e0c2016-03-08 17:48:44 -070089 FILE *log_output = NULL;
Tobin Ehlisb1df55e2015-09-15 09:55:54 -060090 if (!_option || !strcmp("stdout", _option))
91 log_output = stdout;
92 else {
93 log_output = fopen(_option, "w");
94 if (log_output == NULL) {
95 if (_option)
Jon Ashburn5484e0c2016-03-08 17:48:44 -070096 std::cout << std::endl
97 << layerName << " ERROR: Bad output filename specified: " << _option << ". Writing to STDOUT instead"
98 << std::endl
99 << std::endl;
Tobin Ehlisb1df55e2015-09-15 09:55:54 -0600100 log_output = stdout;
101 }
102 }
Cody Northrope3e39ef2015-09-16 08:35:29 -0600103 return log_output;
Tobin Ehlisb1df55e2015-09-15 09:55:54 -0600104}
105
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600106// Map option strings to flag enum values
Mark Lobodzinski07954a52018-02-01 12:14:30 -0700107VK_LAYER_EXPORT VkFlags GetLayerOptionFlags(std::string _option, std::unordered_map<std::string, VkFlags> const &enum_data,
108 uint32_t option_default) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600109 VkDebugReportFlagsEXT flags = option_default;
110 std::string option_list = g_configFileObj.getOption(_option.c_str());
Courtney Goeltzenleuchterb874b8c2015-06-14 11:34:49 -0600111
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600112 while (option_list.length() != 0) {
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600113 // Find length of option string
114 std::size_t option_length = option_list.find(",");
115 if (option_length == option_list.npos) {
116 option_length = option_list.size();
Courtney Goeltzenleuchterb874b8c2015-06-14 11:34:49 -0600117 }
118
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600119 // Get first option in list
120 const std::string option = option_list.substr(0, option_length);
Courtney Goeltzenleuchterb874b8c2015-06-14 11:34:49 -0600121
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600122 auto enum_value = enum_data.find(option);
123 if (enum_value != enum_data.end()) {
124 flags |= enum_value->second;
125 }
126
127 // Remove first option from option_list
128 option_list.erase(0, option_length);
129 // Remove possible comma separator
130 std::size_t char_position = option_list.find(",");
131 if (char_position == 0) {
132 option_list.erase(char_position, 1);
133 }
134 // Remove possible space
135 char_position = option_list.find(" ");
136 if (char_position == 0) {
137 option_list.erase(char_position, 1);
138 }
Courtney Goeltzenleuchterb874b8c2015-06-14 11:34:49 -0600139 }
140 return flags;
141}
142
Mark Lobodzinski07954a52018-02-01 12:14:30 -0700143VK_LAYER_EXPORT void setLayerOption(const char *_option, const char *_val) { g_configFileObj.setOption(_option, _val); }
Jon Ashburndec60512015-01-13 17:24:01 -0700144
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600145// Constructor for ConfigFile. Initialize layers to log error messages to stdout by default. If a vk_layer_settings file is present,
146// its settings will override the defaults.
147ConfigFile::ConfigFile() : m_fileIsParsed(false) {
Mark Lobodzinski13500d32019-03-20 10:06:09 -0600148 m_valueMap["khronos_validation.report_flags"] = "error";
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600149 m_valueMap["lunarg_core_validation.report_flags"] = "error";
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600150 m_valueMap["lunarg_object_tracker.report_flags"] = "error";
151 m_valueMap["lunarg_parameter_validation.report_flags"] = "error";
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600152 m_valueMap["google_threading.report_flags"] = "error";
Mark Lobodzinskiad8448e2016-08-26 08:35:19 -0600153 m_valueMap["google_unique_objects.report_flags"] = "error";
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600154
155#ifdef WIN32
156 // For Windows, enable message logging AND OutputDebugString
Mark Lobodzinski13500d32019-03-20 10:06:09 -0600157 m_valueMap["khronos_validation.debug_action"] =
158 "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG,VK_DBG_LAYER_ACTION_DEBUG_OUTPUT";
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700159 m_valueMap["lunarg_core_validation.debug_action"] =
160 "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG,VK_DBG_LAYER_ACTION_DEBUG_OUTPUT";
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700161 m_valueMap["lunarg_object_tracker.debug_action"] =
162 "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG,VK_DBG_LAYER_ACTION_DEBUG_OUTPUT";
163 m_valueMap["lunarg_parameter_validation.debug_action"] =
164 "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG,VK_DBG_LAYER_ACTION_DEBUG_OUTPUT";
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700165 m_valueMap["google_threading.debug_action"] =
166 "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG,VK_DBG_LAYER_ACTION_DEBUG_OUTPUT";
167 m_valueMap["google_unique_objects.debug_action"] =
168 "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG,VK_DBG_LAYER_ACTION_DEBUG_OUTPUT";
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700169#else // WIN32
Mark Lobodzinski13500d32019-03-20 10:06:09 -0600170 m_valueMap["khronos_validation.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG";
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600171 m_valueMap["lunarg_core_validation.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG";
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600172 m_valueMap["lunarg_object_tracker.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG";
173 m_valueMap["lunarg_parameter_validation.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG";
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600174 m_valueMap["google_threading.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG";
Mark Lobodzinskiad8448e2016-08-26 08:35:19 -0600175 m_valueMap["google_unique_objects.debug_action"] = "VK_DBG_LAYER_ACTION_DEFAULT,VK_DBG_LAYER_ACTION_LOG_MSG";
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700176#endif // WIN32
Mark Lobodzinski13500d32019-03-20 10:06:09 -0600177 m_valueMap["khronos_validation.log_filename"] = "stdout";
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600178 m_valueMap["lunarg_core_validation.log_filename"] = "stdout";
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600179 m_valueMap["lunarg_object_tracker.log_filename"] = "stdout";
180 m_valueMap["lunarg_parameter_validation.log_filename"] = "stdout";
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600181 m_valueMap["google_threading.log_filename"] = "stdout";
Mark Lobodzinskiad8448e2016-08-26 08:35:19 -0600182 m_valueMap["google_unique_objects.log_filename"] = "stdout";
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600183}
Jon Ashburnbe582642014-12-22 12:04:40 -0700184
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700185ConfigFile::~ConfigFile() {}
Jon Ashburnbe582642014-12-22 12:04:40 -0700186
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700187const char *ConfigFile::getOption(const std::string &_option) {
Jon Ashburnbe582642014-12-22 12:04:40 -0700188 std::map<std::string, std::string>::const_iterator it;
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700189 if (!m_fileIsParsed) {
Lenny Komow5c57fcb2018-10-02 09:18:51 -0600190 std::string settings_file = FindSettings();
191 parseFile(settings_file.c_str());
Jon Ashburnbe582642014-12-22 12:04:40 -0700192 }
193
194 if ((it = m_valueMap.find(_option)) == m_valueMap.end())
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600195 return "";
Jon Ashburnbe582642014-12-22 12:04:40 -0700196 else
197 return it->second.c_str();
198}
199
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700200void ConfigFile::setOption(const std::string &_option, const std::string &_val) {
201 if (!m_fileIsParsed) {
Lenny Komow5c57fcb2018-10-02 09:18:51 -0600202 std::string settings_file = FindSettings();
203 parseFile(settings_file.c_str());
Jon Ashburndec60512015-01-13 17:24:01 -0700204 }
205
206 m_valueMap[_option] = _val;
207}
208
Lenny Komow5c57fcb2018-10-02 09:18:51 -0600209std::string ConfigFile::FindSettings() {
210 struct stat info;
211
212#if defined(WIN32)
213 HKEY hive;
214 LSTATUS err = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Khronos\\Vulkan\\Settings", 0, KEY_READ, &hive);
Lenny Komowc7676c72018-11-20 18:35:22 -0700215 if (err == ERROR_SUCCESS) {
Lenny Komow5c57fcb2018-10-02 09:18:51 -0600216 char name[2048];
217 DWORD i = 0, name_size = sizeof(name), type, value, value_size = sizeof(value);
218 while (ERROR_SUCCESS ==
219 RegEnumValue(hive, i++, name, &name_size, nullptr, &type, reinterpret_cast<LPBYTE>(&value), &value_size)) {
220 // Check if the registry entry is a dword with a value of zero
221 if (type != REG_DWORD || value != 0) {
222 continue;
223 }
224
225 // Check if this actually points to a file
Lenny Komowc7676c72018-11-20 18:35:22 -0700226 if ((stat(name, &info) != 0) || !(info.st_mode & S_IFREG)) {
Lenny Komow5c57fcb2018-10-02 09:18:51 -0600227 continue;
228 }
229
230 // Use this file
231 RegCloseKey(hive);
232 return name;
233 }
234
235 RegCloseKey(hive);
236 }
237#else
238 std::string search_path = getEnvironment("XDG_DATA_HOME");
239 if (search_path == "") {
240 search_path = getEnvironment("HOME");
241 if (search_path != "") {
242 search_path += "/.local/share";
243 }
244 }
245
246 // Use the vk_layer_settings.txt file from here, if it is present
247 if (search_path != "") {
248 std::string home_file = search_path + "/vulkan/settings.d/vk_layer_settings.txt";
249 if (stat(home_file.c_str(), &info) == 0) {
250 if (info.st_mode & S_IFREG) {
251 return home_file;
252 }
253 }
254 }
255
256#endif
257
258 std::string env_path = getEnvironment("VK_LAYER_SETTINGS_PATH");
259
260 // If the path exists use it, else use vk_layer_settings
261 if (stat(env_path.c_str(), &info) == 0) {
262 // If this is a directory, look for vk_layer_settings within the directory
263 if (info.st_mode & S_IFDIR) {
264 return env_path + "/vk_layer_settings.txt";
265 }
266 return env_path;
267 }
268 return "vk_layer_settings.txt";
269}
270
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700271void ConfigFile::parseFile(const char *filename) {
Jon Ashburnbe582642014-12-22 12:04:40 -0700272 std::ifstream file;
273 char buf[MAX_CHARS_PER_LINE];
274
275 m_fileIsParsed = true;
Jon Ashburnbe582642014-12-22 12:04:40 -0700276
277 file.open(filename);
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600278 if (!file.good()) {
Jon Ashburnbe582642014-12-22 12:04:40 -0700279 return;
Mark Lobodzinski97c4d512016-05-19 15:27:18 -0600280 }
281
Jon Ashburnbe582642014-12-22 12:04:40 -0700282 // read tokens from the file and form option, value pairs
283 file.getline(buf, MAX_CHARS_PER_LINE);
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700284 while (!file.eof()) {
Jon Ashburnbe582642014-12-22 12:04:40 -0700285 char option[512];
286 char value[512];
287
288 char *pComment;
289
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700290 // discard any comments delimited by '#' in the line
Jon Ashburnbe582642014-12-22 12:04:40 -0700291 pComment = strchr(buf, '#');
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700292 if (pComment) *pComment = '\0';
Jon Ashburnbe582642014-12-22 12:04:40 -0700293
Jon Ashburn5484e0c2016-03-08 17:48:44 -0700294 if (sscanf(buf, " %511[^\n\t =] = %511[^\n \t]", option, value) == 2) {
Jon Ashburnbe582642014-12-22 12:04:40 -0700295 std::string optStr(option);
296 std::string valStr(value);
297 m_valueMap[optStr] = valStr;
298 }
299 file.getline(buf, MAX_CHARS_PER_LINE);
300 }
301}
302
Mark Young6ba8abe2017-11-09 10:37:04 -0700303VK_LAYER_EXPORT void PrintMessageFlags(VkFlags vk_flags, char *msg_flags) {
Courtney Goeltzenleuchterf85e3612015-06-14 11:33:06 -0600304 bool separator = false;
305
306 msg_flags[0] = 0;
Mark Young6ba8abe2017-11-09 10:37:04 -0700307 if (vk_flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
Courtney Goeltzenleuchterf85e3612015-06-14 11:33:06 -0600308 strcat(msg_flags, "DEBUG");
309 separator = true;
310 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700311 if (vk_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700312 if (separator) strcat(msg_flags, ",");
Courtney Goeltzenleuchterf85e3612015-06-14 11:33:06 -0600313 strcat(msg_flags, "INFO");
314 separator = true;
315 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700316 if (vk_flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700317 if (separator) strcat(msg_flags, ",");
Courtney Goeltzenleuchterf85e3612015-06-14 11:33:06 -0600318 strcat(msg_flags, "WARN");
319 separator = true;
320 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700321 if (vk_flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700322 if (separator) strcat(msg_flags, ",");
Courtney Goeltzenleuchterf85e3612015-06-14 11:33:06 -0600323 strcat(msg_flags, "PERF");
324 separator = true;
325 }
Mark Young6ba8abe2017-11-09 10:37:04 -0700326 if (vk_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700327 if (separator) strcat(msg_flags, ",");
Courtney Goeltzenleuchterf85e3612015-06-14 11:33:06 -0600328 strcat(msg_flags, "ERROR");
329 }
330}
Mark Young6ba8abe2017-11-09 10:37:04 -0700331
332VK_LAYER_EXPORT void PrintMessageSeverity(VkFlags vk_flags, char *msg_flags) {
333 bool separator = false;
334
335 msg_flags[0] = 0;
336 if (vk_flags & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
337 strcat(msg_flags, "VERBOSE");
338 separator = true;
339 }
340 if (vk_flags & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
341 if (separator) strcat(msg_flags, ",");
342 strcat(msg_flags, "INFO");
343 separator = true;
344 }
345 if (vk_flags & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
346 if (separator) strcat(msg_flags, ",");
347 strcat(msg_flags, "WARN");
348 separator = true;
349 }
350 if (vk_flags & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
351 if (separator) strcat(msg_flags, ",");
352 strcat(msg_flags, "ERROR");
353 }
354}
355
356VK_LAYER_EXPORT void PrintMessageType(VkFlags vk_flags, char *msg_flags) {
357 bool separator = false;
358
359 msg_flags[0] = 0;
360 if (vk_flags & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) {
361 strcat(msg_flags, "GEN");
362 separator = true;
363 }
364 if (vk_flags & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) {
365 strcat(msg_flags, "SPEC");
366 separator = true;
367 }
368 if (vk_flags & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) {
369 if (separator) strcat(msg_flags, ",");
370 strcat(msg_flags, "PERF");
371 separator = true;
372 }
373}