layers: Rework features/flags/disables & enables

Hooked up setting of enables and disables vi the validation_flags
extension, the validation_features extension, the config file, or
an environment variable.

Change-Id: I54f31afe5d630b9a2459839cf9552e8a285f9168
diff --git a/scripts/layer_chassis_generator.py b/scripts/layer_chassis_generator.py
index b2ed023..b7196ed 100644
--- a/scripts/layer_chassis_generator.py
+++ b/scripts/layer_chassis_generator.py
@@ -257,48 +257,51 @@
     std::vector<VkQueueFamilyProperties> queue_family_properties;
 };
 
-// CHECK_DISABLED struct is a container for bools that can block validation checks from being performed.
-// The end goal is to have all checks guarded by a bool. The bools are all "false" by default meaning that all checks
-// are enabled. At CreateInstance time, the user can use the VK_EXT_validation_flags extension to pass in enum values
-// of VkValidationCheckEXT that will selectively disable checks.
-// The VK_EXT_validation_features extension can also be used with the VkValidationFeaturesEXT structure to set
-// disables in the CHECK_DISABLED struct and/or enables in the CHECK_ENABLED struct.
-struct CHECK_DISABLED {
-    bool command_buffer_state;
-    bool create_descriptor_set_layout;
-    bool destroy_buffer_view;       // Skip validation at DestroyBufferView time
-    bool destroy_image_view;        // Skip validation at DestroyImageView time
-    bool destroy_pipeline;          // Skip validation at DestroyPipeline time
-    bool destroy_descriptor_pool;   // Skip validation at DestroyDescriptorPool time
-    bool destroy_framebuffer;       // Skip validation at DestroyFramebuffer time
-    bool destroy_renderpass;        // Skip validation at DestroyRenderpass time
-    bool destroy_image;             // Skip validation at DestroyImage time
-    bool destroy_sampler;           // Skip validation at DestroySampler time
-    bool destroy_command_pool;      // Skip validation at DestroyCommandPool time
-    bool destroy_event;             // Skip validation at DestroyEvent time
-    bool free_memory;               // Skip validation at FreeMemory time
-    bool object_in_use;             // Skip all object in_use checking
-    bool idle_descriptor_set;       // Skip check to verify that descriptor set is no in-use
-    bool push_constant_range;       // Skip push constant range checks
-    bool free_descriptor_sets;      // Skip validation prior to vkFreeDescriptorSets()
-    bool allocate_descriptor_sets;  // Skip validation prior to vkAllocateDescriptorSets()
-    bool update_descriptor_sets;    // Skip validation prior to vkUpdateDescriptorSets()
-    bool wait_for_fences;
-    bool get_fence_state;
-    bool queue_wait_idle;
-    bool device_wait_idle;
-    bool destroy_fence;
-    bool destroy_semaphore;
-    bool destroy_query_pool;
-    bool get_query_pool_results;
-    bool destroy_buffer;
+typedef enum ValidationCheckDisables {
+    VALIDATION_CHECK_DISABLE_DESTROY_PIPELINE,
+    VALIDATION_CHECK_DISABLE_DESTROY_SAMPLER,
+    VALIDATION_CHECK_DISABLE_DESTROY_COMMAND_POOL,
+    VALIDATION_CHECK_DISABLE_DESTROY_SEMAPHORE,
+    VALIDATION_CHECK_DISABLE_DESTROY_DESCRIPTOR_POOL,
+    VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE,
+    VALIDATION_CHECK_DISABLE_CREATE_DESCRIPTOR_SET_LAYOUT,
+    VALIDATION_CHECK_DISABLE_OBJECT_IN_USE,
+    VALIDATION_CHECK_DISABLE_IDLE_DESCRIPTOR_SET,
+    VALIDATION_CHECK_DISABLE_PUSH_CONSTANT_RANGE,
+    VALIDATION_CHECK_DISABLE_ALLOCATE_DESCRIPTOR_SETS,
+    VALIDATION_CHECK_DISABLE_UPDATE_DESCRIPTOR_SETS,
+    VALIDATION_CHECK_DISABLE_WAIT_FOR_FENCES,
+    VALIDATION_CHECK_DISABLE_QUEUE_WAIT_IDLE,
+    VALIDATION_CHECK_DISABLE_DEVICE_WAIT_IDLE,
+} ValidationCheckDisables;
 
-    bool object_tracking;           // Disable object lifetime validation
-    bool core_checks;               // Disable core validation checks
-    bool thread_safety;             // Disable thread safety validation
-    bool stateless_checks;          // Disable stateless validation checks
-    bool handle_wrapping;           // Disable unique handles/handle wrapping
-    bool shader_validation;         // Skip validation for shaders
+
+// CHECK_DISABLED struct is a container for bools that can block validation checks from being performed.
+// These bools are all "false" by default meaning that all checks are enabled. Enum values can be specified
+// via the vk_layer_setting.txt config file or at CreateInstance time via the VK_EXT_validation_features extension
+// that can selectively disable checks.
+struct CHECK_DISABLED {
+    bool destroy_pipeline;                          // Skip validation at DestroyPipeline time
+    bool destroy_sampler;                           // Skip validation at DestroySampler time
+    bool destroy_command_pool;                      // Skip validation at DestroyCommandPool time
+    bool destroy_semaphore;                         // Skip validation at DestroySemaphore time
+    bool destroy_descriptor_pool;                   // Skip validation at DestroyDescriptorPool time
+    bool command_buffer_state;                      // Skip command buffer state validation
+    bool create_descriptor_set_layout;              // Skip validation at CreateDescSetLayout time
+    bool object_in_use;                             // Skip all object in_use checking
+    bool idle_descriptor_set;                       // Skip check to verify that descriptor set is not in-use
+    bool push_constant_range;                       // Skip push constant range checks
+    bool allocate_descriptor_sets;                  // Skip validation prior to vkAllocateDescriptorSets()
+    bool update_descriptor_sets;                    // Skip validation prior to vkUpdateDescriptorSets()
+    bool wait_for_fences;                           // Skip validation at WaitForFences time
+    bool queue_wait_idle;                           // Skip validation at QueueWaitIdle time
+    bool device_wait_idle;                          // Skip validation at DeviceWaitIdle time
+    bool object_tracking;                           // Disable object lifetime validation
+    bool core_checks;                               // Disable core validation checks
+    bool thread_safety;                             // Disable thread safety validation
+    bool stateless_checks;                          // Disable stateless validation checks
+    bool handle_wrapping;                           // Disable unique handles/handle wrapping
+    bool shader_validation;                         // Skip validation for shaders
 
     void SetAll(bool value) { std::fill(&command_buffer_state, &shader_validation + 1, value); }
 };
@@ -535,27 +538,110 @@
     }
 }
 
