• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 The Khronos Group Inc.
3  * Copyright (c) 2021 Valve Corporation
4  * Copyright (c) 2021 LunarG, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and/or associated documentation files (the "Materials"), to
8  * deal in the Materials without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Materials, and to permit persons to whom the Materials are
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice(s) and this permission notice shall be included in
14  * all copies or substantial portions of the Materials.
15  *
16  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  *
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
23  * USE OR OTHER DEALINGS IN THE MATERIALS.
24  *
25  * Author: Charles Giessen <charles@lunarg.com>
26  */
27 
28 /*
29  * Contains all the utilities needed to make the framework and tests work.
30  * Contains:
31  * All the standard library includes and main platform specific includes
32  * Dll export macro
33  * Manifest ICD & Layer structs
34  * path abstraction class - modelled after C++17's filesystem::path
35  * FolderManager - manages the contents of a folder, cleaning up when needed
36  * per-platform library loading - mirrors the vk_loader_platform
37  * LibraryWrapper - RAII wrapper for a library
38  * DispatchableHandle - RAII wrapper for vulkan dispatchable handle objects
39  * ostream overload for VkResult - prettifies googletest output
40  * VulkanFunctions - loads vulkan functions for tests to use
41  * Instance & Device create info helpers
42  * operator == overloads for many vulkan structs - more concise tests
43  */
44 #pragma once
45 
46 #include <algorithm>
47 #include <array>
48 #include <iostream>
49 #include <fstream>
50 #include <ostream>
51 #include <string>
52 #include <vector>
53 #include <unordered_map>
54 #include <utility>
55 #include <memory>
56 #include <functional>
57 
58 #include <cassert>
59 #include <cstring>
60 #include <ctime>
61 #include <inttypes.h>
62 #include <stdio.h>
63 #include <stdint.h>
64 
65 #if defined(WIN32)
66 #include <direct.h>
67 #include <windows.h>
68 #include <strsafe.h>
69 #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
70 #include <dirent.h>
71 #include <sys/types.h>
72 #include <sys/stat.h>
73 #include <unistd.h>
74 #include <dlfcn.h>
75 
76 // Prevent macro collisions from <sys/types.h>
77 #undef major
78 #undef minor
79 
80 #endif
81 
82 #include <vulkan/vulkan.h>
83 #include <vulkan/vk_icd.h>
84 #include <vulkan/vk_layer.h>
85 
86 #include "framework_config.h"
87 
88 #if defined(__GNUC__) && __GNUC__ >= 4
89 #define FRAMEWORK_EXPORT __attribute__((visibility("default")))
90 #elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
91 #define FRAMEWORK_EXPORT __attribute__((visibility("default")))
92 #elif defined(WIN32)
93 #define FRAMEWORK_EXPORT __declspec(dllexport)
94 #else
95 #define FRAMEWORK_EXPORT
96 #endif
97 
98 /*
99  * Common Environment Variable operations
100  * These operate on the actual environemnt, they are not shims.
101  * set_env_var - sets the env-var with `name` to `value`.
102  * remove_env_var - unsets the env-var `name`. Different than set_env_var(name, "");
103  * get_env_var - returns a std::string of `name`. if report_failure is true, then it will log to stderr that it didn't find the
104  *     env-var
105  */
106 
107 #if defined(WIN32)
108 void set_env_var(std::string const& name, std::string const& value);
109 void remove_env_var(std::string const& name);
110 std::string get_env_var(std::string const& name, bool report_failure = true);
111 
112 #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
113 void set_env_var(std::string const& name, std::string const& value);
114 void remove_env_var(std::string const& name);
115 std::string get_env_var(std::string const& name, bool report_failure = true);
116 #endif
117 
118 // Windows specific error handling logic
119 #if defined(WIN32)
120 const long ERROR_SETENV_FAILED = 10543;           // chosen at random, attempts to not conflict
121 const long ERROR_REMOVEDIRECTORY_FAILED = 10544;  // chosen at random, attempts to not conflict
122 const char* win_api_error_str(LSTATUS status);
123 void print_error_message(LSTATUS status, const char* function_name, std::string optional_message = "");
124 #endif
125 
126 struct ManifestICD;    // forward declaration for FolderManager::write
127 struct ManifestLayer;  // forward declaration for FolderManager::write
128 
129 #ifdef _WIN32
130 // Environment variable list separator - not for filesystem paths
131 const char OS_ENV_VAR_LIST_SEPARATOR = ';';
132 #else
133 // Environment variable list separator - not for filesystem paths
134 const char OS_ENV_VAR_LIST_SEPARATOR = ':';
135 #endif
136 
137 namespace fs {
138 std::string make_native(std::string const&);
139 
140 struct path {
141    private:
142 #if defined(WIN32)
143     static const char path_separator = '\\';
144 #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
145     static const char path_separator = '/';
146 #endif
147 
148    public:
pathpath149     path() {}
pathpath150     path(std::string const& in) : contents(make_native(in)) {}
pathpath151     path(const char* in) : contents(make_native(std::string(in))) {}
152 
153     // concat paths without directoryseperator
154     path& operator+=(path const& in);
155     path& operator+=(std::string const& in);
156     path& operator+=(const char* in);
157 
158     // append paths with directoryseperator
159     path& operator/=(path const& in);
160     path& operator/=(std::string const& in);
161     path& operator/=(const char* in);
162 
163     // concat paths without directory seperator
164     path operator+(path const& in) const;
165     path operator+(std::string const& in) const;
166     path operator+(const char* in) const;
167 
168     // append paths with directory seperator
169     path operator/(path const& in) const;
170     path operator/(std::string const& in) const;
171     path operator/(const char* in) const;
172 
173     // accesors
174     path parent_path() const;
175     bool has_parent_path() const;
176     path filename() const;
177     path extension() const;
178     path stem() const;
179 
180     // modifiers
181     path& replace_filename(path const& replacement);
182 
183     // get c style string
c_strpath184     const char* c_str() const { return contents.c_str(); }
185     // get C++ style string
strpath186     std::string const& str() const { return contents; }
strpath187     std::string& str() { return contents; }
sizepath188     size_t size() const { return contents.size(); }
189 
190     // equality
191     bool operator==(path const& other) const noexcept { return contents == other.contents; }
192     bool operator!=(path const& other) const noexcept { return !(*this == other); }
193 
194    private:
195     std::string contents;
196 };
197 
198 std::string fixup_backslashes_in_path(std::string const& in_path);
199 fs::path fixup_backslashes_in_path(fs::path const& in_path);
200 
201 int create_folder(path const& path);
202 int delete_folder(path const& folder);
203 
204 class FolderManager {
205    public:
206     explicit FolderManager(path root_path, std::string name) noexcept;
207     ~FolderManager() noexcept;
208     FolderManager(FolderManager const&) = delete;
209     FolderManager& operator=(FolderManager const&) = delete;
210     FolderManager(FolderManager&& other) noexcept;
211     FolderManager& operator=(FolderManager&& other) noexcept;
212 
213     path write_manifest(std::string const& name, std::string const& contents);
214 
215     // close file handle, delete file, remove `name` from managed file list.
216     void remove(std::string const& name);
217 
218     // copy file into this folder with name `new_name`. Returns the full path of the file that was copied
219     path copy_file(path const& file, std::string const& new_name);
220 
221     // location of the managed folder
location()222     path location() const { return folder; }
223 
get_files()224     std::vector<std::string> get_files() const { return files; }
225 
226    private:
227     path folder;
228     std::vector<std::string> files;
229 };
230 }  // namespace fs
231 
232 // copy the contents of a std::string into a char array and add a null terminator at the end
233 // src - std::string to read from
234 // dst - char array to write to
235 // size_dst - number of characters in the dst array
copy_string_to_char_array(std::string const & src,char * dst,size_t size_dst)236 inline void copy_string_to_char_array(std::string const& src, char* dst, size_t size_dst) {
237 // Creates a spurious C4996 Warning in VS 2015 - ignore it
238 #if defined(WIN32)
239 #pragma warning(push)
240 #pragma warning(disable : 4996)
241 #endif
242     dst[src.copy(dst, size_dst - 1)] = 0;
243 #if defined(WIN32)
244 #pragma warning(pop)
245 #endif
246 }
247 
248 #if defined(WIN32)
249 // Convert an UTF-16 wstring to an UTF-8 string
250 std::string narrow(const std::wstring& utf16);
251 // Convert an UTF-8 string to an UTF-16 wstring
252 std::wstring widen(const std::string& utf8);
253 #endif
254 
255 #if defined(WIN32)
256 typedef HMODULE loader_platform_dl_handle;
loader_platform_open_library(const char * lib_path)257 static loader_platform_dl_handle loader_platform_open_library(const char* lib_path) {
258     std::wstring lib_path_utf16 = widen(lib_path);
259     // Try loading the library the original way first.
260     loader_platform_dl_handle lib_handle = LoadLibraryW(lib_path_utf16.c_str());
261     if (lib_handle == nullptr && GetLastError() == ERROR_MOD_NOT_FOUND) {
262         // If that failed, then try loading it with broader search folders.
263         lib_handle =
264             LoadLibraryExW(lib_path_utf16.c_str(), nullptr, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
265     }
266     return lib_handle;
267 }
loader_platform_open_library_error(const char * libPath)268 inline char* loader_platform_open_library_error(const char* libPath) {
269     static char errorMsg[164];
270     (void)snprintf(errorMsg, 163, "Failed to open dynamic library \"%s\" with error %lu", libPath, GetLastError());
271     return errorMsg;
272 }
loader_platform_close_library(loader_platform_dl_handle library)273 inline void loader_platform_close_library(loader_platform_dl_handle library) { FreeLibrary(library); }
loader_platform_get_proc_address(loader_platform_dl_handle library,const char * name)274 inline void* loader_platform_get_proc_address(loader_platform_dl_handle library, const char* name) {
275     assert(library);
276     assert(name);
277     return reinterpret_cast<void*>(GetProcAddress(library, name));
278 }
loader_platform_get_proc_address_error(const char * name)279 inline char* loader_platform_get_proc_address_error(const char* name) {
280     static char errorMsg[120];
281     (void)snprintf(errorMsg, 119, "Failed to find function \"%s\" in dynamic library", name);
282     return errorMsg;
283 }
284 
285 #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
286 
287 typedef void* loader_platform_dl_handle;
loader_platform_open_library(const char * libPath)288 inline loader_platform_dl_handle loader_platform_open_library(const char* libPath) {
289     return dlopen(libPath, RTLD_LAZY | RTLD_LOCAL);
290 }
loader_platform_open_library_error(const char * libPath)291 inline const char* loader_platform_open_library_error(const char* libPath) { return dlerror(); }
loader_platform_close_library(loader_platform_dl_handle library)292 inline void loader_platform_close_library(loader_platform_dl_handle library) { dlclose(library); }
loader_platform_get_proc_address(loader_platform_dl_handle library,const char * name)293 inline void* loader_platform_get_proc_address(loader_platform_dl_handle library, const char* name) {
294     assert(library);
295     assert(name);
296     return dlsym(library, name);
297 }
loader_platform_get_proc_address_error(const char * name)298 inline const char* loader_platform_get_proc_address_error(const char* name) { return dlerror(); }
299 #endif
300 
301 class FromVoidStarFunc {
302    private:
303     void* function;
304 
305    public:
FromVoidStarFunc(void * function)306     FromVoidStarFunc(void* function) : function(function) {}
FromVoidStarFunc(PFN_vkVoidFunction function)307     FromVoidStarFunc(PFN_vkVoidFunction function) : function(reinterpret_cast<void*>(function)) {}
308 
309     template <typename T>
T()310     operator T() {
311         return reinterpret_cast<T>(function);
312     }
313 };
314 
315 struct LibraryWrapper {
LibraryWrapperLibraryWrapper316     explicit LibraryWrapper() noexcept {}
LibraryWrapperLibraryWrapper317     explicit LibraryWrapper(fs::path const& lib_path) noexcept : lib_path(lib_path) {
318         lib_handle = loader_platform_open_library(lib_path.c_str());
319         if (lib_handle == nullptr) {
320             fprintf(stderr, "Unable to open library %s: %s\n", lib_path.c_str(),
321                     loader_platform_open_library_error(lib_path.c_str()));
322             assert(lib_handle != nullptr && "Must be able to open library");
323         }
324     }
~LibraryWrapperLibraryWrapper325     ~LibraryWrapper() noexcept {
326         if (lib_handle != nullptr) {
327             loader_platform_close_library(lib_handle);
328             lib_handle = nullptr;
329         }
330     }
331     LibraryWrapper(LibraryWrapper const& wrapper) = delete;
332     LibraryWrapper& operator=(LibraryWrapper const& wrapper) = delete;
LibraryWrapperLibraryWrapper333     LibraryWrapper(LibraryWrapper&& wrapper) noexcept : lib_handle(wrapper.lib_handle), lib_path(wrapper.lib_path) {
334         wrapper.lib_handle = nullptr;
335     }
336     LibraryWrapper& operator=(LibraryWrapper&& wrapper) noexcept {
337         if (this != &wrapper) {
338             if (lib_handle != nullptr) {
339                 loader_platform_close_library(lib_handle);
340             }
341             lib_handle = wrapper.lib_handle;
342             lib_path = wrapper.lib_path;
343             wrapper.lib_handle = nullptr;
344         }
345         return *this;
346     }
get_symbolLibraryWrapper347     FromVoidStarFunc get_symbol(const char* symbol_name) const {
348         assert(lib_handle != nullptr && "Cannot get symbol with null library handle");
349         void* symbol = loader_platform_get_proc_address(lib_handle, symbol_name);
350         if (symbol == nullptr) {
351             fprintf(stderr, "Unable to open symbol %s: %s\n", symbol_name, loader_platform_get_proc_address_error(symbol_name));
352             assert(symbol != nullptr && "Must be able to get symbol");
353         }
354         return FromVoidStarFunc(symbol);
355     }
356 
357     explicit operator bool() const noexcept { return lib_handle != nullptr; }
358 
359     loader_platform_dl_handle lib_handle = nullptr;
360     fs::path lib_path;
361 };
362 
363 template <typename T>
to_vkVoidFunction(T func)364 PFN_vkVoidFunction to_vkVoidFunction(T func) {
365     return reinterpret_cast<PFN_vkVoidFunction>(func);
366 }
367 template <typename T>
368 struct FRAMEWORK_EXPORT DispatchableHandle {
DispatchableHandleDispatchableHandle369     DispatchableHandle() {
370         auto ptr_handle = new VK_LOADER_DATA;
371         set_loader_magic_value(ptr_handle);
372         handle = reinterpret_cast<T>(ptr_handle);
373     }
~DispatchableHandleDispatchableHandle374     ~DispatchableHandle() {
375         delete reinterpret_cast<VK_LOADER_DATA*>(handle);
376         handle = nullptr;
377     }
378     DispatchableHandle(DispatchableHandle const&) = delete;
379     DispatchableHandle& operator=(DispatchableHandle const&) = delete;
DispatchableHandleDispatchableHandle380     DispatchableHandle(DispatchableHandle&& other) noexcept : handle(other.handle) { other.handle = nullptr; }
381     DispatchableHandle& operator=(DispatchableHandle&& other) noexcept {
382         if (this != &other) {
383             delete reinterpret_cast<VK_LOADER_DATA*>(handle);
384             handle = other.handle;
385             other.handle = nullptr;
386         }
387         return *this;
388     }
389     bool operator==(T base_handle) { return base_handle == handle; }
390     bool operator!=(T base_handle) { return base_handle != handle; }
391 
392     T handle = nullptr;
393 };
394 
395 // Stream operator for VkResult so GTEST will print out error codes as strings (automatically)
396 inline std::ostream& operator<<(std::ostream& os, const VkResult& result) {
397     switch (result) {
398         case (VK_SUCCESS):
399             return os << "VK_SUCCESS";
400         case (VK_NOT_READY):
401             return os << "VK_NOT_READY";
402         case (VK_TIMEOUT):
403             return os << "VK_TIMEOUT";
404         case (VK_EVENT_SET):
405             return os << "VK_EVENT_SET";
406         case (VK_EVENT_RESET):
407             return os << "VK_EVENT_RESET";
408         case (VK_INCOMPLETE):
409             return os << "VK_INCOMPLETE";
410         case (VK_ERROR_OUT_OF_HOST_MEMORY):
411             return os << "VK_ERROR_OUT_OF_HOST_MEMORY";
412         case (VK_ERROR_OUT_OF_DEVICE_MEMORY):
413             return os << "VK_ERROR_OUT_OF_DEVICE_MEMORY";
414         case (VK_ERROR_INITIALIZATION_FAILED):
415             return os << "VK_ERROR_INITIALIZATION_FAILED";
416         case (VK_ERROR_DEVICE_LOST):
417             return os << "VK_ERROR_DEVICE_LOST";
418         case (VK_ERROR_MEMORY_MAP_FAILED):
419             return os << "VK_ERROR_MEMORY_MAP_FAILED";
420         case (VK_ERROR_LAYER_NOT_PRESENT):
421             return os << "VK_ERROR_LAYER_NOT_PRESENT";
422         case (VK_ERROR_EXTENSION_NOT_PRESENT):
423             return os << "VK_ERROR_EXTENSION_NOT_PRESENT";
424         case (VK_ERROR_FEATURE_NOT_PRESENT):
425             return os << "VK_ERROR_FEATURE_NOT_PRESENT";
426         case (VK_ERROR_INCOMPATIBLE_DRIVER):
427             return os << "VK_ERROR_INCOMPATIBLE_DRIVER";
428         case (VK_ERROR_TOO_MANY_OBJECTS):
429             return os << "VK_ERROR_TOO_MANY_OBJECTS";
430         case (VK_ERROR_FORMAT_NOT_SUPPORTED):
431             return os << "VK_ERROR_FORMAT_NOT_SUPPORTED";
432         case (VK_ERROR_FRAGMENTED_POOL):
433             return os << "VK_ERROR_FRAGMENTED_POOL";
434         case (VK_ERROR_UNKNOWN):
435             return os << "VK_ERROR_UNKNOWN";
436         case (VK_ERROR_OUT_OF_POOL_MEMORY):
437             return os << "VK_ERROR_OUT_OF_POOL_MEMORY";
438         case (VK_ERROR_INVALID_EXTERNAL_HANDLE):
439             return os << "VK_ERROR_INVALID_EXTERNAL_HANDLE";
440         case (VK_ERROR_FRAGMENTATION):
441             return os << "VK_ERROR_FRAGMENTATION";
442         case (VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS):
443             return os << "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS";
444         case (VK_ERROR_SURFACE_LOST_KHR):
445             return os << "VK_ERROR_SURFACE_LOST_KHR";
446         case (VK_ERROR_NATIVE_WINDOW_IN_USE_KHR):
447             return os << "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR";
448         case (VK_SUBOPTIMAL_KHR):
449             return os << "VK_SUBOPTIMAL_KHR";
450         case (VK_ERROR_OUT_OF_DATE_KHR):
451             return os << "VK_ERROR_OUT_OF_DATE_KHR";
452         case (VK_ERROR_INCOMPATIBLE_DISPLAY_KHR):
453             return os << "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR";
454         case (VK_ERROR_VALIDATION_FAILED_EXT):
455             return os << "VK_ERROR_VALIDATION_FAILED_EXT";
456         case (VK_ERROR_INVALID_SHADER_NV):
457             return os << "VK_ERROR_INVALID_SHADER_NV";
458         case (VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT):
459             return os << "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT";
460         case (VK_ERROR_NOT_PERMITTED_EXT):
461             return os << "VK_ERROR_NOT_PERMITTED_EXT";
462         case (VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT):
463             return os << "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT";
464         case (VK_THREAD_IDLE_KHR):
465             return os << "VK_THREAD_IDLE_KHR";
466         case (VK_THREAD_DONE_KHR):
467             return os << "VK_THREAD_DONE_KHR";
468         case (VK_OPERATION_DEFERRED_KHR):
469             return os << "VK_OPERATION_DEFERRED_KHR";
470         case (VK_OPERATION_NOT_DEFERRED_KHR):
471             return os << "VK_OPERATION_NOT_DEFERRED_KHR";
472         case (VK_PIPELINE_COMPILE_REQUIRED_EXT):
473             return os << "VK_PIPELINE_COMPILE_REQUIRED_EXT";
474         case (VK_RESULT_MAX_ENUM):
475             return os << "VK_RESULT_MAX_ENUM";
476         case (VK_ERROR_COMPRESSION_EXHAUSTED_EXT):
477             return os << "VK_ERROR_COMPRESSION_EXHAUSTED_EXT";
478         case (VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR):
479             return os << "VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR";
480         case (VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR):
481             return os << "VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR";
482         case (VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR):
483             return os << "VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR";
484         case (VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR):
485             return os << "VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR";
486         case (VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR):
487             return os << "VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR";
488         case (VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR):
489             return os << "VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR";
490     }
491     return os << static_cast<int32_t>(result);
492 }
493 
494 bool string_eq(const char* a, const char* b) noexcept;
495 bool string_eq(const char* a, const char* b, size_t len) noexcept;
496 
version_to_string(uint32_t version)497 inline std::string version_to_string(uint32_t version) {
498     std::string out = std::to_string(VK_API_VERSION_MAJOR(version)) + "." + std::to_string(VK_API_VERSION_MINOR(version)) + "." +
499                       std::to_string(VK_API_VERSION_PATCH(version));
500     if (VK_API_VERSION_VARIANT(version) != 0) out += std::to_string(VK_API_VERSION_VARIANT(version)) + "." + out;
501     return out;
502 }
503 
504 // Macro to ease the definition of variables with builder member functions
505 // class_name = class the member variable is apart of
506 // type = type of the variable
507 // name = name of the variable
508 // default_value = value to default initialize, use {} if nothing else makes sense
509 #define BUILDER_VALUE(class_name, type, name, default_value) \
510     type name = default_value;                               \
511     class_name& set_##name(type const& name) {               \
512         this->name = name;                                   \
513         return *this;                                        \
514     }
515 
516 // Macro to ease the definition of vectors with builder member functions
517 // class_name = class the member variable is apart of
518 // type = type of the variable
519 // name = name of the variable
520 // singular_name = used for the `add_singular_name` member function
521 #define BUILDER_VECTOR(class_name, type, name, singular_name)                    \
522     std::vector<type> name;                                                      \
523     class_name& add_##singular_name(type const& singular_name) {                 \
524         this->name.push_back(singular_name);                                     \
525         return *this;                                                            \
526     }                                                                            \
527     class_name& add_##singular_name##s(std::vector<type> const& singular_name) { \
528         for (auto& elem : singular_name) this->name.push_back(elem);             \
529         return *this;                                                            \
530     }
531 // Like BUILDER_VECTOR but for move only types - where passing in means giving up ownership
532 #define BUILDER_VECTOR_MOVE_ONLY(class_name, type, name, singular_name) \
533     std::vector<type> name;                                             \
534     class_name& add_##singular_name(type&& singular_name) {             \
535         this->name.push_back(std::move(singular_name));                 \
536         return *this;                                                   \
537     }
538 
539 struct ManifestVersion {
540     BUILDER_VALUE(ManifestVersion, uint32_t, major, 1)
541     BUILDER_VALUE(ManifestVersion, uint32_t, minor, 0)
542     BUILDER_VALUE(ManifestVersion, uint32_t, patch, 0)
ManifestVersionManifestVersion543     ManifestVersion() noexcept {};
ManifestVersionManifestVersion544     ManifestVersion(uint32_t major, uint32_t minor, uint32_t patch) noexcept : major(major), minor(minor), patch(patch){};
545 
get_version_strManifestVersion546     std::string get_version_str() const noexcept {
547         return std::string("\"file_format_version\": \"") + std::to_string(major) + "." + std::to_string(minor) + "." +
548                std::to_string(patch) + "\",";
549     }
550 };
551 
552 // ManifestICD builder
553 struct ManifestICD {
554     BUILDER_VALUE(ManifestICD, ManifestVersion, file_format_version, ManifestVersion())
555     BUILDER_VALUE(ManifestICD, uint32_t, api_version, 0)
556     BUILDER_VALUE(ManifestICD, std::string, lib_path, {})
557     BUILDER_VALUE(ManifestICD, bool, is_portability_driver, false)
558     BUILDER_VALUE(ManifestICD, std::string, library_arch, "")
559     std::string get_manifest_str() const;
560 };
561 
562 // ManifestLayer builder
563 struct ManifestLayer {
564     struct LayerDescription {
565         enum class Type { INSTANCE, GLOBAL, DEVICE };
get_type_strManifestLayer::LayerDescription566         std::string get_type_str(Type layer_type) const {
567             if (layer_type == Type::GLOBAL)
568                 return "GLOBAL";
569             else if (layer_type == Type::DEVICE)
570                 return "DEVICE";
571             else  // default
572                 return "INSTANCE";
573         }
574         struct FunctionOverride {
575             BUILDER_VALUE(FunctionOverride, std::string, vk_func, {})
576             BUILDER_VALUE(FunctionOverride, std::string, override_name, {})
577 
get_manifest_strManifestLayer::LayerDescription::FunctionOverride578             std::string get_manifest_str() const { return std::string("\"") + vk_func + "\":\"" + override_name + "\""; }
579         };
580         struct Extension {
ExtensionManifestLayer::LayerDescription::Extension581             Extension() noexcept {}
582             Extension(std::string name, uint32_t spec_version = 0, std::vector<std::string> entrypoints = {}) noexcept
nameManifestLayer::LayerDescription::Extension583                 : name(name), spec_version(spec_version), entrypoints(entrypoints) {}
584             std::string name;
585             uint32_t spec_version = 0;
586             std::vector<std::string> entrypoints;
587             std::string get_manifest_str() const;
588         };
589         BUILDER_VALUE(LayerDescription, std::string, name, {})
590         BUILDER_VALUE(LayerDescription, Type, type, Type::INSTANCE)
591         BUILDER_VALUE(LayerDescription, fs::path, lib_path, {})
592         BUILDER_VALUE(LayerDescription, uint32_t, api_version, VK_API_VERSION_1_0)
593         BUILDER_VALUE(LayerDescription, uint32_t, implementation_version, 0)
594         BUILDER_VALUE(LayerDescription, std::string, description, {})
595         BUILDER_VECTOR(LayerDescription, FunctionOverride, functions, function)
596         BUILDER_VECTOR(LayerDescription, Extension, instance_extensions, instance_extension)
597         BUILDER_VECTOR(LayerDescription, Extension, device_extensions, device_extension)
598         BUILDER_VALUE(LayerDescription, std::string, enable_environment, {})
599         BUILDER_VALUE(LayerDescription, std::string, disable_environment, {})
600         BUILDER_VECTOR(LayerDescription, std::string, component_layers, component_layer)
601         BUILDER_VECTOR(LayerDescription, std::string, blacklisted_layers, blacklisted_layer)
602         BUILDER_VECTOR(LayerDescription, std::string, override_paths, override_path)
603         BUILDER_VECTOR(LayerDescription, FunctionOverride, pre_instance_functions, pre_instance_function)
604         BUILDER_VECTOR(LayerDescription, std::string, app_keys, app_key)
605         BUILDER_VALUE(LayerDescription, std::string, library_arch, "")
606 
607         std::string get_manifest_str() const;
608         VkLayerProperties get_layer_properties() const;
609     };
610     BUILDER_VALUE(ManifestLayer, ManifestVersion, file_format_version, {})
611     BUILDER_VECTOR(ManifestLayer, LayerDescription, layers, layer)
612 
613     std::string get_manifest_str() const;
614 };
615 
616 struct Extension {
617     BUILDER_VALUE(Extension, std::string, extensionName, {})
BUILDER_VALUEExtension618     BUILDER_VALUE(Extension, uint32_t, specVersion, VK_API_VERSION_1_0)
619 
620     Extension(const char* name, uint32_t specVersion = VK_API_VERSION_1_0) noexcept
621         : extensionName(name), specVersion(specVersion) {}
622     Extension(std::string extensionName, uint32_t specVersion = VK_API_VERSION_1_0) noexcept
extensionNameExtension623         : extensionName(extensionName), specVersion(specVersion) {}
624 
getExtension625     VkExtensionProperties get() const noexcept {
626         VkExtensionProperties props{};
627         copy_string_to_char_array(extensionName, &props.extensionName[0], VK_MAX_EXTENSION_NAME_SIZE);
628         props.specVersion = specVersion;
629         return props;
630     }
631 };
632 
633 struct MockQueueFamilyProperties {
634     BUILDER_VALUE(MockQueueFamilyProperties, VkQueueFamilyProperties, properties, {})
BUILDER_VALUEMockQueueFamilyProperties635     BUILDER_VALUE(MockQueueFamilyProperties, bool, support_present, false)
636 
637     MockQueueFamilyProperties() {}
638 
639     MockQueueFamilyProperties(VkQueueFamilyProperties properties, bool support_present = false)
propertiesMockQueueFamilyProperties640         : properties(properties), support_present(support_present) {}
641 
getMockQueueFamilyProperties642     VkQueueFamilyProperties get() const noexcept { return properties; }
643 };
644 
645 struct VulkanFunctions {
646     LibraryWrapper loader;
647 
648     // Pre-Instance
649     PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = nullptr;
650     PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties = nullptr;
651     PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties = nullptr;
652     PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion = nullptr;
653     PFN_vkCreateInstance vkCreateInstance = nullptr;
654 
655     // Instance
656     PFN_vkDestroyInstance vkDestroyInstance = nullptr;
657     PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices = nullptr;
658     PFN_vkEnumeratePhysicalDeviceGroups vkEnumeratePhysicalDeviceGroups = nullptr;
659     PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures = nullptr;
660     PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2 = nullptr;
661     PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties = nullptr;
662     PFN_vkGetPhysicalDeviceFormatProperties2 vkGetPhysicalDeviceFormatProperties2 = nullptr;
663     PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties = nullptr;
664     PFN_vkGetPhysicalDeviceImageFormatProperties2 vkGetPhysicalDeviceImageFormatProperties2 = nullptr;
665     PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImageFormatProperties = nullptr;
666     PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 vkGetPhysicalDeviceSparseImageFormatProperties2 = nullptr;
667     PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties = nullptr;
668     PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2 = nullptr;
669     PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties = nullptr;
670     PFN_vkGetPhysicalDeviceQueueFamilyProperties2 vkGetPhysicalDeviceQueueFamilyProperties2 = nullptr;
671     PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties = nullptr;
672     PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2 = nullptr;
673     PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR = nullptr;
674     PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR = nullptr;
675     PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR = nullptr;
676     PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR = nullptr;
677     PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties = nullptr;
678     PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties = nullptr;
679     PFN_vkGetPhysicalDeviceExternalBufferProperties vkGetPhysicalDeviceExternalBufferProperties = nullptr;
680     PFN_vkGetPhysicalDeviceExternalFenceProperties vkGetPhysicalDeviceExternalFenceProperties = nullptr;
681     PFN_vkGetPhysicalDeviceExternalSemaphoreProperties vkGetPhysicalDeviceExternalSemaphoreProperties = nullptr;
682 
683     PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = nullptr;
684     PFN_vkCreateDevice vkCreateDevice = nullptr;
685     PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = nullptr;
686     PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT = nullptr;
687 
688     // WSI
689     PFN_vkCreateHeadlessSurfaceEXT vkCreateHeadlessSurfaceEXT = nullptr;
690     PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR = nullptr;
691     PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR = nullptr;
692     PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR = nullptr;
693     PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR = nullptr;
694     PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR = nullptr;
695     PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR = nullptr;
696     PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR = nullptr;
697     PFN_vkGetPhysicalDevicePresentRectanglesKHR vkGetPhysicalDevicePresentRectanglesKHR = nullptr;
698     PFN_vkGetPhysicalDeviceDisplayProperties2KHR vkGetPhysicalDeviceDisplayProperties2KHR = nullptr;
699     PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR vkGetPhysicalDeviceDisplayPlaneProperties2KHR = nullptr;
700     PFN_vkGetDisplayModeProperties2KHR vkGetDisplayModeProperties2KHR = nullptr;
701     PFN_vkGetDisplayPlaneCapabilities2KHR vkGetDisplayPlaneCapabilities2KHR = nullptr;
702     PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR = nullptr;
703     PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR = nullptr;
704 
705 #ifdef VK_USE_PLATFORM_ANDROID_KHR
706     PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR = nullptr;
707 #endif  // VK_USE_PLATFORM_ANDROID_KHR
708 #ifdef VK_USE_PLATFORM_DIRECTFB_EXT
709     PFN_vkCreateDirectFBSurfaceEXT vkCreateDirectFBSurfaceEXT = nullptr;
710     PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT vkGetPhysicalDeviceDirectFBPresentationSupportEXT = nullptr;
711 #endif  // VK_USE_PLATFORM_DIRECTFB_EXT
712 #ifdef VK_USE_PLATFORM_FUCHSIA
713     PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA = nullptr;
714 #endif  // VK_USE_PLATFORM_FUCHSIA
715 #ifdef VK_USE_PLATFORM_GGP
716     PFN_vkCreateStreamDescriptorSurfaceGGP vkCreateStreamDescriptorSurfaceGGP = nullptr;
717 #endif  // VK_USE_PLATFORM_GGP
718 #ifdef VK_USE_PLATFORM_IOS_MVK
719     PFN_vkCreateIOSSurfaceMVK vkCreateIOSSurfaceMVK = nullptr;
720 #endif  // VK_USE_PLATFORM_IOS_MVK
721 #ifdef VK_USE_PLATFORM_MACOS_MVK
722     PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK = nullptr;
723 #endif  // VK_USE_PLATFORM_MACOS_MVK
724 #ifdef VK_USE_PLATFORM_METAL_EXT
725     PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT = nullptr;
726 #endif  // VK_USE_PLATFORM_METAL_EXT
727 #ifdef VK_USE_PLATFORM_SCREEN_QNX
728     PFN_vkCreateScreenSurfaceQNX vkCreateScreenSurfaceQNX = nullptr;
729     PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX vkGetPhysicalDeviceScreenPresentationSupportQNX = nullptr;
730 #endif  // VK_USE_PLATFORM_SCREEN_QNX
731 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
732     PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR = nullptr;
733     PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR = nullptr;
734 #endif  // VK_USE_PLATFORM_WAYLAND_KHR
735 #ifdef VK_USE_PLATFORM_XCB_KHR
736     PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR = nullptr;
737     PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR = nullptr;
738 #endif  // VK_USE_PLATFORM_XCB_KHR
739 #ifdef VK_USE_PLATFORM_XLIB_KHR
740     PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR = nullptr;
741     PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR = nullptr;
742 #endif  // VK_USE_PLATFORM_XLIB_KHR
743 #ifdef VK_USE_PLATFORM_WIN32_KHR
744     PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR = nullptr;
745     PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR = nullptr;
746 #endif  // VK_USE_PLATFORM_WIN32_KHR
747     PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR = nullptr;
748 
749     // device functions
750     PFN_vkDestroyDevice vkDestroyDevice = nullptr;
751     PFN_vkGetDeviceQueue vkGetDeviceQueue = nullptr;
752 
753     VulkanFunctions();
754 
loadVulkanFunctions755     FromVoidStarFunc load(VkInstance inst, const char* func_name) const {
756         return FromVoidStarFunc(vkGetInstanceProcAddr(inst, func_name));
757     }
758 
loadVulkanFunctions759     FromVoidStarFunc load(VkDevice device, const char* func_name) const {
760         return FromVoidStarFunc(vkGetDeviceProcAddr(device, func_name));
761     }
762 };
763 
764 struct DeviceFunctions {
765     PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = nullptr;
766     PFN_vkDestroyDevice vkDestroyDevice = nullptr;
767     PFN_vkGetDeviceQueue vkGetDeviceQueue = nullptr;
768     PFN_vkCreateCommandPool vkCreateCommandPool = nullptr;
769     PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers = nullptr;
770     PFN_vkDestroyCommandPool vkDestroyCommandPool = nullptr;
771     PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR = nullptr;
772     PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR = nullptr;
773 
774     DeviceFunctions() = default;
775     DeviceFunctions(const VulkanFunctions& vulkan_functions, VkDevice device);
776 
loadDeviceFunctions777     FromVoidStarFunc load(VkDevice device, const char* func_name) const {
778         return FromVoidStarFunc(vkGetDeviceProcAddr(device, func_name));
779     }
780 };
781 
782 struct InstanceCreateInfo {
783     BUILDER_VALUE(InstanceCreateInfo, VkInstanceCreateInfo, instance_info, {})
784     BUILDER_VALUE(InstanceCreateInfo, VkApplicationInfo, application_info, {})
785     BUILDER_VALUE(InstanceCreateInfo, std::string, app_name, {})
786     BUILDER_VALUE(InstanceCreateInfo, std::string, engine_name, {})
787     BUILDER_VALUE(InstanceCreateInfo, uint32_t, flags, 0)
788     BUILDER_VALUE(InstanceCreateInfo, uint32_t, app_version, 0)
789     BUILDER_VALUE(InstanceCreateInfo, uint32_t, engine_version, 0)
790     BUILDER_VALUE(InstanceCreateInfo, uint32_t, api_version, VK_API_VERSION_1_0)
791     BUILDER_VECTOR(InstanceCreateInfo, const char*, enabled_layers, layer)
792     BUILDER_VECTOR(InstanceCreateInfo, const char*, enabled_extensions, extension)
793     // tell the get() function to not provide `application_info`
794     BUILDER_VALUE(InstanceCreateInfo, bool, fill_in_application_info, true)
795 
796     InstanceCreateInfo();
797 
798     VkInstanceCreateInfo* get() noexcept;
799 
800     InstanceCreateInfo& set_api_version(uint32_t major, uint32_t minor, uint32_t patch);
801 };
802 
803 struct DeviceQueueCreateInfo {
804     BUILDER_VALUE(DeviceQueueCreateInfo, VkDeviceQueueCreateInfo, queue_create_info, {})
805     BUILDER_VECTOR(DeviceQueueCreateInfo, float, priorities, priority)
806 
807     DeviceQueueCreateInfo();
808     VkDeviceQueueCreateInfo get() noexcept;
809 };
810 
811 struct DeviceCreateInfo {
812     BUILDER_VALUE(DeviceCreateInfo, VkDeviceCreateInfo, dev, {})
813     BUILDER_VECTOR(DeviceCreateInfo, const char*, enabled_extensions, extension)
814     BUILDER_VECTOR(DeviceCreateInfo, const char*, enabled_layers, layer)
815     BUILDER_VECTOR(DeviceCreateInfo, DeviceQueueCreateInfo, queue_info_details, device_queue)
816 
817     VkDeviceCreateInfo* get() noexcept;
818 
819    private:
820     std::vector<VkDeviceQueueCreateInfo> device_queue_infos;
821 };
822 
823 inline bool operator==(const VkExtent3D& a, const VkExtent3D& b) {
824     return a.width == b.width && a.height == b.height && a.depth == b.depth;
825 }
826 inline bool operator!=(const VkExtent3D& a, const VkExtent3D& b) { return !(a == b); }
827 
828 inline bool operator==(const VkQueueFamilyProperties& a, const VkQueueFamilyProperties& b) {
829     return a.minImageTransferGranularity == b.minImageTransferGranularity && a.queueCount == b.queueCount &&
830            a.queueFlags == b.queueFlags && a.timestampValidBits == b.timestampValidBits;
831 }
832 inline bool operator!=(const VkQueueFamilyProperties& a, const VkQueueFamilyProperties& b) { return !(a == b); }
833 
834 inline bool operator==(const VkLayerProperties& a, const VkLayerProperties& b) {
835     return string_eq(a.layerName, b.layerName, 256) && string_eq(a.description, b.description, 256) &&
836            a.implementationVersion == b.implementationVersion && a.specVersion == b.specVersion;
837 }
838 inline bool operator!=(const VkLayerProperties& a, const VkLayerProperties& b) { return !(a == b); }
839 
840 inline bool operator==(const VkExtensionProperties& a, const VkExtensionProperties& b) {
841     return string_eq(a.extensionName, b.extensionName, 256) && a.specVersion == b.specVersion;
842 }
843 inline bool operator!=(const VkExtensionProperties& a, const VkExtensionProperties& b) { return !(a == b); }
844 
845 struct VulkanFunction {
846     std::string name;
847     PFN_vkVoidFunction function;
848 };
849 
850 template <typename T, size_t U>
check_permutation(std::initializer_list<const char * > expected,std::array<T,U> const & returned)851 bool check_permutation(std::initializer_list<const char*> expected, std::array<T, U> const& returned) {
852     if (expected.size() != returned.size()) return false;
853     for (uint32_t i = 0; i < expected.size(); i++) {
854         bool found = false;
855         for (auto& elem : returned) {
856             if (string_eq(*(expected.begin() + i), elem.layerName)) {
857                 found = true;
858                 break;
859             }
860         }
861         if (!found) return false;
862     }
863     return true;
864 }
865 template <typename T, size_t U>
check_permutation(std::initializer_list<const char * > expected,std::vector<T> const & returned)866 bool check_permutation(std::initializer_list<const char*> expected, std::vector<T> const& returned) {
867     if (expected.size() != returned.size()) return false;
868     for (uint32_t i = 0; i < expected.size(); i++) {
869         bool found = false;
870         for (auto& elem : returned) {
871             if (string_eq(*(expected.begin() + i), elem.layerName)) {
872                 found = true;
873                 break;
874             }
875         }
876         if (!found) return false;
877     }
878     return true;
879 }
880 
contains(std::vector<VkExtensionProperties> const & vec,const char * name)881 inline bool contains(std::vector<VkExtensionProperties> const& vec, const char* name) {
882     return std::any_of(std::begin(vec), std::end(vec),
883                        [name](VkExtensionProperties const& elem) { return string_eq(name, elem.extensionName); });
884 }
contains(std::vector<VkLayerProperties> const & vec,const char * name)885 inline bool contains(std::vector<VkLayerProperties> const& vec, const char* name) {
886     return std::any_of(std::begin(vec), std::end(vec),
887                        [name](VkLayerProperties const& elem) { return string_eq(name, elem.layerName); });
888 }
889 
890 #if defined(__linux__)
891 
892 // find application path + name. Path cannot be longer than 1024, returns NULL if it is greater than that.
test_platform_executable_path()893 static inline std::string test_platform_executable_path() {
894     std::string buffer;
895     buffer.resize(1024);
896     ssize_t count = readlink("/proc/self/exe", &buffer[0], buffer.size());
897     if (count == -1) return NULL;
898     if (count == 0) return NULL;
899     buffer[count] = '\0';
900     buffer.resize(count);
901     return buffer;
902 }
903 #elif defined(__APPLE__)  // defined(__linux__)
904 #include <libproc.h>
test_platform_executable_path()905 static inline std::string test_platform_executable_path() {
906     std::string buffer;
907     buffer.resize(1024);
908     pid_t pid = getpid();
909     int ret = proc_pidpath(pid, &buffer[0], buffer.size());
910     if (ret <= 0) return NULL;
911     buffer[ret] = '\0';
912     buffer.resize(ret);
913     return buffer;
914 }
915 #elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
916 #include <sys/sysctl.h>
test_platform_executable_path()917 static inline std::string test_platform_executable_path() {
918     int mib[] = {
919         CTL_KERN,
920 #if defined(__NetBSD__)
921         KERN_PROC_ARGS,
922         -1,
923         KERN_PROC_PATHNAME,
924 #else
925         KERN_PROC,
926         KERN_PROC_PATHNAME,
927         -1,
928 #endif
929     };
930     std::string buffer;
931     buffer.resize(1024);
932     size_t size = buffer.size();
933     if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), &buffer[0], &size, NULL, 0) < 0) {
934         return NULL;
935     }
936     buffer.resize(size);
937 
938     return buffer;
939 }
940 #elif defined(__Fuchsia__) || defined(__OpenBSD__)
test_platform_executable_path()941 static inline std::string test_platform_executable_path() { return {}; }
942 #elif defined(__QNXNTO__)
943 
944 #define SYSCONFDIR "/etc"
945 
946 #include <fcntl.h>
947 #include <sys/stat.h>
948 
test_platform_executable_path()949 static inline std::string test_platform_executable_path() {
950     std::string buffer;
951     buffer.resize(1024);
952     int fd = open("/proc/self/exefile", O_RDONLY);
953     size_t rdsize;
954 
955     if (fd == -1) {
956         return NULL;
957     }
958 
959     rdsize = read(fd, &buffer[0], buffer.size());
960     if (rdsize == size) {
961         return NULL;
962     }
963     buffer[rdsize] = 0x00;
964     close(fd);
965     buffer.resize(rdsize);
966 
967     return buffer;
968 }
969 #endif  // defined (__QNXNTO__)
970 #if defined(WIN32)
test_platform_executable_path()971 static inline std::string test_platform_executable_path() {
972     std::string buffer;
973     buffer.resize(1024);
974     DWORD ret = GetModuleFileName(NULL, static_cast<LPSTR>(&buffer[0]), (DWORD)buffer.size());
975     if (ret == 0) return NULL;
976     if (ret > buffer.size()) return NULL;
977     buffer.resize(ret);
978     buffer[ret] = '\0';
979     return buffer;
980 }
981 #endif
982