diff --git a/layers/vk_layer_config.cpp b/layers/vk_layer_config.cpp index 8d0d0096be9..2663db3ff5f 100644 --- a/layers/vk_layer_config.cpp +++ b/layers/vk_layer_config.cpp @@ -111,6 +111,16 @@ std::string GetEnvironment(const char *variable) { #endif } +void SetEnvironment(const char *variable, const char *value) { +#if !defined(__ANDROID__) && !defined(_WIN32) + setenv(variable, value, 1); +#elif defined(_WIN32) + SetEnvironmentVariable(variable, value); +#elif defined(__ANDROID__) + assert(FALSE && "Not supported on android"); +#endif +} + const char *getLayerOption(const char *option) { return layer_config.GetOption(option); } const SettingsFileInfo *GetLayerSettingsFileInfo() { return &layer_config.settings_info; } diff --git a/layers/vk_layer_config.h b/layers/vk_layer_config.h index f9183f774b2..b454266446b 100644 --- a/layers/vk_layer_config.h +++ b/layers/vk_layer_config.h @@ -1,6 +1,6 @@ -/* Copyright (c) 2015-2022 The Khronos Group Inc. - * Copyright (c) 2015-2023 Valve Corporation - * Copyright (c) 2015-2023 LunarG, Inc. +/* Copyright (c) 2015-2024 The Khronos Group Inc. + * Copyright (c) 2015-2024 Valve Corporation + * Copyright (c) 2015-2024 LunarG, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,6 +32,9 @@ std::string GetEnvironment(const char *variable); +// Not supported on Android +void SetEnvironment(const char *variable, const char *value); + enum SettingsFileSource { kVkConfig, kEnvVar, @@ -68,9 +71,8 @@ const char *getLayerOption(const char *option); const SettingsFileInfo *GetLayerSettingsFileInfo(); FILE *getLayerLogOutput(const char *option, const char *layer_name); -VkFlags GetLayerOptionFlags(const std::string &option, - vvl::unordered_map const &enum_data, - uint32_t option_default); +VkFlags GetLayerOptionFlags(const std::string &option, vvl::unordered_map const &enum_data, + uint32_t option_default); void PrintMessageFlags(VkFlags vk_flags, char *msg_flags); void PrintMessageSeverity(VkFlags vk_flags, char *msg_flags); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c02c5b926b8..c57a4c43368 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -272,6 +272,24 @@ target_link_libraries(vk_layer_validation_tests PRIVATE $ ) +# setup framework/config.h using framework/config.h.in as a source +file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/config$.h" INPUT "${CMAKE_CURRENT_SOURCE_DIR}/framework/config.h.in") + +# copy config$.h to the build directory +add_custom_command( + PRE_BUILD + COMMAND ${CMAKE_COMMAND} "-E" "copy_if_different" "${CMAKE_CURRENT_BINARY_DIR}/config$.h" "${CMAKE_CURRENT_BINARY_DIR}/config.h" + VERBATIM + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/config$.h" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/config.h" + COMMENT "creating config.h file ({event: PRE_BUILD}, {filename: config.h })" + ) +add_custom_target (generate_framework_config DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/config.h") +add_dependencies (generate_framework_config vk_layer_validation_tests) + +target_sources(vk_layer_validation_tests PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/config.h) +target_include_directories(vk_layer_validation_tests PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + # More details in tests/android/mock/README.md option(VVL_MOCK_ANDROID "Enable building for Android on desktop for testing with MockICD setup") if(VVL_MOCK_ANDROID) diff --git a/tests/framework/config.h.in b/tests/framework/config.h.in new file mode 100644 index 00000000000..4f78febc4ee --- /dev/null +++ b/tests/framework/config.h.in @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 The Khronos Group Inc. + * Copyright (c) 2024 Valve Corporation + * Copyright (c) 2024 LunarG, Inc. + * + * 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. + */ + +#pragma once + +#define VALIDATION_LAYERS_BUILD_PATH "$" diff --git a/tests/framework/test_framework.cpp b/tests/framework/test_framework.cpp index a7406896414..0cf4102d5a3 100644 --- a/tests/framework/test_framework.cpp +++ b/tests/framework/test_framework.cpp @@ -18,6 +18,7 @@ #include "test_framework.h" #include "render.h" +#include "config.h" #include #include #include @@ -71,68 +72,103 @@ static std::vector GetVkEnvironmentVariable(const char *env_var) { return items; } -static void CheckEnvironmentVariables() { +static void CheckAndSetEnvironmentVariables() { for (const char *env_var : {"VK_DRIVER_FILES", "VK_ICD_FILENAMES"}) { const std::vector driver_files = GetVkEnvironmentVariable(env_var); for (const std::string &driver_file : driver_files) { const std::filesystem::path icd_file(driver_file); - // TODO: Error check relative paths (platform dependent) if (icd_file.is_relative()) { continue; } - std::string user_provided; user_provided += "\n\n"; user_provided += env_var; user_provided += " = "; user_provided += driver_file; - - if (!std::filesystem::exists(icd_file)) { - std::cerr << "Invalid " << env_var << "! File doesn't exist!" << user_provided << std::endl; - std::exit(EXIT_FAILURE); - } - - if (icd_file.extension() != ".json") { - std::cerr << "Invalid " << env_var << "! " << env_var << " must be a json file!\n" << user_provided << std::endl; - std::exit(EXIT_FAILURE); + if (std::filesystem::is_directory(icd_file)) { + if (!std::filesystem::exists(icd_file)) { + std::cerr << "Invalid " << env_var << "! Directory doesn't exist!" << user_provided << std::endl; + std::exit(EXIT_FAILURE); + } + bool contains_json = false; + for (auto const &dir_entry : std::filesystem::directory_iterator{icd_file}) { + if (dir_entry.path().extension() == ".json") { + contains_json = true; + } + } + if (!contains_json) { + std::cerr << "Invalid " << env_var << "! " << env_var << " must contain a json file!" << user_provided + << std::endl; + std::exit(EXIT_FAILURE); + } + + } else { + if (!std::filesystem::exists(icd_file)) { + std::cerr << "Invalid " << env_var << "! File doesn't exist!" << user_provided << std::endl; + std::exit(EXIT_FAILURE); + } + + if (icd_file.extension() != ".json") { + std::cerr << "Invalid " << env_var << "! " << env_var << " must be a json file!" << user_provided << std::endl; + std::exit(EXIT_FAILURE); + } } } } - const std::vector vk_layer_paths = GetVkEnvironmentVariable("VK_LAYER_PATH"); bool found_json = false; - for (const std::string &layer_path : vk_layer_paths) { - const std::filesystem::path layer_dir(layer_path); - - // TODO: Error check relative paths (platform dependent) - if (layer_dir.is_relative()) { - continue; + bool vk_layer_env_vars_present = false; + std::stringstream error_log; // Build up error log in case the validation json cannot be found + for (const char *env_var : {"VK_LAYER_PATH", "VK_ADD_LAYER_PATH"}) { + const std::vector vk_layer_paths = GetVkEnvironmentVariable(env_var); + if (!vk_layer_paths.empty()) { + vk_layer_env_vars_present = true; } - const std::string user_provided = "\n\nVK_LAYER_PATH = " + layer_path; + for (const std::string &layer_path : vk_layer_paths) { + const std::filesystem::path layer_dir(layer_path); - if (!std::filesystem::exists(layer_dir)) { - std::cerr << "Invalid VK_LAYER_PATH! Directory " << layer_dir << " doesn't exist!" << user_provided << std::endl; - std::exit(EXIT_FAILURE); - } - - if (!std::filesystem::is_directory(layer_dir)) { - std::cerr << "Invalid VK_LAYER_PATH! " << layer_dir << " must be a directory!" << user_provided << std::endl; - std::exit(EXIT_FAILURE); - } + if (!std::filesystem::exists(layer_dir)) { + error_log << "Invalid " << env_var << "! " << layer_dir << " doesn't exist." << std::endl; + continue; + } - for (auto const &dir_entry : std::filesystem::directory_iterator{layer_dir}) { - if (dir_entry.path().filename() == "VkLayer_khronos_validation.json") { - found_json = true; + if (std::filesystem::is_directory(layer_dir)) { + for (auto const &dir_entry : std::filesystem::directory_iterator{layer_dir}) { + if (dir_entry.path().filename() == "VkLayer_khronos_validation.json") { + if (std::filesystem::exists(dir_entry)) { + found_json = true; + break; + } else { + error_log << "Invalid " << env_var << "! " << dir_entry << " doen not exist!" << std::endl; + } + } + } + if (!found_json) { + error_log << "Invalid " << env_var << "! " << layer_dir + << " is a directory but doesn't contain a VkLayer_khronos_validation.json file!" << std::endl; + } + } else { + if (layer_dir.filename() == "VkLayer_khronos_validation.json") { + found_json = true; + break; + } else { + error_log << "Invalid " << env_var << "! The filename of path" << layer_dir + << " is not VkLayer_khronos_validation.json!" << std::endl; + } + } + if (found_json) { break; } } } if (!found_json) { - std::cerr << "Invalid VK_LAYER_PATH! VK_LAYER_PATH directory must contain VkLayer_khronos_validation.json!" - << GetEnvironment("VK_LAYER_PATH") << std::endl; - std::exit(EXIT_FAILURE); + if (vk_layer_env_vars_present) { + std::cerr << error_log.str() << std::endl; + std::cerr << "Automatically setting VK_LAYER_PATH to " << VALIDATION_LAYERS_BUILD_PATH << std::endl; + } + SetEnvironment("VK_LAYER_PATH", VALIDATION_LAYERS_BUILD_PATH); } } #endif @@ -142,7 +178,7 @@ static void CheckEnvironmentVariables() { void TestEnvironment::SetUp() { #if !defined(VK_USE_PLATFORM_ANDROID_KHR) // Helps ensure common developer environment variables are set correctly - CheckEnvironmentVariables(); + CheckAndSetEnvironmentVariables(); #endif // Initialize GLSL to SPV compiler utility @@ -191,7 +227,8 @@ void VkTestFramework::InitArgs(int *argc, char *argv[]) { "\t--device-index \n" "\t\tIndex into VkPhysicalDevice array returned from vkEnumeratePhysicalDevices.\n" "\t\tThe default behavior is to automatically choose \"the most reasonable device.\"\n" - "\t\tAn invalid index (i.e., outside the range [0, *pPhysicalDeviceCount)) will result in the default behavior\n"); + "\t\tAn invalid index (i.e., outside the range [0, *pPhysicalDeviceCount)) will result in the default " + "behavior\n"); exit(0); } else { printf("\nUnrecognized option: %s\n", argv[i]);