-// For the given ValidationCheck enum, set all relevant instance disabled flags to true
-void SetDisabledFlags(ValidationObject *instance_data, const VkValidationFlagsEXT *val_flags_struct) {
+
+// Process validation features, flags and settings specified through extensions, a layer settings file, or environment variables
+
+static const std::unordered_map<std::string, VkValidationFeatureDisableEXT> VkValFeatureDisableLookup = {
+    {"VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT", VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT},
+    {"VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT", VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT},
+    {"VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT", VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT},
+    {"VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT", VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT},
+    {"VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT", VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT},
+    {"VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT", VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT},
+    {"VK_VALIDATION_FEATURE_DISABLE_ALL_EXT", VK_VALIDATION_FEATURE_DISABLE_ALL_EXT},
+};
+
+static const std::unordered_map<std::string, ValidationCheckDisables> ValidationDisableLookup = {
+    {"VALIDATION_CHECK_DISABLE_DESTROY_PIPELINE", VALIDATION_CHECK_DISABLE_DESTROY_PIPELINE},
+    {"VALIDATION_CHECK_DISABLE_DESTROY_SAMPLER", VALIDATION_CHECK_DISABLE_DESTROY_SAMPLER},
+    {"VALIDATION_CHECK_DISABLE_DESTROY_COMMAND_POOL", VALIDATION_CHECK_DISABLE_DESTROY_COMMAND_POOL},
+    {"VALIDATION_CHECK_DISABLE_DESTROY_SEMAPHORE", VALIDATION_CHECK_DISABLE_DESTROY_SEMAPHORE},
+    {"VALIDATION_CHECK_DISABLE_DESTROY_DESCRIPTOR_POOL", VALIDATION_CHECK_DISABLE_DESTROY_DESCRIPTOR_POOL},
+    {"VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE", VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE},
+    {"VALIDATION_CHECK_DISABLE_CREATE_DESCRIPTOR_SET_LAYOUT", VALIDATION_CHECK_DISABLE_CREATE_DESCRIPTOR_SET_LAYOUT},
+    {"VALIDATION_CHECK_DISABLE_OBJECT_IN_USE", VALIDATION_CHECK_DISABLE_OBJECT_IN_USE},
+    {"VALIDATION_CHECK_DISABLE_IDLE_DESCRIPTOR_SET", VALIDATION_CHECK_DISABLE_IDLE_DESCRIPTOR_SET},
+    {"VALIDATION_CHECK_DISABLE_PUSH_CONSTANT_RANGE", VALIDATION_CHECK_DISABLE_PUSH_CONSTANT_RANGE},
+    {"VALIDATION_CHECK_DISABLE_ALLOCATE_DESCRIPTOR_SETS", VALIDATION_CHECK_DISABLE_ALLOCATE_DESCRIPTOR_SETS},
+    {"VALIDATION_CHECK_DISABLE_UPDATE_DESCRIPTOR_SETS", VALIDATION_CHECK_DISABLE_UPDATE_DESCRIPTOR_SETS},
+    {"VALIDATION_CHECK_DISABLE_WAIT_FOR_FENCES", VALIDATION_CHECK_DISABLE_WAIT_FOR_FENCES},
+    {"VALIDATION_CHECK_DISABLE_QUEUE_WAIT_IDLE", VALIDATION_CHECK_DISABLE_QUEUE_WAIT_IDLE},
+    {"VALIDATION_CHECK_DISABLE_DEVICE_WAIT_IDLE", VALIDATION_CHECK_DISABLE_DEVICE_WAIT_IDLE},
+};
+
+// Set the local disable flag for settings specified through the VK_EXT_validation_flags extension
+void SetValidationFlags(CHECK_DISABLED* disables, const VkValidationFlagsEXT* val_flags_struct) {
     for (uint32_t i = 0; i < val_flags_struct->disabledValidationCheckCount; ++i) {
         switch (val_flags_struct->pDisabledValidationChecks[i]) {
-        case VK_VALIDATION_CHECK_SHADERS_EXT:
-            instance_data->disabled.shader_validation = true;
-            break;
-        case VK_VALIDATION_CHECK_ALL_EXT:
-            // Set all disabled flags to true
-            instance_data->disabled.SetAll(true);
-            break;
-        default:
-            break;
+            case VK_VALIDATION_CHECK_SHADERS_EXT:
+                disables->shader_validation = true;
+                break;
+            case VK_VALIDATION_CHECK_ALL_EXT:
+                // Set all disabled flags to true
+                disables->SetAll(true);
+                break;
+            default:
+                break;
         }
     }
 }
 
-void SetValidationFeatures(CHECK_DISABLED *disable_data, CHECK_ENABLED *enable_data,
-                           const VkValidationFeaturesEXT *val_features_struct) {
-    for (uint32_t i = 0; i < val_features_struct->disabledValidationFeatureCount; ++i) {
-        switch (val_features_struct->pDisabledValidationFeatures[i]) {
+// Set the local disable flag for the appropriate VALIDATION_CHECK_DISABLE enum
+void SetValidationDisable(CHECK_DISABLED* disable_data, const ValidationCheckDisables disable_id) {
+    switch (disable_id) {
+        case VALIDATION_CHECK_DISABLE_DESTROY_PIPELINE:
+            disable_data->destroy_pipeline = true;
+            break;
+        case VALIDATION_CHECK_DISABLE_DESTROY_SAMPLER:
+            disable_data->destroy_sampler = true;
+            break;
+        case VALIDATION_CHECK_DISABLE_DESTROY_COMMAND_POOL:
+            disable_data->destroy_command_pool = true;
+            break;
+        case VALIDATION_CHECK_DISABLE_DESTROY_SEMAPHORE:
+            disable_data->destroy_semaphore = true;
+            break;
+        case VALIDATION_CHECK_DISABLE_DESTROY_DESCRIPTOR_POOL:
+            disable_data->destroy_descriptor_pool = true;
+            break;
+        case VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE:
+            disable_data->command_buffer_state = true;
+            break;
+        case VALIDATION_CHECK_DISABLE_CREATE_DESCRIPTOR_SET_LAYOUT:
+            disable_data->create_descriptor_set_layout = true;
+            break;
+        case VALIDATION_CHECK_DISABLE_OBJECT_IN_USE:
+            disable_data->object_in_use = true;
+            break;
+        case VALIDATION_CHECK_DISABLE_IDLE_DESCRIPTOR_SET:
+            disable_data->idle_descriptor_set = true;
+            break;
+        case VALIDATION_CHECK_DISABLE_PUSH_CONSTANT_RANGE:
+            disable_data->push_constant_range = true;
+            break;
+        case VALIDATION_CHECK_DISABLE_ALLOCATE_DESCRIPTOR_SETS:
+            disable_data->allocate_descriptor_sets = true;
+            break;
+        case VALIDATION_CHECK_DISABLE_UPDATE_DESCRIPTOR_SETS:
+            disable_data->update_descriptor_sets = true;
+            break;
+        case VALIDATION_CHECK_DISABLE_WAIT_FOR_FENCES:
+            disable_data->wait_for_fences = true;
+            break;
+        case VALIDATION_CHECK_DISABLE_QUEUE_WAIT_IDLE:
+            disable_data->queue_wait_idle = true;
+            break;
+        case VALIDATION_CHECK_DISABLE_DEVICE_WAIT_IDLE:
+            disable_data->device_wait_idle = true;
+            break;
+        default:
+            assert(true);
+    }
+}
+
+// Set the local disable flag for a single VK_VALIDATION_FEATURE_DISABLE_* flag
+void SetValidationFeatureDisable(CHECK_DISABLED* disable_data, const VkValidationFeatureDisableEXT feature_disable) {
+    switch (feature_disable) {
         case VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT:
             disable_data->shader_validation = true;
             break;
@@ -580,10 +666,12 @@
             break;
         default:
             break;
-        }
     }
-    for (uint32_t i = 0; i < val_features_struct->enabledValidationFeatureCount; ++i) {
-        switch (val_features_struct->pEnabledValidationFeatures[i]) {
+}
+
+// Set the local enable flag for a single VK_VALIDATION_FEATURE_ENABLE_* flag
+void SetValidationFeatureEnable(CHECK_ENABLED *enable_data, const VkValidationFeatureEnableEXT feature_enable) {
+    switch (feature_enable) {
         case VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT:
             enable_data->gpu_validation = true;
             break;
@@ -592,10 +680,66 @@
             break;
         default:
             break;
-        }
     }
 }
 
+// Process Validation Features flags specified through the ValidationFeature extension
+void SetValidationFeatures(CHECK_DISABLED *disable_data, CHECK_ENABLED *enable_data,
+                           const VkValidationFeaturesEXT *val_features_struct) {
+    for (uint32_t i = 0; i < val_features_struct->disabledValidationFeatureCount; ++i) {
+        SetValidationFeatureDisable(disable_data, val_features_struct->pDisabledValidationFeatures[i]);
+    }
+    for (uint32_t i = 0; i < val_features_struct->enabledValidationFeatureCount; ++i) {
+        SetValidationFeatureEnable(enable_data, val_features_struct->pEnabledValidationFeatures[i]);
+    }
+}
+
+// Given a string representation of a list of disable enum values, call the appropriate setter function
+void SetLocalDisableSetting(std::string list_of_disables, std::string delimiter, CHECK_DISABLED* disables) {
+    size_t pos = 0;
+    std::string token;
+    while (list_of_disables.length() != 0) {
+        pos = list_of_disables.find(delimiter);
+        if (pos != std::string::npos) {
+            token = list_of_disables.substr(0, pos);
+        } else {
+            pos = list_of_disables.length() - delimiter.length();
+            token = list_of_disables;
+        }
+        if (token.find("VK_VALIDATION_FEATURE_DISABLE_") != std::string::npos) {
+            auto result = VkValFeatureDisableLookup.find(token);
+            if (result != VkValFeatureDisableLookup.end()) {
+                SetValidationFeatureDisable(disables, result->second);
+            }
+        }
+        if (token.find("VALIDATION_CHECK_DISABLE_") != std::string::npos) {
+            auto result = ValidationDisableLookup.find(token);
+            if (result != ValidationDisableLookup.end()) {
+                SetValidationDisable(disables, result->second);
+            }
+        }
+        list_of_disables.erase(0, pos + delimiter.length());
+    }
+}
+
+// Obtain and process disables set via the vk_layer_settings.txt config file or the VK_LAYER_DISABLES environment variable
+void ProcessLocalDisableSettings(const char* layer_description, CHECK_DISABLED* disables) {
+    std::string disable_key = layer_description;
+    disable_key.append(".disables");
+    std::string list_of_config_disables = getLayerOption(disable_key.c_str());
+    std::string list_of_env_disables = GetLayerEnvVar("VK_LAYER_DISABLES");
+#if defined(_WIN32)
+    std::string env_delimiter = ";";
+#else
+    std::string env_delimiter = ":";
+#endif
+    SetLocalDisableSetting(list_of_config_disables, ",", disables);
+    SetLocalDisableSetting(list_of_env_disables, env_delimiter, disables);
+}
+
+
+// Non-code-generated chassis API functions
+
 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
     auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
     if (!ApiParentExtensionEnabled(funcName, layer_data->device_extensions.device_extension_set)) {
@@ -671,6 +815,12 @@
     if (validation_features_ext) {
         SetValidationFeatures(&local_disables, &local_enables, validation_features_ext);
     }
+    const auto *validation_flags_ext = lvl_find_in_chain<VkValidationFlagsEXT>(pCreateInfo->pNext);
+    if (validation_flags_ext) {
+        SetValidationFlags(&local_disables, validation_flags_ext);
+    }
+
+    ProcessLocalDisableSettings(OBJECT_LAYER_DESCRIPTION, &local_disables);
 
     // Create temporary dispatch vector for pre-calls until instance is created
     std::vector<ValidationObject*> local_object_dispatch;
@@ -738,12 +888,6 @@
     framework->api_version = api_version;
     framework->instance_extensions.InitFromInstanceCreateInfo(specified_version, pCreateInfo);
 
-    // Parse any pNext chains for validation features and flags
-    const auto *validation_flags_ext = lvl_find_in_chain<VkValidationFlagsEXT>(pCreateInfo->pNext);
-    if (validation_flags_ext) {
-        SetDisabledFlags(framework, validation_flags_ext);
-    }
-
     layer_debug_messenger_actions(framework->report_data, framework->logging_messenger, pAllocator, OBJECT_LAYER_DESCRIPTION);
 
 #if BUILD_OBJECT_TRACKER