Skip to content

Commit

Permalink
test: Set VK_LAYER_PATH automatically if missing
Browse files Browse the repository at this point in the history
Changes:
* Add mechanism to set VK_LAYER_PATH automatically if it isn't set or if
it is set but doesn't contain a path to a valid layer manifest.
* Search VK_ADD_LAYER_PATH in addition to VK_LAYER_PATH when looking for
the layer manifest
* Enhance searching of the layer manifest to include directory support
rather than only allowing files
* Enhance VK_ICD_FILENAMES & VK_DRIVER_FILES checking to support files in
addition to the existing support for directories
  • Loading branch information
charles-lunarg committed Apr 19, 2024
1 parent 0409ac6 commit 7895db3
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 43 deletions.
10 changes: 10 additions & 0 deletions layers/vk_layer_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
14 changes: 8 additions & 6 deletions layers/vk_layer_config.h
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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<std::string, VkFlags> const &enum_data,
uint32_t option_default);
VkFlags GetLayerOptionFlags(const std::string &option, vvl::unordered_map<std::string, VkFlags> const &enum_data,
uint32_t option_default);

void PrintMessageFlags(VkFlags vk_flags, char *msg_flags);
void PrintMessageSeverity(VkFlags vk_flags, char *msg_flags);
Expand Down
18 changes: 18 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,24 @@ target_link_libraries(vk_layer_validation_tests PRIVATE
$<TARGET_NAME_IF_EXISTS:PkgConfig::WAYlAND_CLIENT>
)

# setup framework/config.h using framework/config.h.in as a source
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/config$<CONFIG>.h" INPUT "${CMAKE_CURRENT_SOURCE_DIR}/framework/config.h.in")

# copy config$<CONFIG>.h to the build directory
add_custom_command(
PRE_BUILD
COMMAND ${CMAKE_COMMAND} "-E" "copy_if_different" "${CMAKE_CURRENT_BINARY_DIR}/config$<CONFIG>.h" "${CMAKE_CURRENT_BINARY_DIR}/config.h"
VERBATIM
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/config$<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)
Expand Down
21 changes: 21 additions & 0 deletions tests/framework/config.h.in
Original file line number Diff line number Diff line change
@@ -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 "$<TARGET_FILE_DIR:vvl>"
111 changes: 74 additions & 37 deletions tests/framework/test_framework.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "test_framework.h"
#include "render.h"
#include "config.h"
#include <filesystem>
#include <cmath>
#include <cstdarg>
Expand Down Expand Up @@ -71,68 +72,103 @@ static std::vector<std::string> 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<std::string> 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<std::string> 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<std::string> 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
Expand All @@ -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
Expand Down Expand Up @@ -191,7 +227,8 @@ void VkTestFramework::InitArgs(int *argc, char *argv[]) {
"\t--device-index <physical 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]);
Expand Down

0 comments on commit 7895db3

Please sign in to comment.