blob: 1b83a9ad29f9514ba7119611c24b9f05655cf741 [file] [edit]
/* Copyright (c) 2020-2026 The Khronos Group Inc.
* Copyright (c) 2020-2026 Valve Corporation
* Copyright (c) 2020-2026 LunarG, Inc.
* Copyright (c) 2026 RasterGrid Kft.
* Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "layer_options.h"
#include <vulkan/vulkan_core.h>
#include "chassis/validation_object.h"
#include "containers/span.h"
#include "error_message/log_message_type.h"
#include "error_message/logging.h"
#include "error_message/error_location.h"
#include "generated/error_location_helper.h"
#include "generated/vk_validation_error_messages.h"
#include "utils/hash_util.h"
#include <cstring>
#include <string>
#include <vector>
#include <vulkan/layer/vk_layer_settings.hpp>
#include "gpuav/core/gpuav_settings.h"
#include "sync/sync_settings.h"
#include "gpu_dump/gpu_dump_settings.h"
#include "legacy/legacy_settings.h"
#include "utils/math_utils.h"
#include "vk_layer_config.h"
// Include new / delete overrides if using mimalloc. This needs to be include exactly once in a file that is
// part of the VVL but not the layer utils library.
#if defined(USE_MIMALLOC) && defined(_WIN64)
#include "mimalloc-new-delete.h"
#endif
const auto& VkValFeatureDisableLookup() {
static const vvl::unordered_map<std::string, VkValidationFeatureDisableEXT> vk_val_feature_disable_lookup = {
{"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_SHADER_VALIDATION_CACHE_EXT", VK_VALIDATION_FEATURE_DISABLE_SHADER_VALIDATION_CACHE_EXT},
{"VK_VALIDATION_FEATURE_DISABLE_ALL_EXT", VK_VALIDATION_FEATURE_DISABLE_ALL_EXT},
};
return vk_val_feature_disable_lookup;
}
const auto& VkValFeatureEnableLookup() {
static const vvl::unordered_map<std::string, VkValidationFeatureEnableEXT> vk_val_feature_enable_lookup = {
{"VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT", VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT},
{"VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT",
VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT},
{"VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT", VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT},
{"VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT", VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT},
{"VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT",
VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT},
};
return vk_val_feature_enable_lookup;
}
const auto& ValidationDisableLookup() {
static const vvl::unordered_map<std::string, ValidationCheckDisables> validation_disable_lookup = {
{"VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE", VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE},
{"VALIDATION_CHECK_DISABLE_OBJECT_IN_USE", VALIDATION_CHECK_DISABLE_OBJECT_IN_USE},
{"VALIDATION_CHECK_DISABLE_QUERY_VALIDATION", VALIDATION_CHECK_DISABLE_QUERY_VALIDATION},
{"VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION", VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION},
};
return validation_disable_lookup;
}
const auto& ValidationEnableLookup() {
static const vvl::unordered_map<std::string, ValidationCheckEnables> validation_enable_lookup = {
{"VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_ARM", VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_ARM},
{"VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_AMD", VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_AMD},
{"VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_IMG", VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_IMG},
{"VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_NVIDIA", VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_NVIDIA},
{"VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_ALL", VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_ALL},
};
return validation_enable_lookup;
}
// To enable "my_setting",
// Set env var VK_LAYER_MY_SETTING to 1
//
// The ["VK_LAYER_" + toUpper(key)] logic is don in vk_layer_setting (VUL)
//
// To quickly be able to find the env var corresponding to a setting,
// the following `const char*` holding setting names match their corresponding environment variable
// Corresponding to VkValidationFeatureEnableEXT
// ---
const char* VK_LAYER_ENABLES = "enables";
const char* VK_LAYER_VALIDATE_BEST_PRACTICES = "validate_best_practices";
const char* VK_LAYER_VALIDATE_BEST_PRACTICES_ARM = "validate_best_practices_arm";
const char* VK_LAYER_VALIDATE_BEST_PRACTICES_AMD = "validate_best_practices_amd";
const char* VK_LAYER_VALIDATE_BEST_PRACTICES_IMG = "validate_best_practices_img";
const char* VK_LAYER_VALIDATE_BEST_PRACTICES_NVIDIA = "validate_best_practices_nvidia";
const char* VK_LAYER_VALIDATE_SYNC = "validate_sync";
// Corresponding to VkValidationFeatureDisableEXT
// ---
const char* VK_LAYER_DISABLES = "disables";
const char* VK_LAYER_CHECK_SHADERS = "check_shaders";
const char* VK_LAYER_THREAD_SAFETY = "thread_safety";
const char* VK_LAYER_STATELESS_PARAM = "stateless_param";
const char* VK_LAYER_OBJECT_LIFETIME = "object_lifetime";
const char* VK_LAYER_VALIDATE_CORE = "validate_core";
const char* VK_LAYER_UNIQUE_HANDLES = "unique_handles";
const char* VK_LAYER_CHECK_SHADERS_CACHING = "check_shaders_caching";
// Additional checks exposed in vkconfig, but not in VkValidationFeatureDisableEXT
// ---
// [DEPRECATED]
// After the 1.4.350 SDK we found these were 10 years old and not sure if valuable anymore
// These have not been tested and seem no one is properly checking they are used for newer extensions
// Plan is to remove them, unless we find people are indeed using them
const char* VK_LAYER_CHECK_COMMAND_BUFFER = "check_command_buffer";
const char* VK_LAYER_CHECK_OBJECT_IN_USE = "check_object_in_use";
const char* VK_LAYER_CHECK_QUERY = "check_query";
const char* VK_LAYER_CHECK_IMAGE_LAYOUT = "check_image_layout";
// Options related to debug reporting
// ---
const char* VK_LAYER_MESSAGE_ID_FILTER = "message_id_filter";
const char* VK_LAYER_CUSTOM_STYPE_LIST = "custom_stype_list";
const char* VK_LAYER_ENABLE_MESSAGE_LIMIT = "enable_message_limit";
const char* VK_LAYER_DUPLICATE_MESSAGE_LIMIT = "duplicate_message_limit";
// Global settings
// ---
// Debug settings used for internal development
const char* VK_LAYER_DEBUG_DISABLE_SPIRV_VAL = "debug_disable_spirv_val";
// Used both with GPU-AV and GPU Dump
const char* VK_LAYER_DESCRIPTOR_HASHING = "descriptor_hashing";
const char* VK_LAYER_DESCRIPTOR_HASHING_TOTAL_DESCRIPTORS = "descriptor_hashing_total_descriptors";
// DebugPrintf (which is now part of GPU-AV internally)
// ---
// Quick, single setting to turn on DebugPrintf
const char* VK_LAYER_PRINTF_ONLY_PRESET = "printf_only_preset";
// Was added a new way to set things without having to use VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT
const char* VK_LAYER_PRINTF_ENABLE = "printf_enable";
const char* VK_LAYER_PRINTF_TO_STDOUT = "printf_to_stdout";
const char* VK_LAYER_PRINTF_VERBOSE = "printf_verbose";
const char* VK_LAYER_PRINTF_BUFFER_SIZE = "printf_buffer_size";
// GPU-AV
// ---
const char* VK_LAYER_GPUAV_ENABLE = "gpuav_enable";
const char* VK_LAYER_GPUAV_SAFE_MODE = "gpuav_safe_mode";
const char* VK_LAYER_GPUAV_SHADER_INSTRUMENTATION = "gpuav_shader_instrumentation";
const char* VK_LAYER_GPUAV_DESCRIPTOR_CHECKS = "gpuav_descriptor_checks";
const char* VK_LAYER_GPUAV_BUFFER_ADDRESS_OOB = "gpuav_buffer_address_oob";
const char* VK_LAYER_GPUAV_VALIDATE_TRACE_RAY = "gpuav_validate_trace_ray";
const char* VK_LAYER_GPUAV_MESH_SHADING = "gpuav_mesh_shading";
const char* VK_LAYER_GPUAV_POST_PROCESS_DESCRIPTOR_INDEXING = "gpuav_post_process_descriptor_indexing";
const char* VK_LAYER_GPUAV_VERTEX_ATTRIBUTE_FETCH_OOB = "gpuav_vertex_attribute_fetch_oob";
const char* VK_LAYER_GPUAV_SHADER_SANITIZER = "gpuav_shader_sanitizer";
const char* VK_LAYER_GPUAV_SHARED_MEMORY_DATA_RACE = "gpuav_shared_memory_data_race";
const char* VK_LAYER_GPUAV_MAX_INDICES_COUNT = "gpuav_max_indices_count";
const char* VK_LAYER_GPUAV_SELECT_INSTRUMENTED_SHADERS = "gpuav_select_instrumented_shaders";
const char* VK_LAYER_GPUAV_SHADERS_TO_INSTRUMENT = "gpuav_shaders_to_instrument";
const char* VK_LAYER_GPUAV_CDL_DUMP_PATH = "gpuav_cdl_dump_path";
// This was removed right after 1.4.350 SDK
const char* REMOVED_VK_LAYER_GPUAV_VALIDATE_RAY_QUERY = "gpuav_validate_ray_query";
const char* VK_LAYER_GPUAV_BUFFERS_VALIDATION = "gpuav_buffers_validation";
const char* VK_LAYER_GPUAV_INDIRECT_DRAWS_BUFFERS = "gpuav_indirect_draws_buffers";
const char* VK_LAYER_GPUAV_INDIRECT_DISPATCHES_BUFFERS = "gpuav_indirect_dispatches_buffers";
const char* VK_LAYER_GPUAV_INDIRECT_TRACE_RAYS_BUFFERS = "gpuav_indirect_trace_rays_buffers";
const char* VK_LAYER_GPUAV_BUFFER_COPIES = "gpuav_buffer_copies";
const char* VK_LAYER_GPUAV_COPY_MEMORY_INDIRECT = "gpuav_copy_memory_indirect";
const char* VK_LAYER_GPUAV_INDEX_BUFFERS = "gpuav_index_buffers";
const char* VK_LAYER_GPUAV_ACCELERATION_STRUCTURES_BUILDS = "gpuav_acceleration_structures_builds";
const char* VK_LAYER_GPUAV_RAY_TRACING_BUFFERS_CONSISTENCY = "gpuav_ray_tracing_buffers_consistency";
const char* VK_LAYER_GPUAV_FORCE_ON_ROBUSTNESS = "gpuav_force_on_robustness";
const char* VK_LAYER_GPUAV_DEBUG_DISABLE_ALL = "gpuav_debug_disable_all";
const char* VK_LAYER_GPUAV_DEBUG_VALIDATE_INSTRUMENTED_SHADERS = "gpuav_debug_validate_instrumented_shaders";
const char* VK_LAYER_GPUAV_DEBUG_DUMP_INSTRUMENTED_SHADERS = "gpuav_debug_dump_instrumented_shaders";
const char* VK_LAYER_GPUAV_DEBUG_MAX_INSTRUMENTATIONS_COUNT = "gpuav_debug_max_instrumentations_count";
const char* VK_LAYER_GPUAV_DEBUG_PRINT_INSTRUMENTATION_INFO = "gpuav_debug_print_instrumentation_info";
const char* VK_LAYER_GPUAV_DEBUG_DISABLE_DONTINLINE = "gpuav_debug_disable_dontinline";
// SyncVal
// ---
const char* VK_LAYER_SYNCVAL_FULL_VALIDATION = "syncval_full_validation";
const char* VK_LAYER_SYNCVAL_RECORD_TIME_VALIDATION = "syncval_record_time_validation";
const char* VK_LAYER_SYNCVAL_SHADER_ACCESSES_HEURISTIC = "syncval_shader_accesses_heuristic";
const char* VK_LAYER_SYNCVAL_LOAD_OP_AFTER_STORE_OP_VALIDATION = "syncval_load_op_after_store_op_validation";
const char* VK_LAYER_SYNCVAL_MESSAGE_EXTRA_PROPERTIES = "syncval_message_extra_properties";
// TODO: mark as REMOVED after refactor
const char* VK_LAYER_SYNCVAL_SUBMIT_TIME_VALIDATION = "syncval_submit_time_validation";
// Message Formatting
// ---
const char* VK_LAYER_MESSAGE_FORMAT_JSON = "message_format_json";
const char* VK_LAYER_MESSAGE_FORMAT_DISPLAY_APPLICATION_NAME = "message_format_display_application_name";
// Until post 1.3.290 SDK release, these were not possible to set via environment variables
const char* VK_LAYER_LOG_FILENAME = "log_filename";
const char* VK_LAYER_DEBUG_ACTION = "debug_action";
const char* VK_LAYER_REPORT_FLAGS = "report_flags";
// GPU Dump
// ---
// Used for working with VK_EXT_descriptor_buffer/VK_EXT_descriptor_heap
// Every draw/dispatch/traceRays dump out information about the bound descriptor buffer/heap
const char* VK_LAYER_GPU_DUMP_DESCRIPTORS = "gpu_dump_descriptors";
const char* VK_LAYER_GPU_DUMP_COPY_MEMORY_INDIRECT = "gpu_dump_copy_memory_indirect";
const char* VK_LAYER_GPU_DUMP_DEVICE_GENERATED_COMMANDS = "gpu_dump_device_generated_commands";
// Print to stdout
const char* VK_LAYER_GPU_DUMP_TO_STDOUT = "gpu_dump_to_stdout";
// Legacy Detection
// ---
const char* VK_LAYER_LEGACY_DETECTION = "legacy_detection";
const char* VK_LAYER_LEGACY_DETECTION_MODE = "legacy_detection_mode";
// Don't need any setting helper when using self vvl and don't want unused function warnings
#if !defined(BUILD_SELF_VVL)
// Set the local disable flag for the appropriate VALIDATION_CHECK_DISABLE enum
void SetValidationDisable(ValidationDisabled& disable_data, const ValidationCheckDisables disable_id) {
switch (disable_id) {
case VALIDATION_CHECK_DISABLE_COMMAND_BUFFER_STATE:
disable_data[command_buffer_state] = true;
break;
case VALIDATION_CHECK_DISABLE_OBJECT_IN_USE:
disable_data[object_in_use] = true;
break;
case VALIDATION_CHECK_DISABLE_QUERY_VALIDATION:
disable_data[query_validation] = true;
break;
case VALIDATION_CHECK_DISABLE_IMAGE_LAYOUT_VALIDATION:
disable_data[image_layout_validation] = true;
break;
default:
assert(false);
}
}
// Set the local disable flag for a single VK_VALIDATION_FEATURE_DISABLE_* flag
void SetValidationFeatureDisable(ValidationDisabled& disable_data, const VkValidationFeatureDisableEXT feature_disable) {
switch (feature_disable) {
case VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT:
disable_data[shader_validation] = true;
break;
case VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT:
disable_data[thread_safety] = true;
break;
case VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT:
disable_data[stateless_checks] = true;
break;
case VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT:
disable_data[object_tracking] = true;
break;
case VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT:
disable_data[core_checks] = true;
break;
case VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT:
disable_data[handle_wrapping] = true;
break;
case VK_VALIDATION_FEATURE_DISABLE_SHADER_VALIDATION_CACHE_EXT:
disable_data[shader_validation_caching] = true;
break;
case VK_VALIDATION_FEATURE_DISABLE_ALL_EXT:
// Set all disabled flags to true
std::fill(disable_data.begin(), disable_data.end(), true);
break;
default:
break;
}
}
// Set the local enable flag for the appropriate VALIDATION_CHECK_ENABLE enum
void SetValidationEnable(ValidationEnabled& enable_data, const ValidationCheckEnables enable_id) {
switch (enable_id) {
case VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_ARM:
enable_data[vendor_specific_arm] = true;
break;
case VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_AMD:
enable_data[vendor_specific_amd] = true;
break;
case VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_IMG:
enable_data[vendor_specific_img] = true;
break;
case VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_NVIDIA:
enable_data[vendor_specific_nvidia] = true;
break;
case VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_ALL:
enable_data[vendor_specific_arm] = true;
enable_data[vendor_specific_amd] = true;
enable_data[vendor_specific_img] = true;
enable_data[vendor_specific_nvidia] = true;
break;
default:
assert(false);
}
}
// Set the local enable flag for a single VK_VALIDATION_FEATURE_ENABLE_* flag
void SetValidationFeatureEnable(ValidationEnabled& enable_data, const VkValidationFeatureEnableEXT feature_enable) {
switch (feature_enable) {
case VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT:
enable_data[gpu_validation] = true;
break;
case VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT:
enable_data[gpu_validation_reserve_binding_slot] = true;
break;
case VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT:
enable_data[best_practices] = true;
break;
case VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT:
enable_data[debug_printf_validation] = true;
break;
case VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT:
enable_data[sync_validation] = true;
break;
default:
break;
}
}
// Set the local disable flag for settings specified through the VK_EXT_validation_flags extension
void SetValidationFlags(ValidationDisabled& disabled, 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:
disabled[shader_validation] = true;
break;
case VK_VALIDATION_CHECK_ALL_EXT:
// Set all disabled flags to true
disabled[shader_validation] = true;
break;
default:
break;
}
}
}
// Process Validation Features flags specified through the ValidationFeature extension
void SetValidationFeatures(ValidationDisabled& disable_data, ValidationEnabled& 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]);
}
}
std::string GetNextToken(std::string* token_list, const std::string& delimiter, size_t* pos) {
std::string token;
*pos = token_list->find(delimiter);
if (*pos != std::string::npos) {
token = token_list->substr(0, *pos);
} else {
*pos = token_list->length() - delimiter.length();
token = *token_list;
}
token_list->erase(0, *pos + delimiter.length());
// Remove quotes from quoted strings
if ((token.length() > 0) && (token[0] == '\"')) {
token.erase(token.begin());
if ((token.length() > 0) && (token[token.length() - 1] == '\"')) {
token.erase(--token.end());
}
}
return token;
}
// Given a string representation of a list of enable enum values, call the appropriate setter function
bool SetLocalEnableSetting(std::string list_of_enabled, const std::string& delimiter, ValidationEnabled& enabled) {
bool used = false;
size_t pos = 0;
std::string token;
while (list_of_enabled.length() != 0) {
token = GetNextToken(&list_of_enabled, delimiter, &pos);
if (token.find("VK_VALIDATION_FEATURE_ENABLE_") != std::string::npos) {
auto result = VkValFeatureEnableLookup().find(token);
if (result != VkValFeatureEnableLookup().end()) {
used = true;
SetValidationFeatureEnable(enabled, result->second);
}
} else if (token.find("VALIDATION_CHECK_ENABLE_") != std::string::npos) {
auto result = ValidationEnableLookup().find(token);
if (result != ValidationEnableLookup().end()) {
used = true;
SetValidationEnable(enabled, result->second);
}
}
}
return used;
}
// Given a string representation of a list of disable enum values, call the appropriate setter function
bool SetLocalDisableSetting(std::string list_of_disabled, const std::string& delimiter, ValidationDisabled& disabled) {
bool used = false;
size_t pos = 0;
std::string token;
while (list_of_disabled.length() != 0) {
token = GetNextToken(&list_of_disabled, delimiter, &pos);
if (token.find("VK_VALIDATION_FEATURE_DISABLE_") != std::string::npos) {
auto result = VkValFeatureDisableLookup().find(token);
if (result != VkValFeatureDisableLookup().end()) {
SetValidationFeatureDisable(disabled, result->second);
used = true;
}
} else if (token.find("VALIDATION_CHECK_DISABLE_") != std::string::npos) {
auto result = ValidationDisableLookup().find(token);
if (result != ValidationDisableLookup().end()) {
SetValidationDisable(disabled, result->second);
used = true;
}
}
}
return used;
}
uint32_t TokenToUint(const std::string& token) {
uint32_t int_id = 0;
if ((token.find("0x") == 0) || token.find("0X") == 0) { // Handle hex format
int_id = static_cast<uint32_t>(std::strtoul(token.c_str(), nullptr, 16));
} else {
int_id = static_cast<uint32_t>(std::strtoul(token.c_str(), nullptr, 10)); // Decimal format
}
return int_id;
}
void CreateFilterMessageIdList(const std::vector<std::string>& message_id_filter, vvl::unordered_set<uint32_t>& filter_list) {
for (const std::string& message_id : message_id_filter) {
// There are 3 forms VUID can be filtered
// 1. The VUID hash is provided (can be in hex or dec format)
// 2. Pass in the entire VUID string so we can hash it
// 3. Pass in the VUID final 5 digits and we "glob" all VUs that match
// This mainly is helpful for draw VUs where we have 40 variations
uint32_t filter_id = TokenToUint(message_id);
// Will be non-zero if hash was provided
if (filter_id == 0) {
filter_id = hash_util::VuidHash(message_id);
if (filter_id != 0) {
filter_list.insert(filter_id); // option 2
}
} else if (message_id.length() == 5) {
// User provided the 5 digit, search the VUID list
const vvl::unordered_map<std::string_view, vuid_info> vuid_map = GetVuidMap();
for (const auto& [key, info] : vuid_map) {
std::string_view vuid_digit = key.substr(key.length() - 5);
if (message_id == vuid_digit) {
filter_id = hash_util::VuidHash(key);
if (filter_id != 0) {
filter_list.insert(filter_id); // option 3
}
}
}
} else {
filter_list.insert(filter_id); // option 1
}
}
}
// Because VkLayerSettingsCreateInfoEXT/VkLayerSettingEXT are passed in and used before everything else, need to do the stateless
// validation here as a special exception
//
// We want to use the DebugReport object to print VU error messages in here, but we need to parse the settings in
// VkLayerSettingsCreateInfoEXT in order to configure the DebugReport object. Therefor we just settle with printf in here. These are
// very unlikely things to hit validation layers messages (as everything after will likely crumble) so should be ok.
//
// Returns if valid
static bool ValidateLayerSettingsCreateInfo(const VkLayerSettingsCreateInfoEXT* layer_settings) {
bool valid = true;
if (!layer_settings) return valid;
const Location loc(vvl::Func::vkCreateInstance, vvl::Field::pCreateInfo);
const Location create_info_loc = loc.pNext(vvl::Struct::VkLayerSettingsCreateInfoEXT);
std::ostringstream ss;
if (layer_settings->pSettings) {
for (const auto [i, setting] : vvl::enumerate(layer_settings->pSettings, layer_settings->settingCount)) {
const Location setting_loc = create_info_loc.dot(vvl::Field::pSettings, i);
if (setting.valueCount > 0 && !setting.pValues) {
ss << "[ VUID-VkLayerSettingEXT-valueCount-10070 ] " << setting_loc.dot(vvl::Field::pValues).Message()
<< " is NULL";
printf("Validation Layer Error: %s\n", ss.str().c_str());
valid = false;
}
if (!setting.pLayerName) {
ss << "[ VUID-VkLayerSettingEXT-pLayerName-parameter ] " << setting_loc.dot(vvl::Field::pLayerName).Message()
<< " is NULL";
printf("Validation Layer Error: %s\n", ss.str().c_str());
valid = false;
}
if (!setting.pSettingName) {
ss << "[ VUID-VkLayerSettingEXT-pSettingName-parameter ] " << setting_loc.dot(vvl::Field::pSettingName).Message()
<< " is NULL";
printf("Validation Layer Error: %s\n", ss.str().c_str());
valid = false;
}
// Can assume no new VkLayerSettingTypeEXT will be added
const uint32_t casted_type = (uint32_t)setting.type;
const uint32_t last_setting_type = (uint32_t)VK_LAYER_SETTING_TYPE_STRING_EXT;
if (casted_type > last_setting_type) {
ss << "[ VUID-VkLayerSettingEXT-type-parameter ] " << setting_loc.dot(vvl::Field::type).Message() << " is "
<< casted_type << " which is not a valid VkLayerSettingTypeEXT enum value";
printf("Validation Layer Error: %s\n", ss.str().c_str());
valid = false;
}
}
} else if (layer_settings->settingCount > 0) {
ss << "[ VUID-VkLayerSettingsCreateInfoEXT-pSettings-parameter ] " << create_info_loc.dot(vvl::Field::pSettings).Message()
<< " is NULL";
printf("Validation Layer Error: %s\n", ss.str().c_str());
valid = false;
}
return valid;
}
static void SetValidationSetting(VkuLayerSettingSet layer_setting_set, ValidationDisabled& disable_data,
const DisableFlags feature_disable, const char* setting) {
if (vkuHasLayerSetting(layer_setting_set, setting)) {
bool enabled = true;
vkuGetLayerSettingValue(layer_setting_set, setting, enabled);
disable_data[feature_disable] = !enabled;
}
}
static void SetValidationSetting(VkuLayerSettingSet layer_setting_set, ValidationEnabled& enable_data,
const EnableFlags feature_enable, const char* setting) {
if (vkuHasLayerSetting(layer_setting_set, setting)) {
bool enabled = true;
vkuGetLayerSettingValue(layer_setting_set, setting, enabled);
enable_data[feature_enable] = enabled;
}
}
static std::string Merge(const std::vector<std::string>& strings) {
std::string result;
for (std::size_t i = 0, n = strings.size(); i < n; ++i) {
if (!result.empty()) {
result += ",";
}
result += strings[i];
}
return result;
}
// If log_filename is NULL or stdout, return stdout, otherwise try to open log_filename
// as a filename. If successful, return file handle, otherwise stdout
FILE* GetLayerLogOutput(const char* log_filename, std::vector<std::string>& setting_warnings) {
FILE* log_output = NULL;
if (!log_filename || !strcmp("stdout", log_filename)) {
log_output = stdout;
} else {
log_output = fopen(log_filename, "w");
if (log_output == NULL) {
if (log_filename) {
setting_warnings.emplace_back("log_filename (" + std::string(log_filename) +
") could not be opened, falling back to stdout instead.");
}
log_output = stdout;
}
}
return log_output;
}
// Definitions for Debug Actions
enum VkLayerDbgActionBits {
VK_DBG_LAYER_ACTION_IGNORE = 0x00000000,
VK_DBG_LAYER_ACTION_CALLBACK = 0x00000001,
VK_DBG_LAYER_ACTION_LOG_MSG = 0x00000002,
VK_DBG_LAYER_ACTION_BREAK = 0x00000004,
VK_DBG_LAYER_ACTION_DEBUG_OUTPUT = 0x00000008,
VK_DBG_LAYER_ACTION_FAIL = 0x00000010,
VK_DBG_LAYER_ACTION_DEFAULT = 0x40000000,
};
using VkLayerDbgActionFlags = VkFlags;
static void ProcessDebugReportSettings(ConfigAndEnvSettings* settings_data, VkuLayerSettingSet& layer_setting_set,
std::vector<std::string>& setting_warnings) {
DebugReport* debug_report = settings_data->debug_report;
// Message ID Filtering
std::vector<std::string> message_id_filter;
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_MESSAGE_ID_FILTER)) {
vkuGetLayerSettingValues(layer_setting_set, VK_LAYER_MESSAGE_ID_FILTER, message_id_filter);
}
CreateFilterMessageIdList(message_id_filter, debug_report->filter_message_ids);
// Duplicate message limit
bool enable_message_limit = true; // default in JSON
uint32_t duplicate_message_limit = 10; // default in JSON
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_ENABLE_MESSAGE_LIMIT)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_ENABLE_MESSAGE_LIMIT, enable_message_limit);
}
if (enable_message_limit) {
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_DUPLICATE_MESSAGE_LIMIT)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_DUPLICATE_MESSAGE_LIMIT, duplicate_message_limit);
}
} else {
duplicate_message_limit = 0;
}
debug_report->duplicate_message_limit = duplicate_message_limit;
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_MESSAGE_FORMAT_JSON)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_MESSAGE_FORMAT_JSON, debug_report->message_format_settings.json);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_MESSAGE_FORMAT_DISPLAY_APPLICATION_NAME)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_MESSAGE_FORMAT_DISPLAY_APPLICATION_NAME,
debug_report->message_format_settings.display_application_name);
}
std::string log_filename = "stdout"; // Default
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_LOG_FILENAME)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_LOG_FILENAME, log_filename);
}
const bool is_stdout = log_filename.compare("stdout") == 0;
// Default
std::vector<std::string> debug_actions_list = {"VK_DBG_LAYER_ACTION_DEFAULT", "VK_DBG_LAYER_ACTION_LOG_MSG"};
#ifdef _WIN32
// For Windows, enable message logging AND OutputDebugString
debug_actions_list.push_back("VK_DBG_LAYER_ACTION_DEBUG_OUTPUT");
#endif // _WIN32
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_DEBUG_ACTION)) {
vkuGetLayerSettingValues(layer_setting_set, VK_LAYER_DEBUG_ACTION, debug_actions_list);
}
VkLayerDbgActionFlags debug_action = 0;
const vvl::unordered_map<std::string, VkFlags> debug_actions_option = {
{std::string("VK_DBG_LAYER_ACTION_IGNORE"), VK_DBG_LAYER_ACTION_IGNORE},
{std::string("VK_DBG_LAYER_ACTION_CALLBACK"), VK_DBG_LAYER_ACTION_CALLBACK},
{std::string("VK_DBG_LAYER_ACTION_LOG_MSG"), VK_DBG_LAYER_ACTION_LOG_MSG},
{std::string("VK_DBG_LAYER_ACTION_BREAK"), VK_DBG_LAYER_ACTION_BREAK},
{std::string("VK_DBG_LAYER_ACTION_DEBUG_OUTPUT"), VK_DBG_LAYER_ACTION_DEBUG_OUTPUT},
{std::string("VK_DBG_LAYER_ACTION_FAIL"), VK_DBG_LAYER_ACTION_FAIL},
{std::string("VK_DBG_LAYER_ACTION_DEFAULT"), VK_DBG_LAYER_ACTION_DEFAULT}};
for (const auto& element : debug_actions_list) {
auto enum_value = debug_actions_option.find(element);
if (enum_value != debug_actions_option.end()) {
debug_action |= enum_value->second;
} else {
if (element.find(',') != std::string::npos) {
setting_warnings.emplace_back("\"" + element +
"\" was not a valid option for VK_LAYER_DEBUG_ACTION (ignoring).\nIf using "
"VkLayerSettings, each string needs to be its own VkLayerSettingEXT::pValues.");
} else {
setting_warnings.emplace_back(
"\"" + element +
"\" was not a valid option for VK_LAYER_DEBUG_ACTION (ignoring).\nValid options are "
"[VK_DBG_LAYER_ACTION_IGNORE, VK_DBG_LAYER_ACTION_CALLBACK, VK_DBG_LAYER_ACTION_LOG_MSG, "
"VK_DBG_LAYER_ACTION_BREAK, VK_DBG_LAYER_ACTION_DEBUG_OUTPUT, VK_DBG_LAYER_ACTION_FAIL, "
"VK_DBG_LAYER_ACTION_DEFAULT]");
}
}
}
std::vector<std::string> report_flags_list = {"error", "warn"}; // Default
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_REPORT_FLAGS)) {
vkuGetLayerSettingValues(layer_setting_set, VK_LAYER_REPORT_FLAGS, report_flags_list);
}
VkLayerDbgActionFlags report_flags = 0;
const vvl::unordered_map<std::string, VkFlags> report_flags_options = {{std::string("warn"), kWarningBit},
{std::string("info"), kInformationBit},
{std::string("perf"), kPerformanceWarningBit},
{std::string("error"), kErrorBit},
{std::string("verbose"), kVerboseBit}};
for (const auto& element : report_flags_list) {
auto enum_value = report_flags_options.find(element);
if (enum_value != report_flags_options.end()) {
report_flags |= enum_value->second;
} else {
if (element.find(',') != std::string::npos) {
setting_warnings.emplace_back("\"" + element +
"\" was not a valid option for VK_LAYER_REPORT_FLAGS (ignoring)\nIf using "
"VkLayerSettings, each string needs to be its own VkLayerSettingEXT::pValues.");
} else {
setting_warnings.emplace_back("\"" + element +
"\" was not a valid option for VK_LAYER_REPORT_FLAGS (ignoring)\nValid options are "
"[error, warn, info, perf, verbose].");
}
}
}
// Before creating the debug callback, see if other settings interfere
if (settings_data->gpuav_settings->debug_printf_enabled) {
if (settings_data->gpuav_settings->debug_printf_to_stdout && (debug_action & VK_DBG_LAYER_ACTION_LOG_MSG)) {
if (is_stdout) {
setting_warnings.emplace_back(
"The debug callback is already logging to stdout, but " + std::string(VK_LAYER_PRINTF_TO_STDOUT) +
" is also enabled. DebugPrintf will skip the debug callback in favor of a direct stdout write.");
} else {
setting_warnings.emplace_back("The logging to " + log_filename + " will not contain any DebugPrintf info because " +
std::string(VK_LAYER_PRINTF_TO_STDOUT) + " is enabled.");
}
}
if (!settings_data->gpuav_settings->debug_printf_to_stdout && ((report_flags & kInformationBit) == 0)) {
// Normally it is a lot of spam to use kInformationBit, but if only using DebugPrintf, it should be minimal information
// printed
setting_warnings.emplace_back(
"DebugPrintf logs to the Information message severity, enabling Information level logging otherwise the message "
"will not be seen.");
report_flags |= kInformationBit;
}
}
if (settings_data->enabled[legacy_detection] && ((report_flags & kWarningBit) == 0)) {
setting_warnings.emplace_back(
"Legacy Detection logs to the Warning message severity, enabling Warning level logging otherwise the message "
"will not be seen.");
report_flags |= kWarningBit;
}
if (settings_data->enabled[gpu_dump]) {
const bool has_info_bit = (report_flags & kInformationBit) != 0;
const bool has_warn_bit = (report_flags & kWarningBit) != 0;
if (settings_data->gpu_dump_settings->to_stdout) {
if ((debug_action & VK_DBG_LAYER_ACTION_LOG_MSG)) {
if (is_stdout) {
setting_warnings.emplace_back(
"The debug callback is already logging to stdout, but " + std::string(VK_LAYER_GPU_DUMP_TO_STDOUT) +
" is also enabled. GPU Dump will skip the debug callback in favor of a direct stdout write.");
} else {
setting_warnings.emplace_back("The logging to " + log_filename +
" will not contain any GPU Dump info because " +
std::string(VK_LAYER_GPU_DUMP_TO_STDOUT) + " is enabled.");
}
}
} else if (!settings_data->gpu_dump_settings->to_stdout) {
// If the user ONLY wants warning, don't turn on info
// If they forgot both, turn both on
if (!has_info_bit && !has_warn_bit) {
setting_warnings.emplace_back(
"GPU Dump logs to both the Warning and Information message severity, enabling both Warning and Information "
"level logging otherwise the message "
"will not be seen.");
report_flags |= kInformationBit;
report_flags |= kWarningBit;
}
}
// If the user has only info on to get information, that could be seen as a legit usecase
if (has_warn_bit && settings_data->enabled[gpu_validation]) {
setting_warnings.emplace_back(
"GPU Dump and GPU-AV are both enabled and this is NOT desired. GPU Dump warnings are designed to find everything "
"GPU-AV does but in a 'CPU best attempt' fashion. Only use GPU Dump or GPU-AV, not both together.");
}
}
// Flag as default if these settings are not from a vk_layer_settings.txt file
const bool default_layer_callback = (debug_action & VK_DBG_LAYER_ACTION_DEFAULT) != 0;
VkDebugUtilsMessengerCreateInfoEXT dbg_create_info = vku::InitStructHelper();
dbg_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
if (report_flags & kErrorBit) {
dbg_create_info.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
}
if (report_flags & kWarningBit) {
dbg_create_info.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
}
if (report_flags & kPerformanceWarningBit) {
dbg_create_info.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
dbg_create_info.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
}
if (report_flags & kInformationBit) {
dbg_create_info.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
}
if (report_flags & kVerboseBit) {
dbg_create_info.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
}
settings_data->global_settings->only_report_errors = report_flags == kErrorBit;
VkDebugUtilsMessengerEXT messenger = VK_NULL_HANDLE;
if (debug_action & VK_DBG_LAYER_ACTION_LOG_MSG) {
FILE* log_output = GetLayerLogOutput(log_filename.c_str(), setting_warnings);
if (log_output != stdout) {
// This particular warning is designed to show the user where the debug callback is going (which is important to know!),
// so it makes no sense to put the warning in the callback location. For this one only we attempt to print to the
// everywhere else possible
const std::string tmp = "Validation Layer Info - Logging validation error to " + log_filename + "\n";
const char* cstr = tmp.c_str();
printf("%s", cstr);
#ifdef VK_USE_PLATFORM_WIN32_KHR
OutputDebugString(cstr);
#endif
#ifdef VK_USE_PLATFORM_ANDROID_KHR
__android_log_print(ANDROID_LOG_INFO, "VALIDATION", "%s", cstr);
#endif
}
dbg_create_info.pfnUserCallback = MessengerLogCallback;
dbg_create_info.pUserData = (void*)log_output;
LayerCreateMessengerCallback(debug_report, default_layer_callback, &dbg_create_info, &messenger);
} else if (!is_stdout) {
setting_warnings.emplace_back("The log_filename was set to " + log_filename +
" but VK_DBG_LAYER_ACTION_LOG_MSG was not set, so it won't be sent to the file.");
}
#ifdef VK_USE_PLATFORM_WIN32_KHR
messenger = VK_NULL_HANDLE;
if (debug_action & VK_DBG_LAYER_ACTION_DEBUG_OUTPUT) {
dbg_create_info.pfnUserCallback = MessengerWin32DebugOutputMsg;
dbg_create_info.pUserData = nullptr;
LayerCreateMessengerCallback(debug_report, default_layer_callback, &dbg_create_info, &messenger);
}
#endif
messenger = VK_NULL_HANDLE;
if (debug_action & VK_DBG_LAYER_ACTION_BREAK) {
dbg_create_info.pfnUserCallback = MessengerBreakCallback;
dbg_create_info.pUserData = nullptr;
LayerCreateMessengerCallback(debug_report, default_layer_callback, &dbg_create_info, &messenger);
}
messenger = VK_NULL_HANDLE;
if (debug_action & VK_DBG_LAYER_ACTION_FAIL) {
dbg_create_info.pfnUserCallback = MessengerFailCallback;
dbg_create_info.pUserData = nullptr;
LayerCreateMessengerCallback(debug_report, default_layer_callback, &dbg_create_info, &messenger);
}
}
// Set as deprecated for the first time in the 1.4.335 SDK release
static std::string GetDeprecatedEnabledDisabledWarning(const std::vector<std::string>& enabled,
const std::vector<std::string>& disabled) {
std::ostringstream ss;
ss << "Application is using deprecated";
if (!enabled.empty()) {
ss << " \"enables\" (VK_LAYER_ENABLES)";
if (!disabled.empty()) {
ss << " and";
}
}
if (!disabled.empty()) {
ss << " \"disables\" (VK_LAYER_DISABLES)";
}
ss << " layer settings.\nDeprecated settings and new settings cannot be mixed, and deprecated ones take precedence. Consider "
"only using the new settings:\n";
// We tried to have a more clever way to do this, but was hitting strange compiler issues...
// This for loop will NEVER grow, these are the only deprecated settings we have because they are baked into the Vulkan Spec
for (const std::string& deprecated_string : enabled) {
if (deprecated_string == "VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT") {
ss << " Deprecated: VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT | New: \"" << VK_LAYER_GPUAV_ENABLE
<< "\" (VK_LAYER_GPUAV_ENABLE=1)\n";
} else if (deprecated_string == "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT") {
ss << " Deprecated: VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT | New: \"" << VK_LAYER_VALIDATE_BEST_PRACTICES
<< "\" (VK_LAYER_VALIDATE_BEST_PRACTICES=1)\n";
} else if (deprecated_string == "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT") {
ss << " Deprecated: VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT | New: \"" << VK_LAYER_PRINTF_ENABLE
<< "\" (VK_LAYER_PRINTF_ENABLE=1)\n";
} else if (deprecated_string == "VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT") {
ss << " Deprecated: VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT | New: \"" << VK_LAYER_VALIDATE_SYNC
<< "\" (VK_LAYER_VALIDATE_SYNC=1)\n";
}
}
for (const std::string& deprecated_string : disabled) {
if (deprecated_string == "VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT") {
ss << " Deprecated: VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT | New: \"" << VK_LAYER_CHECK_SHADERS
<< "\" (VK_LAYER_CHECK_SHADERS=0)\n";
} else if (deprecated_string == "VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT") {
ss << " Deprecated: VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT | New: \"" << VK_LAYER_THREAD_SAFETY
<< "\" (VK_LAYER_THREAD_SAFETY=0)\n";
} else if (deprecated_string == "VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT") {
ss << " Deprecated: VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT | New: \"" << VK_LAYER_STATELESS_PARAM
<< "\" (VK_LAYER_STATELESS_PARAM=0)\n";
} else if (deprecated_string == "VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT") {
ss << " Deprecated: VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT | New: \"" << VK_LAYER_OBJECT_LIFETIME
<< "\" (VK_LAYER_OBJECT_LIFETIME=0)\n";
} else if (deprecated_string == "VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT") {
ss << " Deprecated: VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT | New: \"" << VK_LAYER_VALIDATE_CORE
<< "\" (VK_LAYER_VALIDATE_CORE=0)\n";
} else if (deprecated_string == "VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT") {
ss << " Deprecated: VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT | New: \"" << VK_LAYER_UNIQUE_HANDLES
<< "\" (VK_LAYER_UNIQUE_HANDLES=0)\n";
} else if (deprecated_string == "VK_VALIDATION_FEATURE_DISABLE_SHADER_VALIDATION_CACHE_EXT") {
ss << " Deprecated: VK_VALIDATION_FEATURE_DISABLE_SHADER_VALIDATION_CACHE_EXT | New: \""
<< VK_LAYER_CHECK_SHADERS_CACHING << "\" (VK_LAYER_CHECK_SHADERS_CACHING=0)\n";
} else if (deprecated_string == "VK_VALIDATION_FEATURE_DISABLE_ALL_EXT") {
ss << " Deprecated: VK_VALIDATION_FEATURE_DISABLE_ALL_EXT | Currently has no replacement, disabling the layer has the "
"same effects.\n";
}
}
return ss.str();
}
static const char* GetDefaultPrefix() {
#ifdef __ANDROID__
return "vvl";
#else
return "LAYER";
#endif
}
#endif // !defined(BUILD_SELF_VVL)
// This is a (less than desired) way to allow Statless validation tracking a setting
bool& HasCustomStypeInfo() {
static bool allow_custom_types = false;
return allow_custom_types;
}
#if !defined(BUILD_SELF_VVL)
// Generated, put here to mimic where it would have been if manually written
// Can't move up to top of file until we generate the VK_LAYER_* names as well
#include "layer_options_validation.h"
#endif
// Process enables and disables set though the vk_layer_settings.txt config file or through an environment variable
void ProcessConfigAndEnvSettings(ConfigAndEnvSettings* settings_data) {
// When compiling a build for self validation, ProcessConfigAndEnvSettings immediately returns,
// so that the layer always defaults to the standard validation options we want,
// and does not try to process option coming from the VVL we are debugging
#if defined(BUILD_SELF_VVL)
// Found having sync val on is very important for catching GPU-AV bugs
settings_data->enabled[sync_validation] = true;
// Setup default messenger callback to stdout and just error validation messages
FILE* log_output = stdout;
VkDebugUtilsMessengerEXT messenger = VK_NULL_HANDLE;
VkDebugUtilsMessengerCreateInfoEXT dbg_create_info = vku::InitStructHelper();
dbg_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
dbg_create_info.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
dbg_create_info.pfnUserCallback = MessengerLogCallback;
dbg_create_info.pUserData = (void*)log_output;
LayerCreateMessengerCallback(settings_data->debug_report, true, &dbg_create_info, &messenger);
#ifdef _WIN32
messenger = VK_NULL_HANDLE;
dbg_create_info.pfnUserCallback = MessengerWin32DebugOutputMsg;
dbg_create_info.pUserData = nullptr;
LayerCreateMessengerCallback(settings_data->debug_report, true, &dbg_create_info, &messenger);
#endif // _WIN32
return;
#else
// We need to send all warnings through the DebugCallback (printf will go into the void and likely is not seen for people), but
// we also need to get settings setup before creating the DebugCallback. This is the only spot that needs this, so we create a
// temp list of strings here and shove them through DebugCallback right after we call it. This function should not be a
// bottleneck so some extra string building should be ok here.
std::vector<std::string> setting_warnings;
// If not cleared, garbage has been seen in some Android run effecting the error message
HasCustomStypeInfo() = false;
VkuLayerSettingSet layer_setting_set = VK_NULL_HANDLE;
auto layer_setting_create_info = vkuFindLayerSettingsCreateInfo(settings_data->create_info);
if (!ValidateLayerSettingsCreateInfo(layer_setting_create_info)) {
return; // nullptr will crash things
}
vkuCreateLayerSettingSet(OBJECT_LAYER_NAME, layer_setting_create_info, nullptr, nullptr, &layer_setting_set);
vkuSetLayerSettingCompatibilityNamespace(layer_setting_set, GetDefaultPrefix());
if (layer_setting_create_info) {
ValidateLayerSettingsProvided(*layer_setting_create_info, setting_warnings);
}
// Read legacy "enables" flags for backward compatibility
std::vector<std::string> enabled;
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_ENABLES)) {
vkuGetLayerSettingValues(layer_setting_set, VK_LAYER_ENABLES, enabled);
}
const std::string string_enabled = Merge(enabled);
const bool used_enabled = SetLocalEnableSetting(string_enabled, ",", settings_data->enabled);
// Read legacy "disables" flags for backward compatibility
std::vector<std::string> disabled;
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_DISABLES)) {
vkuGetLayerSettingValues(layer_setting_set, VK_LAYER_DISABLES, disabled);
}
const std::string string_disabled = Merge(disabled);
const bool used_disabled = SetLocalDisableSetting(string_disabled, ",", settings_data->disabled);
// Check if actually used, or will give bogus warning if the user set VK_LAYER_ENABLES to some garbage setting
if (used_enabled || used_disabled) {
setting_warnings.emplace_back(GetDeprecatedEnabledDisabledWarning(enabled, disabled));
}
GlobalSettings& global_settings = *settings_data->global_settings;
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_DEBUG_DISABLE_SPIRV_VAL)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_DEBUG_DISABLE_SPIRV_VAL, global_settings.debug_disable_spirv_val);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_DESCRIPTOR_HASHING)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_DESCRIPTOR_HASHING, global_settings.descriptor_hashing);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_DESCRIPTOR_HASHING_TOTAL_DESCRIPTORS)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_DESCRIPTOR_HASHING_TOTAL_DESCRIPTORS,
global_settings.descriptor_hashing_total_descriptors);
if (!IsPowerOfTwo(global_settings.descriptor_hashing_total_descriptors)) {
uint32_t old_value = global_settings.descriptor_hashing_total_descriptors;
uint32_t new_value = GetSmallestGreaterOrEquallPowerOfTwo(old_value);
global_settings.descriptor_hashing_total_descriptors = new_value;
setting_warnings.emplace_back(
"VK_LAYER_DESCRIPTOR_HASHING_TOTAL_DESCRIPTORS (descriptor_hashing_total_descriptors) was set to " +
std::to_string(old_value) + " but being set to " + std::to_string(new_value) + " as it needs to be a power of two");
}
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_CUSTOM_STYPE_LIST)) {
// We use to support this, but feel no one is using this
// As a transition, we will allow to be used and just skip the 1 VU check if anything is set
// (added after SDK 1.4.341)
setting_warnings.emplace_back(
"VK_LAYER_CUSTOM_STYPE_LIST is set, but currently the feature seems unused, we plan to drop this support, so please "
"report if seeing this warning");
HasCustomStypeInfo() = true;
}
GpuAVSettings& gpuav_settings = *settings_data->gpuav_settings;
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_SAFE_MODE)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_SAFE_MODE, gpuav_settings.safe_mode);
}
bool shader_instrumentation_enabled = true;
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_SHADER_INSTRUMENTATION)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_SHADER_INSTRUMENTATION, shader_instrumentation_enabled);
}
if (!shader_instrumentation_enabled) {
gpuav_settings.DisableShaderInstrumentationAndOptions();
} else {
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_DESCRIPTOR_CHECKS)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_DESCRIPTOR_CHECKS,
gpuav_settings.shader_instrumentation.descriptor_checks);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_POST_PROCESS_DESCRIPTOR_INDEXING)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_POST_PROCESS_DESCRIPTOR_INDEXING,
gpuav_settings.shader_instrumentation.post_process_descriptor_indexing);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_MESH_SHADING)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_MESH_SHADING,
gpuav_settings.shader_instrumentation.mesh_shading);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_VERTEX_ATTRIBUTE_FETCH_OOB)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_VERTEX_ATTRIBUTE_FETCH_OOB,
gpuav_settings.shader_instrumentation.vertex_attribute_fetch_oob);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_BUFFER_ADDRESS_OOB)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_BUFFER_ADDRESS_OOB,
gpuav_settings.shader_instrumentation.buffer_device_address);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_VALIDATE_TRACE_RAY)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_VALIDATE_TRACE_RAY,
gpuav_settings.shader_instrumentation.trace_ray);
}
if (vkuHasLayerSetting(layer_setting_set, REMOVED_VK_LAYER_GPUAV_VALIDATE_RAY_QUERY)) {
setting_warnings.emplace_back(std::string(REMOVED_VK_LAYER_GPUAV_VALIDATE_RAY_QUERY) +
" advanced setting was removed, just use " +
std::string(VK_LAYER_GPUAV_VALIDATE_TRACE_RAY) + " now.");
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_SHADER_SANITIZER)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_SHADER_SANITIZER,
gpuav_settings.shader_instrumentation.sanitizer);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_SHARED_MEMORY_DATA_RACE)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_SHARED_MEMORY_DATA_RACE,
gpuav_settings.shader_instrumentation.shared_memory_data_race);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_MAX_INDICES_COUNT)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_MAX_INDICES_COUNT, gpuav_settings.invalid_index_command);
// Hard limit is set by the fact we have kActionId_Mask used... which is also arbitrary
// ... we don't need 64k slots for the kErrorLoggerId_Mask, so could increase 64k if really wanted
// (If we update, please update the SetMaxIndicesCountAtTheLimit test)
if (gpuav_settings.invalid_index_command >= 65535) {
setting_warnings.emplace_back(
"VK_LAYER_GPUAV_MAX_INDICES_COUNT (gpuav_max_indices_count) is being set to 65534, the max value supported "
"currently.");
gpuav_settings.invalid_index_command = 65534;
}
gpuav_settings.indices_buffer_count = gpuav_settings.invalid_index_command + 1;
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_SELECT_INSTRUMENTED_SHADERS)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_SELECT_INSTRUMENTED_SHADERS,
gpuav_settings.select_instrumented_shaders);
}
if (gpuav_settings.select_instrumented_shaders) {
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_CDL_DUMP_PATH)) {
std::string cdl_dump_path;
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_CDL_DUMP_PATH, cdl_dump_path);
gpuav_settings.LoadCDLDump(std::move(cdl_dump_path), setting_warnings);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_SHADERS_TO_INSTRUMENT)) {
std::vector<std::string> shaders_to_instrument;
vkuGetLayerSettingValues(layer_setting_set, VK_LAYER_GPUAV_SHADERS_TO_INSTRUMENT, shaders_to_instrument);
gpuav_settings.SetShaderSelectionRegexes(std::move(shaders_to_instrument));
}
}
// No need to enable shader instrumentation options is no instrumentation is done
if (!gpuav_settings.IsShaderInstrumentationEnabled()) {
gpuav_settings.DisableShaderInstrumentationAndOptions();
}
}
bool buffers_validation_enabled = true;
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_BUFFERS_VALIDATION)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_BUFFERS_VALIDATION, buffers_validation_enabled);
}
if (!buffers_validation_enabled) {
gpuav_settings.SetBufferValidationEnabled(false);
} else {
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_INDIRECT_DRAWS_BUFFERS)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_INDIRECT_DRAWS_BUFFERS,
gpuav_settings.validate_indirect_draws_buffers);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_INDIRECT_DISPATCHES_BUFFERS)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_INDIRECT_DISPATCHES_BUFFERS,
gpuav_settings.validate_indirect_dispatches_buffers);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_INDIRECT_TRACE_RAYS_BUFFERS)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_INDIRECT_TRACE_RAYS_BUFFERS,
gpuav_settings.validate_indirect_trace_rays_buffers);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_BUFFER_COPIES)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_BUFFER_COPIES, gpuav_settings.validate_buffer_copies);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_COPY_MEMORY_INDIRECT)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_COPY_MEMORY_INDIRECT,
gpuav_settings.validate_copy_memory_indirect);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_INDEX_BUFFERS)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_INDEX_BUFFERS, gpuav_settings.validate_index_buffers);
}
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_ACCELERATION_STRUCTURES_BUILDS)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_ACCELERATION_STRUCTURES_BUILDS,
gpuav_settings.validate_acceleration_structures_builds);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_RAY_TRACING_BUFFERS_CONSISTENCY)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_RAY_TRACING_BUFFERS_CONSISTENCY,
gpuav_settings.ray_tracing_buffers_consistency);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_FORCE_ON_ROBUSTNESS)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_FORCE_ON_ROBUSTNESS, gpuav_settings.force_on_robustness);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_DEBUG_VALIDATE_INSTRUMENTED_SHADERS)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_DEBUG_VALIDATE_INSTRUMENTED_SHADERS,
gpuav_settings.debug_validate_instrumented_shaders);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_DEBUG_DUMP_INSTRUMENTED_SHADERS)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_DEBUG_DUMP_INSTRUMENTED_SHADERS,
gpuav_settings.debug_dump_instrumented_shaders);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_DEBUG_MAX_INSTRUMENTATIONS_COUNT)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_DEBUG_MAX_INSTRUMENTATIONS_COUNT,
gpuav_settings.debug_max_instrumentations_count);
}
// Debug Printf - (which we bundle into GPU-AV internally)
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_PRINTF_ENABLE)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_PRINTF_ENABLE, gpuav_settings.debug_printf_enabled);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_DEBUG_PRINT_INSTRUMENTATION_INFO)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_DEBUG_PRINT_INSTRUMENTATION_INFO,
gpuav_settings.debug_print_instrumentation_info);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_DEBUG_DISABLE_DONTINLINE)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_DEBUG_DISABLE_DONTINLINE,
gpuav_settings.debug_disable_dontinline);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_PRINTF_TO_STDOUT)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_PRINTF_TO_STDOUT, gpuav_settings.debug_printf_to_stdout);
}
// This option was published when DebugPrintf came out, leave to not break people's flow
// Deprecated right after the 1.3.280 SDK release
if (!GetEnvironment("DEBUG_PRINTF_TO_STDOUT").empty()) {
setting_warnings.emplace_back("DEBUG_PRINTF_TO_STDOUT was set, this is deprecated, please use VK_LAYER_PRINTF_TO_STDOUT");
gpuav_settings.debug_printf_to_stdout = true;
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_PRINTF_VERBOSE)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_PRINTF_VERBOSE, gpuav_settings.debug_printf_verbose);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_PRINTF_BUFFER_SIZE)) {
const uint32_t default_buffer_size = gpuav_settings.debug_printf_buffer_size;
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_PRINTF_BUFFER_SIZE, gpuav_settings.debug_printf_buffer_size);
if (gpuav_settings.debug_printf_buffer_size == 0) {
gpuav_settings.debug_printf_buffer_size = default_buffer_size;
setting_warnings.emplace_back(std::string(VK_LAYER_PRINTF_BUFFER_SIZE) +
" was set to zero, which is invalid, setting to the default of " +
std::to_string(default_buffer_size));
}
}
SyncValSettings& syncval_settings = *settings_data->syncval_settings;
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_SYNCVAL_FULL_VALIDATION)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_SYNCVAL_FULL_VALIDATION, syncval_settings.full_validation);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_SYNCVAL_RECORD_TIME_VALIDATION)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_SYNCVAL_RECORD_TIME_VALIDATION,
syncval_settings.record_time_validation);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_SYNCVAL_SHADER_ACCESSES_HEURISTIC)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_SYNCVAL_SHADER_ACCESSES_HEURISTIC,
syncval_settings.shader_accesses_heuristic);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_SYNCVAL_LOAD_OP_AFTER_STORE_OP_VALIDATION)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_SYNCVAL_LOAD_OP_AFTER_STORE_OP_VALIDATION,
syncval_settings.load_op_after_store_op_validation);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_SYNCVAL_MESSAGE_EXTRA_PROPERTIES)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_SYNCVAL_MESSAGE_EXTRA_PROPERTIES,
syncval_settings.message_extra_properties);
}
// TODO: add REMOVED warning similar to REMOVED_VK_LAYER_GPUAV_VALIDATE_RAY_QUERY
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_SYNCVAL_SUBMIT_TIME_VALIDATION)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_SYNCVAL_SUBMIT_TIME_VALIDATION,
syncval_settings.legacy_submit_time_validation);
}
GpuDumpSettings& gpu_dump_settings = *settings_data->gpu_dump_settings;
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPU_DUMP_DESCRIPTORS)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPU_DUMP_DESCRIPTORS, gpu_dump_settings.descriptors);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPU_DUMP_COPY_MEMORY_INDIRECT)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPU_DUMP_COPY_MEMORY_INDIRECT, gpu_dump_settings.copy_memory_indirect);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPU_DUMP_DEVICE_GENERATED_COMMANDS)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPU_DUMP_DEVICE_GENERATED_COMMANDS,
gpu_dump_settings.device_generated_commands);
}
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPU_DUMP_TO_STDOUT)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPU_DUMP_TO_STDOUT, gpu_dump_settings.to_stdout);
}
LegacyDetectionSettings& legacy_detection_settings = *settings_data->legacy_detection_settings;
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_LEGACY_DETECTION_MODE)) {
std::string mode;
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_LEGACY_DETECTION_MODE, mode);
if (mode == "ONLY_SUPPORTED") {
legacy_detection_settings.only_supported = true;
} else if (mode == "ONLY_ENABLED") {
legacy_detection_settings.only_enabled = true;
}
}
legacy_detection_settings.always = !legacy_detection_settings.only_supported && !legacy_detection_settings.only_enabled;
// Feel safe to remove by end of 2026, will have enough SDK cycles by then
const char* REMOVED_VK_LAYER_SYNCVAL_MESSAGE_EXTRA_PROPERTIES_PRETTY_PRINT = "syncval_message_extra_properties_pretty_print";
if (vkuHasLayerSetting(layer_setting_set, REMOVED_VK_LAYER_SYNCVAL_MESSAGE_EXTRA_PROPERTIES_PRETTY_PRINT)) {
setting_warnings.emplace_back(std::string(REMOVED_VK_LAYER_SYNCVAL_MESSAGE_EXTRA_PROPERTIES_PRETTY_PRINT) +
" was removed. The main purpose of the extra properties section is to filter syncval error "
"messages. The priority is to have a fixed and easy-to-parse layout.");
}
const auto* validation_features_ext = vku::FindStructInPNextChain<VkValidationFeaturesEXT>(settings_data->create_info);
if (validation_features_ext) {
SetValidationFeatures(settings_data->disabled, settings_data->enabled, validation_features_ext);
}
const auto* validation_flags_ext = vku::FindStructInPNextChain<VkValidationFlagsEXT>(settings_data->create_info);
if (validation_flags_ext) {
SetValidationFlags(settings_data->disabled, validation_flags_ext);
}
const bool use_fine_grained_settings = disabled.empty() && enabled.empty();
// Only read the legacy enables flags when used, not their replacement.
// Avoid Android C.I. performance regression from reading Android env variables
if (use_fine_grained_settings) {
SetValidationSetting(layer_setting_set, settings_data->enabled, best_practices, VK_LAYER_VALIDATE_BEST_PRACTICES);
SetValidationSetting(layer_setting_set, settings_data->enabled, vendor_specific_arm, VK_LAYER_VALIDATE_BEST_PRACTICES_ARM);
SetValidationSetting(layer_setting_set, settings_data->enabled, vendor_specific_amd, VK_LAYER_VALIDATE_BEST_PRACTICES_AMD);
SetValidationSetting(layer_setting_set, settings_data->enabled, vendor_specific_img, VK_LAYER_VALIDATE_BEST_PRACTICES_IMG);
SetValidationSetting(layer_setting_set, settings_data->enabled, vendor_specific_nvidia,
VK_LAYER_VALIDATE_BEST_PRACTICES_NVIDIA);
SetValidationSetting(layer_setting_set, settings_data->enabled, sync_validation, VK_LAYER_VALIDATE_SYNC);
}
// These don't have a VkValidationFeaturesEXT equivalent, so always check these
SetValidationSetting(layer_setting_set, settings_data->enabled, legacy_detection, VK_LAYER_LEGACY_DETECTION);
settings_data->enabled[gpu_dump] = gpu_dump_settings.EnableLayer();
// Only read the legacy disables flags when used, not their replacement.
// Avoid Android C.I. performance regression from reading Android env variables
if (use_fine_grained_settings) {
SetValidationSetting(layer_setting_set, settings_data->disabled, stateless_checks, VK_LAYER_STATELESS_PARAM);
SetValidationSetting(layer_setting_set, settings_data->disabled, thread_safety, VK_LAYER_THREAD_SAFETY);
SetValidationSetting(layer_setting_set, settings_data->disabled, core_checks, VK_LAYER_VALIDATE_CORE);
SetValidationSetting(layer_setting_set, settings_data->disabled, command_buffer_state, VK_LAYER_CHECK_COMMAND_BUFFER);
SetValidationSetting(layer_setting_set, settings_data->disabled, object_in_use, VK_LAYER_CHECK_OBJECT_IN_USE);
SetValidationSetting(layer_setting_set, settings_data->disabled, query_validation, VK_LAYER_CHECK_QUERY);
SetValidationSetting(layer_setting_set, settings_data->disabled, image_layout_validation, VK_LAYER_CHECK_IMAGE_LAYOUT);
SetValidationSetting(layer_setting_set, settings_data->disabled, handle_wrapping, VK_LAYER_UNIQUE_HANDLES);
SetValidationSetting(layer_setting_set, settings_data->disabled, object_tracking, VK_LAYER_OBJECT_LIFETIME);
SetValidationSetting(layer_setting_set, settings_data->disabled, shader_validation, VK_LAYER_CHECK_SHADERS);
SetValidationSetting(layer_setting_set, settings_data->disabled, shader_validation_caching, VK_LAYER_CHECK_SHADERS_CACHING);
}
// This is the "original" way to use DebugPrintf before you could use it with GPU-AV
// In this case, we want to emulate supporting only for DebugPrintf with GPU-AV disabled
if (settings_data->enabled[debug_printf_validation]) {
gpuav_settings.debug_printf_enabled = true;
} else if (gpuav_settings.debug_printf_enabled) {
// enabled the new way, but chassis uses this to create Validation Object
settings_data->enabled[debug_printf_validation] = true;
}
// New way to override everything to make it easy to use DebugPrintf when VkConfig isn't available
bool printf_only_preset = false;
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_PRINTF_ONLY_PRESET)) {
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_PRINTF_ONLY_PRESET, printf_only_preset);
if (printf_only_preset) {
gpuav_settings.SetOnlyDebugPrintf();
// chassis uses this to create Validation Object
settings_data->enabled[debug_printf_validation] = true;
settings_data->enabled[gpu_validation] = false;
// Tried to use VK_VALIDATION_FEATURE_DISABLE_ALL_EXT but when running on Android
// (--gtest_filter="NegativeGpuAVDebugPrintf.BasicLayerSettingsPrintfPreset:NegativeWsi.UseDestroyedSwapchain")
// Was getting asserts in VulkanTypedHandle::Cast() Simple fix was to just not disable
// VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT
SetValidationFeatureDisable(settings_data->disabled, VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT);
SetValidationFeatureDisable(settings_data->disabled, VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT);
SetValidationFeatureDisable(settings_data->disabled, VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT);
SetValidationFeatureDisable(settings_data->disabled, VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT);
SetValidationFeatureDisable(settings_data->disabled, VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT);
SetValidationFeatureDisable(settings_data->disabled, VK_VALIDATION_FEATURE_DISABLE_SHADER_VALIDATION_CACHE_EXT);
setting_warnings.emplace_back(
"Disabling as much of normal validation as possible so that only DebugPrintf will be running.");
}
}
// This is the "new" way to enable GPU-AV
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_ENABLE)) {
bool gpuav_enable = false;
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_ENABLE, gpuav_enable);
if (printf_only_preset) {
setting_warnings.emplace_back(std::string(VK_LAYER_PRINTF_ONLY_PRESET) + " was set, so ignoring " +
std::string(VK_LAYER_GPUAV_ENABLE) + ".");
} else if (gpuav_enable) {
// enabled the new way, but chassis uses this to create Validation Object
settings_data->enabled[gpu_validation] = true;
}
}
// Only truly needed for pipelines (see GpuShaderInstrumentor::PreCallRecordSetDebugUtilsObjectNameEXT)
// In the future, could be removed in favor of debug names supplied at pipeline creation time.
if (gpuav_settings.select_instrumented_shaders) {
if (settings_data->disabled[handle_wrapping]) {
setting_warnings.emplace_back(
"Handle wrapping has been disabled, but GPU-AV selective shader instrumentation is enabled. Forcing activation of "
"handle wrapping.");
settings_data->disabled[handle_wrapping] = false;
}
}
// After checking the various ways to enable both DebugPrintf and GPU-AV, disable non-DebugPrintf portion if not used
if (settings_data->enabled[debug_printf_validation] && !settings_data->enabled[gpu_validation]) {
gpuav_settings.SetOnlyDebugPrintf();
}
// if app is setting VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, we can use this to disable it for debugging
if (vkuHasLayerSetting(layer_setting_set, VK_LAYER_GPUAV_DEBUG_DISABLE_ALL)) {
bool disable_gpuav = false;
vkuGetLayerSettingValue(layer_setting_set, VK_LAYER_GPUAV_DEBUG_DISABLE_ALL, disable_gpuav);
if (disable_gpuav) {
settings_data->enabled[gpu_validation] = false;
}
}
if (settings_data->enabled[gpu_validation] && !settings_data->disabled[core_checks]) {
setting_warnings.emplace_back(
"Both GPU Assisted Validation and Normal Core Check Validation are enabled, this is not recommend as it will be very "
"slow. Once all "
"errors in Core Check are solved, please disable, then only use GPU-AV for best performance.");
}
// Set at the end once we decide what settings are actually on
if (settings_data->disabled[shader_validation] || settings_data->disabled[core_checks]) {
// only is used for core validation checks
global_settings.spirv_const_fold = false;
// sync val relies on the information from spirv::Module being parsed and stored
if (!settings_data->enabled[sync_validation]) {
// GPU-AV/DebugPrintf relies on spirv::Module to hold the original SPIR-V
if (!settings_data->enabled[gpu_validation] && !settings_data->enabled[debug_printf_validation] &&
!settings_data->enabled[gpu_dump]) {
global_settings.spirv_store = false;
} else if (settings_data->disabled[shader_validation]) {
setting_warnings.emplace_back(
"Shader Validation was explicitly turned off, but the SPIR-V still needs to be stored, but not validated, in "
"order for GPU-AV/DebugPrintf to get information from the original SPIR-V.");
}
} else if (settings_data->disabled[shader_validation]) {
setting_warnings.emplace_back(
"Shader Validation was explicitly turned off, but the SPIR-V still needs to be parsed/stored, but not validated, "
"in order for Sync Validation to get read/write information out the SPIR-V.");
}
}
if (global_settings.descriptor_hashing && !settings_data->enabled[gpu_validation] && !gpu_dump_settings.descriptors) {
setting_warnings.emplace_back(
"Descriptor Hashing was turned on, but neither GPU-AV nor GPU Dump (for descriptors) is enabled. Turning off as this "
"setting has no "
"effect.");
global_settings.descriptor_hashing = false;
}
// Our way to to try and get rid of these settings
// Detect if people have core, but manually turned off these settings
//
// These were added 10 years ago and were not properly maintained nor tested
// We added this warning at 1.4.355 and want to give a few SDK cycles before fully removing
if (!settings_data->disabled[core_checks]) {
if (settings_data->disabled[command_buffer_state]) {
setting_warnings.emplace_back(
"VK_LAYER_CHECK_COMMAND_BUFFER (check_command_buffer) is deprecated and planned to be removed in the future. "
"Please "
"inform us if you are still using this setting!");
}
if (settings_data->disabled[object_in_use]) {
setting_warnings.emplace_back(
"VK_LAYER_CHECK_OBJECT_IN_USE (check_object_in_use) is deprecated and planned to be removed in the future. Please "
"inform us if you are still using this setting!");
}
if (settings_data->disabled[query_validation]) {
setting_warnings.emplace_back(
"VK_LAYER_CHECK_QUERY (check_query) is deprecated and planned to be removed in the future. Please inform us if you "
"are "
"still using this setting!");
}
if (settings_data->disabled[image_layout_validation]) {
setting_warnings.emplace_back(
"VK_LAYER_CHECK_IMAGE_LAYOUT (check_image_layout) is deprecated and planned to be removed in the future. Please "
"inform "
"us if you are still using this setting!");
}
}
// Last as previous settings are needed so we can make sure they line up with the DebugReport settings
ProcessDebugReportSettings(settings_data, layer_setting_set, setting_warnings);
// Grab application name here while we have access to it and know if to save it or not
if (settings_data->debug_report->message_format_settings.display_application_name) {
const VkApplicationInfo* app_info = settings_data->create_info->pApplicationInfo;
settings_data->debug_report->message_format_settings.application_name =
(app_info && app_info->pApplicationName) ? app_info->pApplicationName : "";
}
for (const auto& warning : setting_warnings) {
Location loc(vvl::Func::vkCreateInstance);
settings_data->debug_report->LogMessage(kWarningBit, "VALIDATION-SETTINGS", {}, loc, warning);
}
vkuDestroyLayerSettingSet(layer_setting_set, nullptr);
#endif // !BUILD_SELF_VVL
}