D3DKMT_Adapter& add_path(fs::path src, std::vector<std::wstring>& dest);
};
+#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
+
+struct DirEntry {
+ DIR* directory;
+ std::string folder_path;
+ std::vector<struct dirent*> contents;
+ size_t current_index;
+};
+
#endif
+
+struct FrameworkEnvironment; // forward declaration
+
// Necessary to have inline definitions as shim is a dll and thus functions
// defined in the .cpp wont be found by the rest of the application
struct PlatformShim {
+ PlatformShim() = default;
+ PlatformShim(std::vector<fs::FolderManager>* folders) : folders(folders) {}
+
+ // Used to get info about which drivers & layers have been added to folders
+ std::vector<fs::FolderManager>* folders;
+
// Test Framework interface
void reset();
void set_elevated_privilege(bool elev) { use_fake_elevation = elev; }
bool use_fake_elevation = false;
+
+ std::vector<DirEntry> dir_entries;
#endif
};
std::vector<std::string> parse_env_var_list(std::string const& var);
std::string category_path_name(ManifestCategory category);
+std::vector<std::string> get_folder_contents(std::vector<fs::FolderManager>* folders, std::string folder_name) noexcept;
+
extern "C" {
// dynamically link on windows and macos
#if defined(WIN32) || defined(__APPLE__)
-using PFN_get_platform_shim = PlatformShim* (*)();
+using PFN_get_platform_shim = PlatformShim* (*)(std::vector<fs::FolderManager>* folders);
#define GET_PLATFORM_SHIM_STR "get_platform_shim"
#elif defined(__linux__) || defined(__FreeBSD__)
// statically link on linux
-PlatformShim* get_platform_shim();
+PlatformShim* get_platform_shim(std::vector<fs::FolderManager>* folders);
#endif
}
return items;
}
+std::vector<std::string> get_folder_contents(std::vector<fs::FolderManager>* folders, std::string folder_name) noexcept {
+ for (auto& folder : *folders) {
+ if (folder.location() == folder_name) {
+ return folder.get_files();
+ }
+ }
+ return {};
+}
+
#if defined(WIN32)
D3DKMT_Adapter& D3DKMT_Adapter::add_driver_manifest_path(fs::path const& src) { return add_path(src, driver_paths); }
redirect_path(fs::path(SYSCONFDIR) / "vulkan" / category_path_name(category), path);
}
-#endif
\ No newline at end of file
+#endif
static PlatformShim platform_shim;
extern "C" {
#if defined(__linux__) || defined(__FreeBSD__)
-PlatformShim* get_platform_shim() {
- platform_shim = PlatformShim();
+PlatformShim* get_platform_shim(std::vector<fs::FolderManager>* folders) {
+ platform_shim = PlatformShim(folders);
return &platform_shim;
}
#elif defined(__APPLE__)
-FRAMEWORK_EXPORT PlatformShim* get_platform_shim() {
- platform_shim = PlatformShim();
+FRAMEWORK_EXPORT PlatformShim* get_platform_shim(std::vector<fs::FolderManager>* folders) {
+ platform_shim = PlatformShim(folders);
return &platform_shim;
}
#endif
-// Necessary for MacOS function himming
+// Necessary for MacOS function shimming
#if defined(__linux__) || defined(__FreeBSD__)
#define OPENDIR_FUNC_NAME opendir
+#define READDIR_FUNC_NAME readdir
+#define CLOSEDIR_FUNC_NAME closedir
#define ACCESS_FUNC_NAME access
#define FOPEN_FUNC_NAME fopen
#define GETEUID_FUNC_NAME geteuid
#endif
#elif defined(__APPLE__)
#define OPENDIR_FUNC_NAME my_opendir
+#define READDIR_FUNC_NAME my_readdir
+#define CLOSEDIR_FUNC_NAME my_closedir
#define ACCESS_FUNC_NAME my_access
#define FOPEN_FUNC_NAME my_fopen
#define GETEUID_FUNC_NAME my_geteuid
#endif
using PFN_OPENDIR = DIR* (*)(const char* path_name);
+using PFN_READDIR = struct dirent* (*)(DIR* dir_stream);
+using PFN_CLOSEDIR = int (*)(DIR* dir_stream);
using PFN_ACCESS = int (*)(const char* pathname, int mode);
using PFN_FOPEN = FILE* (*)(const char* filename, const char* mode);
using PFN_GETEUID = uid_t (*)(void);
#endif
static PFN_OPENDIR real_opendir = nullptr;
+static PFN_READDIR real_readdir = nullptr;
+static PFN_CLOSEDIR real_closedir = nullptr;
static PFN_ACCESS real_access = nullptr;
static PFN_FOPEN real_fopen = nullptr;
static PFN_GETEUID real_geteuid = nullptr;
if (platform_shim.is_fake_path(path_name)) {
auto fake_path_name = platform_shim.get_fake_path(fs::path(path_name));
dir = real_opendir(fake_path_name.c_str());
+ platform_shim.dir_entries.push_back(DirEntry{dir, std::string(path_name), {}, false});
} else {
dir = real_opendir(path_name);
}
return dir;
}
+FRAMEWORK_EXPORT struct dirent* READDIR_FUNC_NAME(DIR* dir_stream) {
+ if (!real_readdir) real_readdir = (PFN_READDIR)dlsym(RTLD_NEXT, "readdir");
+ auto it = std::find_if(platform_shim.dir_entries.begin(), platform_shim.dir_entries.end(),
+ [dir_stream](DirEntry const& entry) { return entry.directory == dir_stream; });
+
+ if (it == platform_shim.dir_entries.end()) {
+ return real_readdir(dir_stream);
+ }
+ // Folder was found but this is the first file to be read from it
+ if (it->current_index == 0) {
+ std::vector<struct dirent*> folder_contents;
+ std::vector<std::string> dirent_filenames;
+ while (true) {
+ struct dirent* dir_entry = real_readdir(dir_stream);
+ if (NULL == dir_entry) {
+ break;
+ }
+ folder_contents.push_back(dir_entry);
+ dirent_filenames.push_back(&dir_entry->d_name[0]);
+ }
+ auto real_path = platform_shim.redirection_map.at(it->folder_path);
+ auto filenames = get_folder_contents(platform_shim.folders, real_path.str());
+
+ // Add the dirent structures in the order they appear in the FolderManager
+ // Ignore anything which wasn't in the FolderManager
+ for (auto const& file : filenames) {
+ for (size_t i = 0; i < dirent_filenames.size(); i++) {
+ if (file == dirent_filenames.at(i)) {
+ it->contents.push_back(folder_contents.at(i));
+ break;
+ }
+ }
+ }
+ }
+ if (it->current_index >= it->contents.size()) return nullptr;
+ return it->contents.at(it->current_index++);
+}
+
+FRAMEWORK_EXPORT int CLOSEDIR_FUNC_NAME(DIR* dir_stream) {
+ if (!real_closedir) real_closedir = (PFN_CLOSEDIR)dlsym(RTLD_NEXT, "closedir");
+
+ auto it = std::find_if(platform_shim.dir_entries.begin(), platform_shim.dir_entries.end(),
+ [dir_stream](DirEntry const& entry) { return entry.directory == dir_stream; });
+
+ if (it != platform_shim.dir_entries.end()) {
+ platform_shim.dir_entries.erase(it);
+ }
+
+ return real_closedir(dir_stream);
+}
+
FRAMEWORK_EXPORT int ACCESS_FUNC_NAME(const char* in_pathname, int mode) {
if (!real_access) real_access = (PFN_ACCESS)dlsym(RTLD_NEXT, "access");
};
__attribute__((used)) static Interposer _interpose_opendir MACOS_ATTRIB = {VOIDP_CAST(my_opendir), VOIDP_CAST(opendir)};
+// don't intercept readdir as it crashes when using ASAN with macOS
+// __attribute__((used)) static Interposer _interpose_readdir MACOS_ATTRIB = {VOIDP_CAST(my_readdir), VOIDP_CAST(readdir)};
+__attribute__((used)) static Interposer _interpose_closedir MACOS_ATTRIB = {VOIDP_CAST(my_closedir), VOIDP_CAST(closedir)};
__attribute__((used)) static Interposer _interpose_access MACOS_ATTRIB = {VOIDP_CAST(my_access), VOIDP_CAST(access)};
__attribute__((used)) static Interposer _interpose_fopen MACOS_ATTRIB = {VOIDP_CAST(my_fopen), VOIDP_CAST(fopen)};
__attribute__((used)) static Interposer _interpose_euid MACOS_ATTRIB = {VOIDP_CAST(my_geteuid), VOIDP_CAST(geteuid)};
return DXGI_ERROR_INVALID_CALL;
}
if (ppAdapter != nullptr) {
- auto* pAdapter = create_IDXGIAdapter1();
+ auto *pAdapter = create_IDXGIAdapter1();
*ppAdapter = pAdapter;
platform_shim.dxgi_adapter_map[pAdapter] = Adapter;
}
return DXGI_ERROR_INVALID_CALL;
}
if (ppAdapter != nullptr) {
- auto* pAdapter = create_IDXGIAdapter1();
+ auto *pAdapter = create_IDXGIAdapter1();
*ppAdapter = pAdapter;
platform_shim.dxgi_adapter_map[pAdapter] = Adapter;
}
assert(GpuPreference == DXGI_GPU_PREFERENCE::DXGI_GPU_PREFERENCE_UNSPECIFIED &&
"Test shim assumes the GpuPreference is unspecified.");
if (ppvAdapter != nullptr) {
- auto* pAdapter = create_IDXGIAdapter1();
+ auto *pAdapter = create_IDXGIAdapter1();
*ppvAdapter = pAdapter;
platform_shim.dxgi_adapter_map[pAdapter] = Adapter;
}
LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) {
const std::string *path = get_path_of_created_key(hKey);
if (path == nullptr) return ERROR_NO_MORE_ITEMS;
+
const auto *location_ptr = get_registry_vector(*path);
if (location_ptr == nullptr) return ERROR_NO_MORE_ITEMS;
const auto &location = *location_ptr;
if (dwIndex >= location.size()) return ERROR_NO_MORE_ITEMS;
+
if (*lpcchValueName < location[dwIndex].name.size()) return ERROR_NO_MORE_ITEMS;
for (size_t i = 0; i < location[dwIndex].name.size(); i++) {
lpValueName[i] = location[dwIndex].name[i];
}
return TRUE;
}
-FRAMEWORK_EXPORT PlatformShim *get_platform_shim() {
- platform_shim = PlatformShim();
+FRAMEWORK_EXPORT PlatformShim *get_platform_shim(std::vector<fs::FolderManager> *folders) {
+ platform_shim = PlatformShim(folders);
return &platform_shim;
}
-}
\ No newline at end of file
+}
create_info.instance_info.pNext = wrapper.get();
}
-PlatformShimWrapper::PlatformShimWrapper() noexcept {
+PlatformShimWrapper::PlatformShimWrapper(std::vector<fs::FolderManager>* folders) noexcept {
#if defined(WIN32) || defined(__APPLE__)
shim_library = LibraryWrapper(SHIM_LIBRARY_NAME);
PFN_get_platform_shim get_platform_shim_func = shim_library.get_symbol(GET_PLATFORM_SHIM_STR);
assert(get_platform_shim_func != NULL && "Must be able to get \"platform_shim\"");
- platform_shim = get_platform_shim_func();
+ platform_shim = get_platform_shim_func(folders);
#elif defined(__linux__) || defined(__FreeBSD__)
- platform_shim = get_platform_shim();
+ platform_shim = get_platform_shim(folders);
#endif
platform_shim->reset();
fs::path TestLayerHandle::get_layer_full_path() noexcept { return layer_library.lib_path; }
fs::path TestLayerHandle::get_layer_manifest_path() noexcept { return manifest_path; }
-FrameworkEnvironment::FrameworkEnvironment() noexcept
- : platform_shim(),
- null_folder(FRAMEWORK_BUILD_DIRECTORY, "null_dir"),
- icd_folder(FRAMEWORK_BUILD_DIRECTORY, "icd_manifests"),
- icd_env_vars_folder(FRAMEWORK_BUILD_DIRECTORY, "icd_env_vars_manifests"),
- explicit_layer_folder(FRAMEWORK_BUILD_DIRECTORY, "explicit_layer_manifests"),
- explicit_env_var_layer_folder(FRAMEWORK_BUILD_DIRECTORY, "explicit_env_var_layer_folder"),
- explicit_add_env_var_layer_folder(FRAMEWORK_BUILD_DIRECTORY, "explicit_add_env_var_layer_folder"),
- implicit_layer_folder(FRAMEWORK_BUILD_DIRECTORY, "implicit_layer_manifests"),
- override_layer_folder(FRAMEWORK_BUILD_DIRECTORY, "override_layer_manifests"),
- vulkan_functions() {
- platform_shim->redirect_all_paths(null_folder.location());
- platform_shim->set_path(ManifestCategory::icd, icd_folder.location());
- platform_shim->set_path(ManifestCategory::explicit_layer, explicit_layer_folder.location());
- platform_shim->set_path(ManifestCategory::implicit_layer, implicit_layer_folder.location());
+FrameworkEnvironment::FrameworkEnvironment() noexcept : platform_shim(&folders), vulkan_functions() {
+ // This order is important, it matches the enum ManifestLocation, used to index the folders vector
+ folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("null_dir"));
+ folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("icd_manifests"));
+ folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("icd_env_vars_manifests"));
+ folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("explicit_layer_manifests"));
+ folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("explicit_env_var_layer_folder"));
+ folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("explicit_add_env_var_layer_folder"));
+ folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("implicit_layer_manifests"));
+ folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("override_layer_manifests"));
+
+ platform_shim->redirect_all_paths(get_folder(ManifestLocation::null).location());
+ platform_shim->set_path(ManifestCategory::icd, get_folder(ManifestLocation::driver).location());
+ platform_shim->set_path(ManifestCategory::explicit_layer, get_folder(ManifestLocation::explicit_layer).location());
+ platform_shim->set_path(ManifestCategory::implicit_layer, get_folder(ManifestLocation::implicit_layer).location());
}
void FrameworkEnvironment::add_icd(TestICDDetails icd_details) noexcept {
size_t cur_icd_index = icds.size();
- fs::FolderManager* folder = &icd_folder;
+ fs::FolderManager* folder = &get_folder(ManifestLocation::driver);
if (icd_details.discovery_type == ManifestDiscoveryType::env_var ||
icd_details.discovery_type == ManifestDiscoveryType::add_env_var) {
- folder = &icd_env_vars_folder;
+ folder = &get_folder(ManifestLocation::driver_env_var);
}
if (!icd_details.is_fake) {
fs::path new_driver_name = fs::path(icd_details.icd_manifest.lib_path).stem() + "_" + std::to_string(cur_icd_index) +
}
void FrameworkEnvironment::add_layer_impl(TestLayerDetails layer_details, ManifestCategory category) {
- fs::FolderManager* fs_ptr = &explicit_layer_folder;
+ fs::FolderManager* fs_ptr = &get_folder(ManifestLocation::explicit_layer);
switch (layer_details.discovery_type) {
default:
case (ManifestDiscoveryType::generic):
- if (category == ManifestCategory::implicit_layer) fs_ptr = &implicit_layer_folder;
+ if (category == ManifestCategory::implicit_layer) fs_ptr = &get_folder(ManifestLocation::implicit_layer);
break;
case (ManifestDiscoveryType::env_var):
- fs_ptr = &explicit_env_var_layer_folder;
+ fs_ptr = &get_folder(ManifestLocation::explicit_layer_env_var);
if (!env_var_vk_layer_paths.empty()) {
env_var_vk_layer_paths += OS_ENV_VAR_LIST_SEPARATOR;
}
- env_var_vk_layer_paths += explicit_env_var_layer_folder.location().str();
+ env_var_vk_layer_paths += fs_ptr->location().str();
set_env_var("VK_LAYER_PATH", env_var_vk_layer_paths);
break;
case (ManifestDiscoveryType::add_env_var):
- fs_ptr = &explicit_add_env_var_layer_folder;
+ fs_ptr = &get_folder(ManifestLocation::explicit_layer_add_env_var);
if (!add_env_var_vk_layer_paths.empty()) {
add_env_var_vk_layer_paths += OS_ENV_VAR_LIST_SEPARATOR;
}
- add_env_var_vk_layer_paths += explicit_add_env_var_layer_folder.location().str();
+ add_env_var_vk_layer_paths += fs_ptr->location().str();
set_env_var("VK_ADD_LAYER_PATH", add_env_var_vk_layer_paths);
break;
case (ManifestDiscoveryType::override_folder):
- fs_ptr = &override_layer_folder;
+ fs_ptr = &get_folder(ManifestLocation::override_layer);
break;
case (ManifestDiscoveryType::none):
break;
fs::path FrameworkEnvironment::get_test_layer_path(size_t index) noexcept { return layers[index].get_layer_full_path(); }
fs::path FrameworkEnvironment::get_layer_manifest_path(size_t index) noexcept { return layers[index].get_layer_manifest_path(); }
+fs::FolderManager& FrameworkEnvironment::get_folder(ManifestLocation location) noexcept {
+ // index it directly using the enum location since they will always be in that order
+ return folders.at(static_cast<size_t>(location));
+}
void setup_WSI_in_ICD(TestICD& icd) {
icd.enable_icd_wsi = true;
#ifdef VK_USE_PLATFORM_ANDROID_KHR
#endif
return surface;
-}
\ No newline at end of file
+}
void FillDebugUtilsCreateDetails(InstanceCreateInfo& create_info, DebugUtilsLogger& logger);
void FillDebugUtilsCreateDetails(InstanceCreateInfo& create_info, DebugUtilsWrapper& wrapper);
+struct FrameworkEnvironment; // forward declaration
+
struct PlatformShimWrapper {
- PlatformShimWrapper() noexcept;
+ PlatformShimWrapper(std::vector<fs::FolderManager>* folders) noexcept;
~PlatformShimWrapper() noexcept;
PlatformShimWrapper(PlatformShimWrapper const&) = delete;
PlatformShimWrapper& operator=(PlatformShimWrapper const&) = delete;
BUILDER_VALUE(TestLayerDetails, bool, is_fake, false);
};
+enum class ManifestLocation {
+ null = 0,
+ driver = 1,
+ driver_env_var = 2,
+ explicit_layer = 3,
+ explicit_layer_env_var = 4,
+ explicit_layer_add_env_var = 5,
+ implicit_layer = 6,
+ override_layer = 7
+};
+
struct FrameworkEnvironment {
FrameworkEnvironment() noexcept;
fs::path get_test_layer_path(size_t index = 0) noexcept;
fs::path get_layer_manifest_path(size_t index = 0) noexcept;
+ fs::FolderManager& get_folder(ManifestLocation location) noexcept;
+
PlatformShimWrapper platform_shim;
- fs::FolderManager null_folder;
- fs::FolderManager icd_folder;
- fs::FolderManager icd_env_vars_folder;
- fs::FolderManager explicit_layer_folder;
- fs::FolderManager explicit_env_var_layer_folder;
- fs::FolderManager explicit_add_env_var_layer_folder;
- fs::FolderManager implicit_layer_folder;
- fs::FolderManager override_layer_folder;
+ std::vector<fs::FolderManager> folders;
DebugUtilsLogger debug_log;
VulkanFunctions vulkan_functions;
void setup_WSI_in_create_instance(InstWrapper& inst);
// api_selection: optionally provide a VK_USE_PLATFORM_XXX string to select which API to create a surface with
// Note: MUST provide api_selection on platforms with multiple viable API's, such as linux and MacOS
-VkSurfaceKHR create_surface(InstWrapper& inst, const char* api_selection = nullptr);
\ No newline at end of file
+VkSurfaceKHR create_surface(InstWrapper& inst, const char* api_selection = nullptr);
const std::string& native_path(const std::string& utf8) { return utf8; }
#endif
-FolderManager::FolderManager(path root_path, std::string name) : folder(root_path / name) {
+FolderManager::FolderManager(path root_path, std::string name) noexcept : folder(root_path / name) {
delete_folder_contents(folder);
create_folder(folder);
}
-FolderManager::~FolderManager() {
+FolderManager::~FolderManager() noexcept {
+ if (folder.str().empty()) return;
auto list_of_files_to_delete = files;
// remove(file) modifies the files variable, copy the list before deleting it
// Note: the allocation tests currently leak the loaded driver handles because in an OOM scenario the loader doesn't bother
}
delete_folder(folder);
}
+FolderManager::FolderManager(FolderManager&& other) noexcept : folder(other.folder), files(other.files) {
+ other.folder.str().clear();
+}
+FolderManager& FolderManager::operator=(FolderManager&& other) noexcept {
+ folder = other.folder;
+ files = other.files;
+ other.folder.str().clear();
+ return *this;
+}
+
path FolderManager::write_manifest(std::string const& name, std::string const& contents) {
path out_path = folder / name;
auto found = std::find(files.begin(), files.end(), name);
class FolderManager {
public:
- explicit FolderManager(path root_path, std::string name);
- ~FolderManager();
+ explicit FolderManager(path root_path, std::string name) noexcept;
+ ~FolderManager() noexcept;
FolderManager(FolderManager const&) = delete;
FolderManager& operator=(FolderManager const&) = delete;
+ FolderManager(FolderManager&& other) noexcept;
+ FolderManager& operator=(FolderManager&& other) noexcept;
path write_manifest(std::string const& name, std::string const& contents);
// location of the managed folder
path location() const { return folder; }
+ std::vector<std::string> get_files() const { return files; }
+
private:
path folder;
std::vector<std::string> files;
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
env.get_test_icd().physical_devices.push_back({});
- env.platform_shim->redirect_path("/tmp/carol", env.explicit_env_var_layer_folder.location());
+ env.platform_shim->redirect_path("/tmp/carol", env.get_folder(ManifestLocation::explicit_layer_env_var).location());
const char* layer_name = "TestLayer";
env.add_explicit_layer(
FrameworkEnvironment env{};
env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
env.get_test_icd().physical_devices.push_back({});
- env.platform_shim->redirect_path("/tmp/carol", env.explicit_add_env_var_layer_folder.location());
+ env.platform_shim->redirect_path("/tmp/carol", env.get_folder(ManifestLocation::explicit_layer_add_env_var).location());
const char* layer_name = "TestLayer";
env.add_explicit_layer(
"regular_test_layer.json"}
.set_discovery_type(ManifestDiscoveryType::override_folder));
- env.add_implicit_layer(ManifestLayer{}
- .set_file_format_version(ManifestVersion(1, 2, 0))
- .add_layer(ManifestLayer::LayerDescription{}
- .set_name(lunarg_meta_layer_name)
- .set_api_version(VK_MAKE_API_VERSION(0, 1, 1, 0))
- .add_component_layer(regular_layer_name)
- .set_disable_environment("DisableMeIfYouCan")
- .add_override_path(env.override_layer_folder.location().str())),
- "meta_test_layer.json");
+ env.add_implicit_layer(
+ ManifestLayer{}
+ .set_file_format_version(ManifestVersion(1, 2, 0))
+ .add_layer(ManifestLayer::LayerDescription{}
+ .set_name(lunarg_meta_layer_name)
+ .set_api_version(VK_MAKE_API_VERSION(0, 1, 1, 0))
+ .add_component_layer(regular_layer_name)
+ .set_disable_environment("DisableMeIfYouCan")
+ .add_override_path(env.get_folder(ManifestLocation::override_layer).location().str())),
+ "meta_test_layer.json");
InstWrapper inst{env.vulkan_functions};
inst.create_info.set_api_version(1, 1, 0);