Mark Lobodzinski | 183746f | 2020-07-21 11:48:18 -0600 | [diff] [blame] | 1 | /* Copyright (c) 2020 The Khronos Group Inc. |
| 2 | * Copyright (c) 2020 Valve Corporation |
| 3 | * Copyright (c) 2020 LunarG, Inc. |
| 4 | * |
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | * you may not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at |
| 8 | * |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
| 16 | * |
| 17 | * Author: Mark Lobodzinski <mark@lunarg.com> |
John Zulauf | a7624e2 | 2020-08-31 16:46:41 -0600 | [diff] [blame^] | 18 | * Author: John Zulauf <jzulauf@lunarg.com> |
Mark Lobodzinski | 183746f | 2020-07-21 11:48:18 -0600 | [diff] [blame] | 19 | */ |
| 20 | |
| 21 | #include "layer_options.h" |
| 22 | |
| 23 | // Set the local disable flag for the appropriate VALIDATION_CHECK_DISABLE enum |
| 24 | void SetValidationDisable(CHECK_DISABLED &disable_data, const ValidationCheckDisables disable_id) { |
| 25 | switch (disable_id) { |
| 26 | case VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE: |
| 27 | disable_data[command_buffer_state] = true; |
| 28 | break; |
| 29 | case VALIDATION_CHECK_DISABLE_OBJECT_IN_USE: |
| 30 | disable_data[object_in_use] = true; |
| 31 | break; |
| 32 | case VALIDATION_CHECK_DISABLE_IDLE_DESCRIPTOR_SET: |
| 33 | disable_data[idle_descriptor_set] = true; |
| 34 | break; |
| 35 | case VALIDATION_CHECK_DISABLE_PUSH_CONSTANT_RANGE: |
| 36 | disable_data[push_constant_range] = true; |
| 37 | break; |
| 38 | case VALIDATION_CHECK_DISABLE_QUERY_VALIDATION: |
| 39 | disable_data[query_validation] = true; |
| 40 | break; |
| 41 | case VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION: |
| 42 | disable_data[image_layout_validation] = true; |
| 43 | break; |
| 44 | default: |
| 45 | assert(true); |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | // Set the local disable flag for a single VK_VALIDATION_FEATURE_DISABLE_* flag |
| 50 | void SetValidationFeatureDisable(CHECK_DISABLED &disable_data, const VkValidationFeatureDisableEXT feature_disable) { |
| 51 | switch (feature_disable) { |
| 52 | case VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT: |
| 53 | disable_data[shader_validation] = true; |
| 54 | break; |
| 55 | case VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT: |
| 56 | disable_data[thread_safety] = true; |
| 57 | break; |
| 58 | case VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT: |
| 59 | disable_data[stateless_checks] = true; |
| 60 | break; |
| 61 | case VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT: |
| 62 | disable_data[object_tracking] = true; |
| 63 | break; |
| 64 | case VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT: |
| 65 | disable_data[core_checks] = true; |
| 66 | break; |
| 67 | case VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT: |
| 68 | disable_data[handle_wrapping] = true; |
| 69 | break; |
| 70 | case VK_VALIDATION_FEATURE_DISABLE_ALL_EXT: |
| 71 | // Set all disabled flags to true |
| 72 | std::fill(disable_data.begin(), disable_data.end(), true); |
| 73 | break; |
| 74 | default: |
| 75 | break; |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | // Set the local enable flag for the appropriate VALIDATION_CHECK_ENABLE enum |
| 80 | void SetValidationEnable(CHECK_ENABLED &enable_data, const ValidationCheckEnables enable_id) { |
| 81 | switch (enable_id) { |
| 82 | case VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_ARM: |
| 83 | enable_data[vendor_specific_arm] = true; |
| 84 | break; |
| 85 | case VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_ALL: |
| 86 | enable_data[vendor_specific_arm] = true; |
| 87 | break; |
| 88 | default: |
| 89 | assert(true); |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | // Set the local enable flag for a single VK_VALIDATION_FEATURE_ENABLE_* flag |
| 94 | void SetValidationFeatureEnable(CHECK_ENABLED &enable_data, const VkValidationFeatureEnableEXT feature_enable) { |
| 95 | switch (feature_enable) { |
| 96 | case VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT: |
| 97 | enable_data[gpu_validation] = true; |
| 98 | break; |
| 99 | case VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT: |
| 100 | enable_data[gpu_validation_reserve_binding_slot] = true; |
| 101 | break; |
| 102 | case VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT: |
| 103 | enable_data[best_practices] = true; |
| 104 | break; |
| 105 | case VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT: |
| 106 | enable_data[debug_printf] = true; |
John Zulauf | a7624e2 | 2020-08-31 16:46:41 -0600 | [diff] [blame^] | 107 | break; |
| 108 | case VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT: |
| 109 | enable_data[sync_validation] = true; |
| 110 | break; |
Mark Lobodzinski | 183746f | 2020-07-21 11:48:18 -0600 | [diff] [blame] | 111 | default: |
| 112 | break; |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | void SetValidationFeatureEnable2(CHECK_ENABLED &enable_data, const VkValidationFeatureEnable feature_enable) { |
| 117 | switch (feature_enable) { |
| 118 | case VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION: |
| 119 | enable_data[sync_validation] = true; |
| 120 | break; |
| 121 | default: |
| 122 | break; |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | // Set the local disable flag for settings specified through the VK_EXT_validation_flags extension |
| 127 | void SetValidationFlags(CHECK_DISABLED &disables, const VkValidationFlagsEXT *val_flags_struct) { |
| 128 | for (uint32_t i = 0; i < val_flags_struct->disabledValidationCheckCount; ++i) { |
| 129 | switch (val_flags_struct->pDisabledValidationChecks[i]) { |
| 130 | case VK_VALIDATION_CHECK_SHADERS_EXT: |
| 131 | disables[shader_validation] = true; |
| 132 | break; |
| 133 | case VK_VALIDATION_CHECK_ALL_EXT: |
| 134 | // Set all disabled flags to true |
| 135 | disables[shader_validation] = true; |
| 136 | break; |
| 137 | default: |
| 138 | break; |
| 139 | } |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | // Process Validation Features flags specified through the ValidationFeature extension |
| 144 | void SetValidationFeatures(CHECK_DISABLED &disable_data, CHECK_ENABLED &enable_data, |
| 145 | const VkValidationFeaturesEXT *val_features_struct) { |
| 146 | for (uint32_t i = 0; i < val_features_struct->disabledValidationFeatureCount; ++i) { |
| 147 | SetValidationFeatureDisable(disable_data, val_features_struct->pDisabledValidationFeatures[i]); |
| 148 | } |
| 149 | for (uint32_t i = 0; i < val_features_struct->enabledValidationFeatureCount; ++i) { |
| 150 | SetValidationFeatureEnable(enable_data, val_features_struct->pEnabledValidationFeatures[i]); |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | std::string GetNextToken(std::string *token_list, const std::string &delimiter, size_t *pos) { |
| 155 | std::string token; |
| 156 | *pos = token_list->find(delimiter); |
| 157 | if (*pos != std::string::npos) { |
| 158 | token = token_list->substr(0, *pos); |
| 159 | } else { |
| 160 | *pos = token_list->length() - delimiter.length(); |
| 161 | token = *token_list; |
| 162 | } |
| 163 | token_list->erase(0, *pos + delimiter.length()); |
| 164 | return token; |
| 165 | } |
| 166 | |
| 167 | // Given a string representation of a list of enable enum values, call the appropriate setter function |
| 168 | void SetLocalEnableSetting(std::string list_of_enables, std::string delimiter, CHECK_ENABLED &enables) { |
| 169 | size_t pos = 0; |
| 170 | std::string token; |
| 171 | while (list_of_enables.length() != 0) { |
| 172 | token = GetNextToken(&list_of_enables, delimiter, &pos); |
| 173 | if (token.find("VK_VALIDATION_FEATURE_ENABLE_") != std::string::npos) { |
| 174 | auto result = VkValFeatureEnableLookup.find(token); |
| 175 | if (result != VkValFeatureEnableLookup.end()) { |
| 176 | SetValidationFeatureEnable(enables, result->second); |
| 177 | } else { |
| 178 | auto result2 = VkValFeatureEnableLookup2.find(token); |
| 179 | if (result2 != VkValFeatureEnableLookup2.end()) { |
| 180 | SetValidationFeatureEnable2(enables, result2->second); |
| 181 | } |
| 182 | } |
| 183 | } else if (token.find("VALIDATION_CHECK_ENABLE_") != std::string::npos) { |
| 184 | auto result = ValidationEnableLookup.find(token); |
| 185 | if (result != ValidationEnableLookup.end()) { |
| 186 | SetValidationEnable(enables, result->second); |
| 187 | } |
| 188 | } |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | // Given a string representation of a list of disable enum values, call the appropriate setter function |
| 193 | void SetLocalDisableSetting(std::string list_of_disables, std::string delimiter, CHECK_DISABLED &disables) { |
| 194 | size_t pos = 0; |
| 195 | std::string token; |
| 196 | while (list_of_disables.length() != 0) { |
| 197 | token = GetNextToken(&list_of_disables, delimiter, &pos); |
| 198 | if (token.find("VK_VALIDATION_FEATURE_DISABLE_") != std::string::npos) { |
| 199 | auto result = VkValFeatureDisableLookup.find(token); |
| 200 | if (result != VkValFeatureDisableLookup.end()) { |
| 201 | SetValidationFeatureDisable(disables, result->second); |
| 202 | } |
| 203 | } else if (token.find("VALIDATION_CHECK_DISABLE_") != std::string::npos) { |
| 204 | auto result = ValidationDisableLookup.find(token); |
| 205 | if (result != ValidationDisableLookup.end()) { |
| 206 | SetValidationDisable(disables, result->second); |
| 207 | } |
| 208 | } |
| 209 | } |
| 210 | } |
| 211 | |
| 212 | uint32_t TokenToUint(std::string &token) { |
| 213 | uint32_t int_id = 0; |
| 214 | if ((token.find("0x") == 0) || token.find("0X") == 0) { // Handle hex format |
| 215 | int_id = std::strtoul(token.c_str(), nullptr, 16); |
| 216 | } else { |
| 217 | int_id = std::strtoul(token.c_str(), nullptr, 10); // Decimal format |
| 218 | } |
| 219 | return int_id; |
| 220 | } |
| 221 | |
| 222 | void CreateFilterMessageIdList(std::string raw_id_list, std::string delimiter, std::vector<uint32_t> &filter_list) { |
| 223 | size_t pos = 0; |
| 224 | std::string token; |
| 225 | while (raw_id_list.length() != 0) { |
| 226 | token = GetNextToken(&raw_id_list, delimiter, &pos); |
| 227 | uint32_t int_id = TokenToUint(token); |
| 228 | if (int_id == 0) { |
| 229 | size_t id_hash = XXH32(token.c_str(), strlen(token.c_str()), 8); // String |
| 230 | if (id_hash != 0) { |
| 231 | int_id = static_cast<uint32_t>(id_hash); |
| 232 | } |
| 233 | } |
| 234 | if ((int_id != 0) && (std::find(filter_list.begin(), filter_list.end(), int_id)) == filter_list.end()) { |
| 235 | filter_list.push_back(int_id); |
| 236 | } |
| 237 | } |
| 238 | } |
| 239 | |
| 240 | void SetCustomStypeInfo(std::string raw_id_list, std::string delimiter) { |
| 241 | size_t pos = 0; |
| 242 | std::string token; |
| 243 | // List format is a list of integer pairs |
| 244 | while (raw_id_list.length() != 0) { |
| 245 | token = GetNextToken(&raw_id_list, delimiter, &pos); |
| 246 | uint32_t stype_id = TokenToUint(token); |
| 247 | token = GetNextToken(&raw_id_list, delimiter, &pos); |
| 248 | uint32_t struct_size_in_bytes = TokenToUint(token); |
| 249 | if ((stype_id != 0) && (struct_size_in_bytes != 0)) { |
| 250 | bool found = false; |
| 251 | // Prevent duplicate entries |
| 252 | for (auto item : custom_stype_info) { |
| 253 | if (item.first == stype_id) { |
| 254 | found = true; |
| 255 | break; |
| 256 | } |
| 257 | } |
| 258 | if (!found) custom_stype_info.push_back(std::make_pair(stype_id, struct_size_in_bytes)); |
| 259 | } |
| 260 | } |
| 261 | } |
| 262 | |
| 263 | uint32_t SetMessageDuplicateLimit(std::string &config_message_limit, std::string &env_message_limit) { |
| 264 | uint32_t limit = 0; |
| 265 | auto GetNum = [](std::string &source_string) { |
| 266 | uint32_t limit = 0; |
| 267 | int radix = ((source_string.find("0x") == 0) ? 16 : 10); |
| 268 | limit = std::strtoul(source_string.c_str(), nullptr, radix); |
| 269 | return limit; |
| 270 | }; |
| 271 | // ENV var takes precedence over settings file |
| 272 | limit = GetNum(env_message_limit); |
| 273 | if (limit == 0) { |
| 274 | limit = GetNum(config_message_limit); |
| 275 | } |
| 276 | return limit; |
| 277 | } |
| 278 | |
| 279 | const VkLayerSettingsEXT *FindSettingsInChain(const void *next) { |
| 280 | const VkBaseOutStructure *current = reinterpret_cast<const VkBaseOutStructure *>(next); |
| 281 | const VkLayerSettingsEXT *found = nullptr; |
| 282 | while (current) { |
| 283 | if (static_cast<VkStructureType>(VK_STRUCTURE_TYPE_INSTANCE_LAYER_SETTINGS_EXT) == current->sType) { |
| 284 | found = reinterpret_cast<const VkLayerSettingsEXT *>(current); |
| 285 | current = nullptr; |
| 286 | } else { |
| 287 | current = current->pNext; |
| 288 | } |
| 289 | } |
| 290 | return found; |
| 291 | } |
| 292 | |
| 293 | // Process enables and disables set though the vk_layer_settings.txt config file or through an environment variable |
| 294 | void ProcessConfigAndEnvSettings(ConfigAndEnvSettings *settings_data) { |
| 295 | const auto layer_settings_ext = FindSettingsInChain(settings_data->pnext_chain); |
| 296 | if (layer_settings_ext) { |
| 297 | for (uint32_t i = 0; i < layer_settings_ext->settingCount; i++) { |
| 298 | auto cur_setting = layer_settings_ext->pSettings[i]; |
| 299 | std::string name(cur_setting.name); |
| 300 | if (name == "enables") { |
| 301 | std::string data(cur_setting.data.arrayString.pCharArray); |
| 302 | SetLocalEnableSetting(data, ",", settings_data->enables); |
| 303 | } else if (name == "disables") { |
| 304 | std::string data(cur_setting.data.arrayString.pCharArray); |
| 305 | SetLocalDisableSetting(data, ",", settings_data->disables); |
| 306 | } else if (name == "message_id_filter") { |
| 307 | std::string data(cur_setting.data.arrayString.pCharArray); |
| 308 | CreateFilterMessageIdList(data, ",", settings_data->message_filter_list); |
| 309 | } else if (name == "duplicate_message_limit") { |
| 310 | *settings_data->duplicate_message_limit = cur_setting.data.value32; |
| 311 | } else if (name == "custom_stype_list") { |
| 312 | if (cur_setting.type == VK_LAYER_SETTING_VALUE_TYPE_STRING_ARRAY_EXT) { |
| 313 | std::string data(cur_setting.data.arrayString.pCharArray); |
| 314 | SetCustomStypeInfo(data, ","); |
| 315 | } else if (cur_setting.type == VK_LAYER_SETTING_VALUE_TYPE_UINT32_ARRAY_EXT) { |
| 316 | for (uint32_t j = 0; j < cur_setting.data.arrayInt32.count / 2; j++) { |
| 317 | auto stype_id = cur_setting.data.arrayInt32.pInt32Array[j * 2]; |
| 318 | auto struct_size = cur_setting.data.arrayInt32.pInt32Array[(j * 2) + 1]; |
| 319 | bool found = false; |
| 320 | // Prevent duplicate entries |
| 321 | for (auto item : custom_stype_info) { |
| 322 | if (item.first == stype_id) { |
| 323 | found = true; |
| 324 | break; |
| 325 | } |
| 326 | } |
| 327 | if (!found) custom_stype_info.push_back(std::make_pair(stype_id, struct_size)); |
| 328 | } |
| 329 | } |
| 330 | } |
| 331 | } |
| 332 | } |
| 333 | const auto *validation_features_ext = lvl_find_in_chain<VkValidationFeaturesEXT>(settings_data->pnext_chain); |
| 334 | if (validation_features_ext) { |
| 335 | SetValidationFeatures(settings_data->disables, settings_data->enables, validation_features_ext); |
| 336 | } |
| 337 | const auto *validation_flags_ext = lvl_find_in_chain<VkValidationFlagsEXT>(settings_data->pnext_chain); |
| 338 | if (validation_flags_ext) { |
| 339 | SetValidationFlags(settings_data->disables, validation_flags_ext); |
| 340 | } |
| 341 | |
| 342 | std::string enable_key(settings_data->layer_description); |
| 343 | std::string disable_key(settings_data->layer_description); |
| 344 | std::string stypes_key(settings_data->layer_description); |
| 345 | std::string filter_msg_key(settings_data->layer_description); |
| 346 | std::string message_limit(settings_data->layer_description); |
| 347 | enable_key.append(".enables"); |
| 348 | disable_key.append(".disables"); |
| 349 | stypes_key.append(".custom_stype_list"); |
| 350 | filter_msg_key.append(".message_id_filter"); |
| 351 | message_limit.append(".duplicate_message_limit"); |
| 352 | std::string list_of_config_enables = getLayerOption(enable_key.c_str()); |
| 353 | std::string list_of_env_enables = GetLayerEnvVar("VK_LAYER_ENABLES"); |
| 354 | std::string list_of_config_disables = getLayerOption(disable_key.c_str()); |
| 355 | std::string list_of_env_disables = GetLayerEnvVar("VK_LAYER_DISABLES"); |
| 356 | std::string list_of_config_filter_ids = getLayerOption(filter_msg_key.c_str()); |
| 357 | std::string list_of_env_filter_ids = GetLayerEnvVar("VK_LAYER_MESSAGE_ID_FILTER"); |
| 358 | std::string list_of_config_stypes = getLayerOption(stypes_key.c_str()); |
| 359 | std::string list_of_env_stypes = GetLayerEnvVar("VK_LAYER_CUSTOM_STYPE_LIST"); |
| 360 | std::string config_message_limit = getLayerOption(message_limit.c_str()); |
| 361 | std::string env_message_limit = GetLayerEnvVar("VK_LAYER_DUPLICATE_MESSAGE_LIMIT"); |
| 362 | |
| 363 | #if defined(_WIN32) |
| 364 | std::string env_delimiter = ";"; |
| 365 | #else |
| 366 | std::string env_delimiter = ":"; |
| 367 | #endif |
| 368 | // Process layer enables and disable settings |
| 369 | SetLocalEnableSetting(list_of_config_enables, ",", settings_data->enables); |
| 370 | SetLocalEnableSetting(list_of_env_enables, env_delimiter, settings_data->enables); |
| 371 | SetLocalDisableSetting(list_of_config_disables, ",", settings_data->disables); |
| 372 | SetLocalDisableSetting(list_of_env_disables, env_delimiter, settings_data->disables); |
| 373 | // Process message filter ID list |
| 374 | CreateFilterMessageIdList(list_of_config_filter_ids, ",", settings_data->message_filter_list); |
| 375 | CreateFilterMessageIdList(list_of_env_filter_ids, env_delimiter, settings_data->message_filter_list); |
| 376 | // Process custom stype struct list |
| 377 | SetCustomStypeInfo(list_of_config_stypes, ","); |
| 378 | SetCustomStypeInfo(list_of_env_stypes, env_delimiter); |
| 379 | // Process message limit |
| 380 | uint32_t config_limit_setting = SetMessageDuplicateLimit(config_message_limit, env_message_limit); |
| 381 | if (config_limit_setting != 0) { |
| 382 | *settings_data->duplicate_message_limit = config_limit_setting; |
| 383 | } |
| 384 | } |