├── .clang-format ├── .gitignore ├── CMakeLists.txt ├── README.md ├── codegen_text.py ├── generate.py ├── include └── vulkan │ ├── vk_platform.h │ ├── vulkan.cpp │ ├── vulkan.h │ ├── vulkan_string.cpp │ └── vulkan_string.h ├── sample ├── CMakeLists.txt ├── shaders │ ├── frag.glsl │ ├── frag.spv │ ├── vert.glsl │ └── vert.spv └── triangle.cpp └── test ├── CMakeLists.txt └── main.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | # Use defaults from the Google style with the following exceptions: 3 | BasedOnStyle: Mozilla 4 | IndentWidth: 4 5 | ColumnLimit: 132 6 | SortIncludes: false 7 | AlwaysBreakAfterDefinitionReturnType : None 8 | AlwaysBreakAfterReturnType : None 9 | ... 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.vscode 2 | *.vs 3 | registry 4 | build 5 | __pycache__ -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Charles Giessen (cdgiessen@gmail.com) 2 | 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 4 | # (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 5 | # publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do 6 | # so, subject to the following conditions: 7 | 8 | # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 11 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 12 | # FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 13 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | 15 | cmake_minimum_required(VERSION 3.12 FATAL_ERROR) 16 | project(vulkan-simple-cpp CXX) 17 | 18 | option(VK_SIMPLE_CPP_GENERATE_SOURCE "Get dependencies necessary for generating the bindings" off) 19 | option(VK_SIMPLE_CPP_SAMPLES "Build samples for the bindings, will download glfw" off) 20 | option(VK_SIMPLE_CPP_TESTS "Build tests for the bindings, will download catch2" off) 21 | option(VK_SIMPLE_CPP_ENABLE_ADDRESS_SANITIZER "Enable Address Sanitizer. Mainly for developers only" off) 22 | 23 | if (VK_SIMPLE_CPP_TESTS) 24 | option(SET_COMPILE_TIME_TRACE "enable clang's -ftime-trace " OFF) 25 | endif(VK_SIMPLE_CPP_TESTS) 26 | 27 | if (VK_SIMPLE_CPP_GENERATE_SOURCE OR VK_SIMPLE_CPP_SAMPLES OR VK_SIMPLE_CPP_TESTS) 28 | find_package(PythonInterp 3 QUIET) 29 | 30 | include(FetchContent) 31 | FetchContent_Declare( 32 | vulkan_headers 33 | GIT_REPOSITORY https://github.com/KhronosGroup/Vulkan-Headers 34 | GIT_TAG v1.3.204 35 | ) 36 | FetchContent_GetProperties(vulkan-headers) 37 | if(NOT vulkan_headers_POPULATED) 38 | FetchContent_Populate(vulkan_headers) 39 | add_subdirectory(${vulkan_headers_SOURCE_DIR} ${vulkan_headers_BINARY_DIR}) 40 | endif() 41 | add_custom_target(copy_source ALL 42 | COMMAND ${CMAKE_COMMAND} -E copy ${vulkan_headers_SOURCE_DIR}/registry/vk.xml ${CMAKE_CURRENT_LIST_DIR}/registry/vk.xml 43 | COMMAND ${CMAKE_COMMAND} -E copy ${vulkan_headers_SOURCE_DIR}/include/vulkan/vk_platform.h ${CMAKE_CURRENT_LIST_DIR}/include/vulkan/vk_platform.h) 44 | add_custom_target(generate_source 45 | COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/generate.py 46 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}) 47 | add_dependencies(generate_source copy_source) 48 | 49 | endif() 50 | 51 | 52 | # Determine whether we're compiling with clang++ 53 | string(FIND "${CMAKE_CXX_COMPILER}" "clang++" VK_SIMPLE_CPP_COMPILER_CLANGPP) 54 | if(VK_SIMPLE_CPP_COMPILER_CLANGPP GREATER -1) 55 | set(VK_SIMPLE_CPP_COMPILER_CLANGPP 1) 56 | else() 57 | set(VK_SIMPLE_CPP_COMPILER_CLANGPP 0) 58 | endif() 59 | 60 | add_library(vk-simple-cpp-compiler-options INTERFACE) 61 | target_compile_options(vk-simple-cpp-compiler-options 62 | INTERFACE 63 | $<$,$,${VK_SIMPLE_CPP_COMPILER_CLANGPP}>: 64 | -Wall 65 | -Wextra 66 | -pedantic-errors 67 | -Wconversion 68 | -Wsign-conversion> 69 | $<$: 70 | /WX 71 | /W4> 72 | ) 73 | 74 | if (VK_SIMPLE_CPP_ENABLE_ADDRESS_SANITIZER) 75 | if (UNIX and not APPLE) 76 | target_compile_options(vk-simple-cpp-compiler-options INTERFACE -fsanitize=address) 77 | target_link_options(vk-simple-cpp-compiler-options INTERFACE -fsanitize=address) 78 | elseif(WIN32) 79 | target_compile_options(vk-simple-cpp-compiler-options INTERFACE /fsanitize=address) 80 | target_link_options(vk-simple-cpp-compiler-options INTERFACE /fsanitize=address) 81 | endif() 82 | endif() 83 | 84 | add_library(vk-simple-cpp-platform-defines INTERFACE) 85 | target_compile_options(vk-simple-cpp-platform-defines INTERFACE 86 | $<$:-DVK_USE_PLATFORM_WIN32_KHR> 87 | $<$:-DVK_USE_PLATFORM_ANDROID_KHR> 88 | $<$:-DVK_USE_PLATFORM_MACOS_MVK> 89 | $<$,$>>: 90 | $<$:-DVK_USE_PLATFORM_XCB_KHR> 91 | $<$:-DVK_USE_PLATFORM_XLIB_KHR> 92 | $<$:-DVK_USE_PLATFORM_WAYLAND_KHR>> 93 | ) 94 | 95 | add_library(vulkan-simple-cpp STATIC 96 | ${CMAKE_CURRENT_LIST_DIR}/include/vulkan/vulkan.h 97 | ${CMAKE_CURRENT_LIST_DIR}/include/vulkan/vulkan.cpp 98 | ${CMAKE_CURRENT_LIST_DIR}/include/vulkan/vulkan_string.h 99 | ${CMAKE_CURRENT_LIST_DIR}/include/vulkan/vulkan_string.cpp) 100 | target_include_directories(vulkan-simple-cpp BEFORE PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) 101 | target_include_directories(vulkan-simple-cpp PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include/vulkan) 102 | target_link_libraries(vulkan-simple-cpp PUBLIC vk-simple-cpp-compiler-options) 103 | target_compile_features(vulkan-simple-cpp PUBLIC cxx_std_14) 104 | set_target_properties(vulkan-simple-cpp PROPERTIES CXX_STANDARD 14) 105 | set_target_properties(vulkan-simple-cpp PROPERTIES LINKER_LANGUAGE CXX) 106 | 107 | if (NOT WIN32) 108 | target_link_libraries(vulkan-simple-cpp PUBLIC ${CMAKE_DL_LIBS}) 109 | endif() 110 | 111 | if (SET_COMPILE_TIME_TRACE) 112 | target_compile_options(vulkan-simple-cpp PUBLIC -ftime-trace) 113 | endif(SET_COMPILE_TIME_TRACE) 114 | 115 | if (VK_SIMPLE_CPP_SAMPLES) 116 | add_subdirectory(sample) 117 | endif(VK_SIMPLE_CPP_SAMPLES) 118 | 119 | if (VK_SIMPLE_CPP_TESTS) 120 | add_subdirectory(test) 121 | endif (VK_SIMPLE_CPP_TESTS) 122 | 123 | if (VK_SIMPLE_CPP_GENERATE_SOURCE OR VK_SIMPLE_CPP_SAMPLES OR VK_SIMPLE_CPP_TESTS) 124 | add_dependencies(vulkan-simple-cpp generate_source) 125 | endif() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vk-simple-cpp 2 | 3 | Takes the current C headers and adds a few quality of life improvements while staying faithful to the original C API. 4 | 5 | Improvements: 6 | 7 | * Enums and Bitfields use enum classes, makes it impossible to use the wrong enum. 8 | * sType parameters are initialized to their correct value. 9 | * Structs always initialize all values to zero (except sType). Prevents uninitialized memory bugs. 10 | * Add an API to automatically load function pointers with the following benefits: 11 | * Function pointers are known to be faster than using the exported Vulkan functions. 12 | * No compile time dependency on the Vulkan-Loader. It is loaded at runtime instead. 13 | * Automatically querying function pointers from extensions 14 | * Removes the need to use an external library such as [volk](https://github.com/zeux/volk) to accomplish this task 15 | 16 | Notes: 17 | 18 | * This aims to be a production ready solution - though currently lacks in test coverage 19 | * The goal of these bindings is to bridge the gap between the simplicity of the C API and the type safety of `vulkan.hpp`. 20 | * I am not planning on adding additional features, but am open to simple QoL suggestions. 21 | 22 | 23 | ## Getting started 24 | 25 | Since vk-simple-cpp loads function pointers, some special functions must be called in order to load the functions. 26 | 27 | ```c++ 28 | // Call this before calling any vulkan functions 29 | VkResult res = vkSimpleCppInitializeLoaderLibrary(); 30 | assert(res == VK_SUCCESS); 31 | 32 | // Create your instance 33 | vkSimplCppInitializeInstanceFunctions(instance); 34 | // Create your device 35 | vkSimpleCppInitializeDeviceFunctions(device); 36 | 37 | ... // rest of the renderer/application mainloop 38 | 39 | // shutdown 40 | vkSimpleCppCloseLoaderLibrary(); 41 | ``` 42 | 43 | 44 | To use vk-simple-cpp as a header-only library, define the following macro in one source file before including the vulkan headers. 45 | ```c++ 46 | #define VULKAN_CPP_IMPLEMENTATION 47 | #include "vulkan/vulkan.h" 48 | ``` -------------------------------------------------------------------------------- /codegen_text.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Charles Giessen (cdgiessen@gmail.com) 2 | 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 4 | # (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 5 | # publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do 6 | # so, subject to the following conditions: 7 | 8 | # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 11 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 12 | # FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 13 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | 15 | license_header = '''/* 16 | * Copyright 2021 Charles Giessen (cdgiessen@gmail.com) 17 | * 18 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 19 | * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 20 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 21 | * furnished to do so, subject to the following conditions: 22 | * 23 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 26 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 28 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | */ 30 | ''' 31 | 32 | vk_module_file_header = ''' 33 | // clang-format off 34 | #pragma once 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include "vk_platform.h" 46 | 47 | #if defined(VK_USE_PLATFORM_FUCHSIA) 48 | #include 49 | #endif 50 | 51 | #if defined(VK_USE_PLATFORM_WAYLAND_KHR) 52 | #include 53 | #endif 54 | 55 | #if defined(VK_USE_PLATFORM_XCB_KHR) 56 | #include 57 | #endif 58 | 59 | #if defined(VK_USE_PLATFORM_XLIB_KHR) 60 | #include 61 | #endif 62 | 63 | #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) 64 | #include 65 | #endif 66 | 67 | #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) 68 | #include 69 | #include 70 | #endif 71 | 72 | #if defined(VK_USE_PLATFORM_GGP) 73 | #include 74 | #endif 75 | 76 | // Compatability with compilers that don't support __has_feature 77 | #if !defined(__has_feature) 78 | #define __has_feature(x) 0 79 | #endif 80 | 81 | #if !defined(VK_MODULE_DISABLE_LEAK_SANITIZER_SUPPRESSION) && (__has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) ) 82 | #include 83 | #define VK_MODULE_LEAK_SANITIZER_SUPPRESSION_CODE __lsan::ScopedDisabler lsan_scope{}; 84 | #else 85 | #define VK_MODULE_LEAK_SANITIZER_SUPPRESSION_CODE 86 | #endif 87 | 88 | #if !defined(__has_feature) 89 | #undef __has_feature 90 | #endif 91 | 92 | #if !defined(VULKAN_CUSTOM_ASSERT) 93 | #include 94 | #define VULKAN_CUSTOM_ASSERT assert 95 | #endif 96 | 97 | namespace vk { 98 | constexpr uint32_t make_vk_version(uint32_t major, uint32_t minor, uint32_t patch) { 99 | return major << 22 | minor << 12 | patch; 100 | } 101 | 102 | #if !defined(VK_DEFINE_HANDLE) 103 | #define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; 104 | #endif 105 | 106 | #if !defined(VK_DEFINE_NON_DISPATCHABLE_HANDLE) 107 | #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) 108 | #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; 109 | #else 110 | #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; 111 | #endif 112 | #endif 113 | ''' 114 | 115 | bitmask_flags_macro = ''' 116 | #define DECLARE_ENUM_FLAG_OPERATORS(FLAG_TYPE, FLAG_BITS, BASE_TYPE) \\ 117 | \\ 118 | struct FLAG_TYPE { \\ 119 | BASE_TYPE flags = static_cast(0); \\ 120 | \\ 121 | constexpr FLAG_TYPE() noexcept = default; \\ 122 | constexpr FLAG_TYPE(BASE_TYPE in) noexcept: flags(in){ } \\ 123 | constexpr FLAG_TYPE(FLAG_BITS in) noexcept: flags(static_cast(in)){ } \\ 124 | constexpr bool operator==(FLAG_TYPE const& right) const { return flags == right.flags;}\\ 125 | constexpr bool operator!=(FLAG_TYPE const& right) const { return flags != right.flags;}\\ 126 | constexpr explicit operator BASE_TYPE() const { return flags;} \\ 127 | constexpr explicit operator bool() const noexcept { \\ 128 | return flags != 0; \\ 129 | } \\ 130 | }; \\ 131 | constexpr FLAG_TYPE operator|(FLAG_TYPE a, FLAG_TYPE b) noexcept { \\ 132 | return static_cast(a.flags | b.flags); \\ 133 | } \\ 134 | constexpr FLAG_TYPE operator&(FLAG_TYPE a, FLAG_TYPE b) noexcept { \\ 135 | return static_cast(a.flags & b.flags); \\ 136 | } \\ 137 | constexpr FLAG_TYPE operator^(FLAG_TYPE a, FLAG_TYPE b) noexcept { \\ 138 | return static_cast(a.flags ^ b.flags); \\ 139 | } \\ 140 | constexpr FLAG_TYPE operator~(FLAG_TYPE a) noexcept { \\ 141 | return static_cast(~a.flags); \\ 142 | } \\ 143 | constexpr FLAG_TYPE& operator|=(FLAG_TYPE& a, FLAG_TYPE b) noexcept { \\ 144 | a.flags = (a.flags | b.flags); return a; \\ 145 | } \\ 146 | constexpr FLAG_TYPE& operator&=(FLAG_TYPE& a, FLAG_TYPE b) noexcept { \\ 147 | a.flags = (a.flags & b.flags); return a; \\ 148 | } \\ 149 | constexpr FLAG_TYPE operator^=(FLAG_TYPE& a, FLAG_TYPE b) noexcept { \\ 150 | a.flags = (a.flags ^ b.flags); return a; \\ 151 | } \\ 152 | constexpr FLAG_TYPE operator|(FLAG_BITS a, FLAG_BITS b) noexcept { \\ 153 | return static_cast(static_cast(a) | static_cast(b)); \\ 154 | } \\ 155 | constexpr FLAG_TYPE operator&(FLAG_BITS a, FLAG_BITS b) noexcept { \\ 156 | return static_cast(static_cast(a) & static_cast(b)); \\ 157 | } \\ 158 | constexpr FLAG_TYPE operator~(FLAG_BITS key) noexcept { \\ 159 | return static_cast(~static_cast(key)); \\ 160 | } \\ 161 | constexpr FLAG_TYPE operator^(FLAG_BITS a, FLAG_BITS b) noexcept { \\ 162 | return static_cast(static_cast(a) ^ static_cast(b)); \\ 163 | } \\ 164 | ''' 165 | 166 | cpp_header_guard = ''' 167 | // clang-format off 168 | #ifndef SIMPLE_VULKAN_H_ 169 | #ifdef VULKAN_H_ 170 | #error "Must include these bindings first, not official C vulkan headers (vulkan.h)" 171 | #endif 172 | #endif 173 | #ifndef VULKAN_H_ 174 | #define VULKAN_H_ 1 175 | #define SIMPLE_VULKAN_H_ 1 176 | 177 | #define VK_VERSION_1_0 1 178 | #define VK_VERSION_1_1 1 179 | #define VK_VERSION_1_2 1 180 | #include 181 | #include "vk_platform.h" 182 | ''' 183 | 184 | cpp_platform_headers = ''' 185 | #if defined(VK_USE_PLATFORM_FUCHSIA) 186 | #include 187 | #endif 188 | 189 | #if defined(VK_USE_PLATFORM_WAYLAND_KHR) 190 | #include 191 | #endif 192 | 193 | #if defined(VK_USE_PLATFORM_XCB_KHR) 194 | #include 195 | #endif 196 | 197 | #if defined(VK_USE_PLATFORM_XLIB_KHR) 198 | #include 199 | #endif 200 | 201 | #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) 202 | #include 203 | #endif 204 | 205 | #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) 206 | #include 207 | #include 208 | #endif 209 | 210 | #if defined(VK_USE_PLATFORM_GGP) 211 | #include 212 | #endif 213 | ''' 214 | 215 | cpp_footer = ''' 216 | // This function finds the Vulkan-Loader (vulkan-1.dll, libvulkan.so, libvulkan.dylib, etc) on a system, loads it, 217 | // and loads the follwing functions: 218 | // * vkGetInstanceProcAddr 219 | // * vkCreateInstance 220 | // * vkEnumerateInstanceExtensionProperties 221 | // * vkEnumerateInstanceLayerProperties 222 | // * vkEnumerateInstanceVersion 223 | // 224 | // Note: 225 | // This function must be called before all other vulkan calls! 226 | // 227 | // Return Codes: 228 | // VkResult::Success -- Successful initialization & loading of functions 229 | // VkResult::ErrorInitializationFailed -- failure [unable to find Vulkan-Loader] 230 | // 231 | // Optional Parameter: 232 | // PFN_vkGetInstanceProcAddr pfn_vkGetInstanceProcAddr = VK_NULL_HANDLE 233 | VkResult vkSimpleCppInitializeLoaderLibrary(PFN_vkGetInstanceProcAddr pfn_vkGetInstanceProcAddr = VK_NULL_HANDLE); 234 | 235 | // Close the Vulkan-Loader and assigns VK_NULL_HANDLE to vkGetInstanceProcAddr 236 | // 237 | // Note: 238 | // After this function is called, no further vulkan calls can be made, except for `vkSimpleCppInitializeLoaderLibrary()` 239 | void vkSimpleCppCloseLoaderLibrary(); 240 | 241 | // Initialize the instance and physical device functions into the global function pointers 242 | // (all functions which take a VkInstance or VkPhysicalDevice as the first parameter) 243 | // 244 | // Note: This must only be called after the application has created a valid VkInstance with vkCreateInstance 245 | // 246 | // Parameter: 247 | // VkInstance instance 248 | // The VkInstance handle which the application has created. Must not be VK_NULL_HANDLE 249 | void vkSimpleCppInitializeInstanceFunctions(VkInstance instance); 250 | 251 | // Loads device functions into the global function pointers 252 | // 253 | // Notes: 254 | // * This function must not be used for any application which creates multiple VkDevices. 255 | // Instead, the application should use a VkDeviceDispatchTable per device created. 256 | // * This must only be called after the application has created a valid VkDevice with vkCreateDevice 257 | // 258 | // Parameter: 259 | // VkDevice device 260 | // The VkDevice handle which the application has created. Must not be VK_NULL_HANDLE 261 | void vkSimpleCppInitializeDeviceFunctions(VkDevice device); 262 | 263 | // Loads device functions into the provided VkDeviceDispatchTable 264 | // 265 | // Notes: 266 | // * 267 | // * This must only be called after the application has created a valid VkDevice with vkCreateDevice 268 | // 269 | // Parameters: 270 | // * VkDevice device 271 | // The VkDevice handle which the application has created. Must not be VK_NULL_HANDLE 272 | // * VkDeviceDispatchTable& table 273 | // The table in which holds all loaded device function pointers. 274 | void vkSimpleCppInitializeDeviceDispatchTable(VkDevice device, VkDeviceDispatchTable& table); 275 | 276 | #ifdef __cplusplus 277 | } // extern "C" 278 | #endif 279 | 280 | #if defined(VULKAN_CPP_IMPLEMENTATION) 281 | #include "vulkan.cpp" 282 | #endif //defined(VULKAN_CPP_IMPLEMENTATION) 283 | 284 | #endif // VULKAN_H_ 285 | // clang-format on 286 | ''' 287 | 288 | cpp_definition = ''' 289 | 290 | #if defined(_WIN32) 291 | using HINSTANCE = struct HINSTANCE__ *; 292 | #if defined( _WIN64 ) 293 | using FARPROC = int64_t( __stdcall * )(); 294 | #else 295 | using FARPROC = typedef int( __stdcall * )(); 296 | #endif 297 | extern "C" __declspec( dllimport ) HINSTANCE __stdcall LoadLibraryA( char const * lpLibFileName ); 298 | extern "C" __declspec( dllimport ) int __stdcall FreeLibrary( HINSTANCE hLibModule ); 299 | extern "C" __declspec( dllimport ) FARPROC __stdcall GetProcAddress( HINSTANCE hModule, const char * lpProcName ); 300 | #elif defined(__linux__) || defined(__APPLE__) 301 | #include 302 | #endif 303 | 304 | #if defined(__linux__) || defined(__APPLE__) 305 | void *library = nullptr; 306 | #elif defined(_WIN32) 307 | ::HINSTANCE library = nullptr; 308 | #endif 309 | 310 | void* LibraryLoadFunction(const char* name) { 311 | #if defined(__linux__) || defined(__APPLE__) 312 | return dlsym(library, name); 313 | #elif defined(_WIN32) 314 | return ::GetProcAddress(library, name); 315 | #endif 316 | } 317 | void LoadGetInstanceProcAddr(){ 318 | vkGetInstanceProcAddr = reinterpret_cast(LibraryLoadFunction("vkGetInstanceProcAddr")); 319 | } 320 | void LoadGlobalFunctions() { 321 | if (vkGetInstanceProcAddr == VK_NULL_HANDLE) return; 322 | vkCreateInstance = reinterpret_cast(vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateInstance")); 323 | vkEnumerateInstanceExtensionProperties = reinterpret_cast(vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties")); 324 | vkEnumerateInstanceLayerProperties = reinterpret_cast(vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceLayerProperties")); 325 | vkEnumerateInstanceVersion = reinterpret_cast(vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceVersion")); 326 | } 327 | 328 | VkResult vkSimpleCppInitializeLoaderLibrary(PFN_vkGetInstanceProcAddr pfn_vkGetInstanceProcAddr){ 329 | if(pfn_vkGetInstanceProcAddr != VK_NULL_HANDLE){ 330 | vkGetInstanceProcAddr = pfn_vkGetInstanceProcAddr; 331 | LoadGlobalFunctions(); 332 | return VkResult::Success; 333 | } 334 | 335 | #if defined(__linux__) 336 | library = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL); 337 | if (!library) library = dlopen("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL); 338 | #elif defined(__APPLE__) 339 | library = dlopen("libvulkan.dylib", RTLD_NOW | RTLD_LOCAL); 340 | #elif defined(_WIN32) 341 | library = ::LoadLibraryA("vulkan-1.dll"); 342 | #endif 343 | if (library == 0) return VkResult::ErrorInitializationFailed; 344 | LoadGetInstanceProcAddr(); 345 | LoadGlobalFunctions(); 346 | if (vkGetInstanceProcAddr == nullptr) return VkResult::ErrorInitializationFailed; 347 | return VkResult::Success; 348 | } 349 | 350 | void vkSimpleCppCloseLoaderLibrary(){ 351 | if (library != nullptr) { 352 | #if defined(__linux__) || defined(__APPLE__) 353 | dlclose(library); 354 | #elif defined(_WIN32) 355 | ::FreeLibrary(library); 356 | #endif 357 | library = 0; 358 | vkGetInstanceProcAddr = VK_NULL_HANDLE; 359 | } 360 | } 361 | ''' 362 | 363 | begin_extern_c = ''' 364 | #ifdef __cplusplus 365 | extern "C" { 366 | #endif 367 | ''' 368 | 369 | end_extern_c = ''' 370 | #ifdef __cplusplus 371 | } // extern "C" 372 | #endif 373 | ''' -------------------------------------------------------------------------------- /generate.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Charles Giessen (cdgiessen@gmail.com) 2 | 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 4 | # (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 5 | # publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do 6 | # so, subject to the following conditions: 7 | 8 | # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 11 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 12 | # FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 13 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | 15 | import xml.etree.ElementTree 16 | import re 17 | from codegen_text import * 18 | 19 | #globals that are initialized near beginning of xml parsing 20 | vendor_abbreviations = [] 21 | base_type_implicit_conversions = {} 22 | api_constants = {} 23 | 24 | base_type_default_values = { 25 | 'void*': 'nullptr', 26 | 'char': '0', 27 | 'uint8_t': '0', 28 | 'uint16_t': '0', 29 | 'uint32_t': '0', 30 | 'uint64_t': '0', 31 | 'int32_t': '0', 32 | 'int64_t': '0', 33 | 'int': '0', 34 | 'float': '0.f', 35 | 'double': '0.0', 36 | 'size_t': '0' 37 | } 38 | 39 | def MorphVkEnumName(name, enum_name_len): 40 | n_part = name.title().split('_')[enum_name_len:] 41 | if n_part[-1] == "Bit": 42 | n_part = n_part[:-1] 43 | if n_part[-1].upper() in vendor_abbreviations: 44 | n_part[-1] = n_part[-1].upper() 45 | out = ''.join(n_part) 46 | if out[0].isnumeric(): 47 | out = 'e' + out 48 | return out 49 | 50 | def PrintConsecutivePlatforms(file, in_list, function_name, *args, **kwargs): 51 | prev_platform = None 52 | for item in in_list: 53 | if getattr(item, 'platform', None) is not None: 54 | if prev_platform != item.platform: 55 | if prev_platform is not None: 56 | file.write(f'#endif // defined({prev_platform})\n') 57 | if item.platform is not None: 58 | file.write(f'#if defined({item.platform})\n') 59 | prev_platform = item.platform 60 | else: 61 | if prev_platform is not None: 62 | file.write(f'#endif // defined({prev_platform})\n') 63 | prev_platform = None 64 | getattr(item, function_name)(file, *args, **kwargs) 65 | if prev_platform is not None: 66 | file.write(f'#endif // defined({prev_platform})\n') 67 | 68 | def TrimVkFromType(in_string): 69 | return in_string[2:] if in_string[:2] == 'Vk' or in_string[:2] == 'vk' else in_string 70 | 71 | def TrimVkFromPFN(in_string): 72 | return f'PFN_{in_string[6:]}' if in_string[:6] == 'PFN_vk' else in_string 73 | 74 | def TrimVkFromAll(in_string): 75 | return TrimVkFromType(TrimVkFromPFN(in_string)) 76 | 77 | class PlatformRequires: 78 | def __init__(self, node): 79 | self.name = node.get('name') 80 | self.requires = node.get('requires') 81 | 82 | 83 | def platform_check(type_to_check, platform, extension_type_list): 84 | if type(type_to_check) in [Bitmask, EmptyBitmask]: 85 | if type_to_check.name in extension_type_list or type_to_check.flags_name in extension_type_list: 86 | type_to_check.platform = platform 87 | 88 | if type_to_check.name in extension_type_list: 89 | type_to_check.platform = platform 90 | 91 | class ApiConstant: 92 | def __init__(self, node): 93 | self.name = node.get('name') 94 | self.value = node.get('value') 95 | self.alias = node.get('alias') 96 | self.type = node.get('type') if node.get('type') is not None else 'auto' 97 | 98 | def print(self, file): 99 | if self.alias is not None: 100 | file.write(f'constexpr {self.type} {self.name} = {self.alias};\n') 101 | elif self.value is not None: 102 | file.write(f'constexpr {self.type} {self.name} = {self.value};\n') 103 | 104 | class BaseType: 105 | def __init__(self, node): 106 | self.name = node.find('name').text 107 | self.type = None 108 | 109 | raw_xml_text = ' '.join(node.itertext()) 110 | type_list = raw_xml_text.split() 111 | if type_list[0] is not None: 112 | if type_list[0] == 'typedef': 113 | self.type = node.find('type').text 114 | if self.type == 'void': 115 | self.type = 'void*' 116 | self.default_value = 'nullptr' 117 | else: 118 | self.default_value = base_type_default_values[self.type] 119 | if type_list[0] == 'struct': 120 | pass 121 | 122 | def print(self, file): 123 | if self.type is not None: 124 | file.write(f'using {self.name} = {self.type};\n') 125 | 126 | class MacroDefine: 127 | def __init__(self, node): 128 | self.should_print = True 129 | self.name = node.find("name") 130 | self.text = ''.join(node.itertext()) 131 | 132 | 133 | class Enum: 134 | def __init__(self, node): 135 | self.name = node.get('name') 136 | self.underlying_type = 'uint32_t' # for ABI 137 | self.values = {} 138 | self.platform = None 139 | self.alias = node.get('alias') 140 | if self.alias is not None: 141 | return 142 | 143 | self.enum_name_len = len(re.findall('[A-Z][^A-Z]+', self.name)) 144 | if self.name == 'VkResult': 145 | self.enum_name_len = 1 146 | self.underlying_type = 'int32_t' 147 | 148 | for elem in node: 149 | if elem.get('name') is not None and elem.get('value') is not None: 150 | self.values[elem.get('name')] = elem.get('value') 151 | 152 | def fill(self, enum_ext_list): 153 | for ext_enum in enum_ext_list: 154 | self.values[ext_enum.name] = ext_enum.value 155 | 156 | def print(self, file): 157 | if self.alias is not None: 158 | file.write(f'using {self.name} = {self.alias};\n') 159 | else: 160 | file.write(f"enum class {self.name} : {self.underlying_type} {{\n") 161 | for name, value in self.values.items(): 162 | file.write(f' {MorphVkEnumName(name, self.enum_name_len)} = {str(value)},\n') 163 | file.write('};\n') 164 | for name, value in self.values.items(): 165 | file.write(f'const {self.name} {name} = {self.name}::{MorphVkEnumName(name, self.enum_name_len)};\n') 166 | 167 | def print_string(self, file): 168 | if self.alias is not None: 169 | return 170 | if len(self.values) == 0: 171 | file.write(f' const char * to_string([[maybe_unused]] {self.name[2:]} val) {{ return "UNKNOWN"; }}\n') 172 | return 173 | file.write(f'const char * to_string({self.name[2:]} val) {{\n') 174 | file.write(f' switch(val) {{\n') 175 | for name in self.values.keys(): 176 | modified_name = MorphVkEnumName(name, self.enum_name_len) 177 | file.write(f' case({self.name[2:]}::{modified_name}): return \"{modified_name}\";\n') 178 | file.write(' default: return "UNKNOWN";\n }\n}\n') 179 | 180 | def print_string_forward_def(self, file): 181 | if self.alias is None: 182 | file.write(f'const char * to_string({self.name} val);\n') 183 | 184 | def print_string_impl(self, file): 185 | if self.alias is None: 186 | if len(self.values) == 0: 187 | file.write(f'const char * to_string({self.name} val) {{ UNUSED_VARIABLE(val); return "UNKNOWN"; }}\n') 188 | return 189 | file.write(f'const char * to_string({self.name} val) {{\n') 190 | file.write(f' switch(val) {{\n') 191 | for name in self.values.keys(): 192 | modified_name = MorphVkEnumName(name, self.enum_name_len) 193 | file.write(f' case({self.name}::{modified_name}): return \"{modified_name}\";\n') 194 | file.write(' default: return "UNKNOWN";\n }\n}\n') 195 | 196 | def RepresentsIntOrHex(s): 197 | try: 198 | int(s) 199 | int(s, 16) 200 | return True 201 | except ValueError: 202 | return False 203 | 204 | class Bitmask: 205 | def __init__(self, node): 206 | self.node = node 207 | self.name = node.get('name') 208 | self.flags_name = self.name.replace('Bits', 's') 209 | self.underlying_type = 'uint64_t' if node.get('bitwidth') is not None else 'uint32_t' 210 | self.values = {} 211 | self.bitmask_name_len = len(re.findall('[A-Z]+[^A-Z]*', self.name)) - 2 212 | if self.name[-4:] != "Bits": #ie an extension bitmask 213 | self.bitmask_name_len = self.bitmask_name_len - 1 214 | 215 | self.alias = node.get('alias') 216 | self.platform = None 217 | 218 | for elem in node: 219 | value = elem.get('value') 220 | if value is None and elem.get('bitpos') is not None: 221 | value = str(1 << int(elem.get('bitpos'))) 222 | elif elem.get('alias') is not None: 223 | if elem.get('name') == "VK_STENCIL_FRONT_AND_BACK": 224 | continue #ugly special case 225 | value = elem.get("alias") 226 | self.values[elem.get('name')] = value 227 | 228 | def fill(self, bitmask_ext_dict): 229 | for ext_bit in bitmask_ext_dict: 230 | self.values[ext_bit.name] = str(ext_bit.bitpos) 231 | 232 | 233 | def print(self, file): 234 | if self.alias is not None: 235 | file.write(f'using {self.name} = {self.alias};\n') 236 | else: 237 | file.write(f'enum class {self.name}: {self.underlying_type} {{\n') 238 | for name, bitpos in self.values.items(): 239 | file.write(f' {MorphVkEnumName(name, self.bitmask_name_len)} = ') 240 | if all(c.isnumeric() for c in bitpos) or '0x' in bitpos : 241 | file.write(f'{bitpos},\n') 242 | else: 243 | file.write(f'{MorphVkEnumName(bitpos, self.bitmask_name_len)},\n') 244 | file.write('};\n') 245 | for name in self.values.keys(): 246 | file.write(f'const {self.name} {name} = {self.name}::{MorphVkEnumName(name, self.bitmask_name_len)};\n') 247 | 248 | def print_string(self, file): 249 | if self.alias is None: 250 | if len(self.values) == 0: 251 | file.write(f'const char * to_string([[maybe_unused]] {self.name[2:]} val) {{ return "UNKNOWN"; }}\n') 252 | file.write(f'std::string to_string([[maybe_unused]] {self.flags_name[2:]} flag){{ return "UNKNOWN"; }}\n') 253 | return 254 | file.write(f'const char * to_string({self.name[2:]} val) {{\n') 255 | file.write(' switch(val) {\n') 256 | already_printed_bits = set() 257 | for name, bitpos in self.values.items(): 258 | if bitpos in already_printed_bits: 259 | continue 260 | if not RepresentsIntOrHex(bitpos): 261 | continue 262 | modified_name = MorphVkEnumName(name, self.bitmask_name_len) 263 | file.write(f' case({self.name[2:]}::{modified_name}): return \"{modified_name}\";\n') 264 | already_printed_bits.add(bitpos) 265 | 266 | file.write(' default: return "UNKNOWN";\n }\n}\n') 267 | file.write(f'std::string to_string({self.flags_name[2:]} flag){{\n') 268 | file.write(f' if (flag.flags == 0) return \"None\";\n') 269 | file.write(f' std::string out;\n') 270 | for name, bitpos in self.values.items(): 271 | if not RepresentsIntOrHex(bitpos): 272 | continue 273 | modified_name = MorphVkEnumName(name, self.bitmask_name_len) 274 | file.write(f' if (flag & {self.name[2:]}::{modified_name}) out += \"{modified_name} | \";\n') 275 | 276 | file.write(f' return out.substr(0, out.size() - 3);\n}}\n') 277 | 278 | def print_string_forward_def(self, file): 279 | if self.alias is None: 280 | file.write(f'const char * to_string({self.name} val);\n') 281 | file.write(f'std::string to_string({self.flags_name} flag);\n') 282 | 283 | 284 | def print_string_impl(self, file): 285 | if self.alias is None: 286 | if len(self.values) == 0: 287 | file.write(f'const char * to_string({self.name} val) {{ UNUSED_VARIABLE(val); return "UNKNOWN"; }}\n') 288 | file.write(f'std::string to_string({self.flags_name} flag){{ UNUSED_VARIABLE(flag); return "UNKNOWN"; }}\n') 289 | return 290 | file.write(f'const char * to_string({self.name} val) {{\n') 291 | file.write(' switch(val) {\n') 292 | already_printed_bits = set() 293 | for name, bitpos in self.values.items(): 294 | if bitpos in already_printed_bits: 295 | continue 296 | if not RepresentsIntOrHex(bitpos): 297 | continue 298 | modified_name = MorphVkEnumName(name, self.bitmask_name_len) 299 | file.write(f' case({self.name}::{modified_name}): return \"{modified_name}\";\n') 300 | already_printed_bits.add(bitpos) 301 | 302 | file.write(' default: return "UNKNOWN";\n }\n}\n') 303 | file.write(f'std::string to_string({self.flags_name} flag){{\n') 304 | file.write(f' if (flag.flags == 0) return \"None\";\n') 305 | file.write(f' std::string out;\n') 306 | for name, bitpos in self.values.items(): 307 | if not RepresentsIntOrHex(bitpos): 308 | continue 309 | modified_name = MorphVkEnumName(name, self.bitmask_name_len) 310 | file.write(f' if (flag & {self.name}::{modified_name}) out += \"{modified_name} | \";\n') 311 | file.write(f' return out.substr(0, out.size() - 3);\n}}\n') 312 | 313 | class EmptyBitmask: 314 | def __init__(self, name): 315 | self.name = name 316 | self.flags_name = name.replace('Bits', 's') 317 | self.underlying_type = 'uint32_t' 318 | self.platform = None 319 | 320 | def fill(self, bitmask_ext_dict): 321 | pass 322 | 323 | 324 | def print(self, file): 325 | file.write(f'enum class {self.name}: {self.underlying_type} {{ }};\n') 326 | 327 | def print_string(self, file): 328 | file.write(f'const char * to_string([[maybe_unused]] {self.name[2:]} val) {{ return "Unknown"; }} \n') 329 | file.write(f'std::string to_string({self.flags_name[2:]} flag){{\n') 330 | file.write(f' if (flag.flags == 0) return \"None\";\n') 331 | file.write(f' return "Unknown";\n}}\n') 332 | 333 | def print_string_forward_def(self, file): 334 | pass 335 | 336 | def print_string_impl(self, file): 337 | pass 338 | 339 | class Flags: 340 | def __init__(self, node): 341 | if node.find('name') is not None: 342 | self.name = node.find('name').text 343 | self.alias = None 344 | self.underlying_type = 'uint64_t' if node.find('type').text == 'VkFlags64' else 'uint32_t' 345 | else: 346 | self.name = node.get('name') 347 | self.alias = node.get('alias') 348 | self.underlying_type = None 349 | 350 | self.flag_bits_name = self.name.replace('Flags', 'FlagBits') 351 | self.requires = node.get('requires') 352 | self.need_empty = False 353 | if self.alias is None and self.requires is None: 354 | self.need_empty = True 355 | self.platform = None 356 | 357 | def print(self, file): 358 | if self.alias is None: 359 | file.write(f'DECLARE_ENUM_FLAG_OPERATORS({self.name}, {self.flag_bits_name}, {self.underlying_type})\n') 360 | else: 361 | file.write(f'using {self.name} = {self.alias};\n') 362 | 363 | class Handle: 364 | def __init__(self, node): 365 | self.name = None 366 | if node.find('name') is not None: 367 | self.name = node.find('name').text 368 | self.dispatchable = node.find('type').text == 'VK_DEFINE_HANDLE' #else is a nondispatchable handle 369 | self.dispatchable_text = node.find('type').text 370 | self.parent = node.get('parent') 371 | self.alias = node.get('alias') 372 | if self.alias is not None: 373 | self.name = node.get('name') 374 | self.platform = None 375 | 376 | def print_vk_handle(self, file): 377 | if self.alias is None: 378 | file.write(f'{self.dispatchable_text}({self.name})\n') 379 | else: 380 | file.write(f'using {self.name} = {self.alias};\n') 381 | 382 | 383 | class Variable: 384 | def __init__(self, node, handles, default_values): 385 | self.name = node.find('name').text 386 | self.sType_value = node.get('values') 387 | 388 | # attributes 389 | self.optional = node.get('optional') 390 | self.len_attrib = node.get('len') 391 | 392 | self.alt_len = node.get('altlen') 393 | self.length_ref = None 394 | 395 | # type characteristics 396 | self.is_const = False 397 | self.const = '' 398 | self.pointer_type = 'none' 399 | self.array_lengths = [] 400 | self.default_value = None 401 | self.is_equatable = True 402 | self.bitfield = None 403 | 404 | self.base_type = node.find('type').text 405 | self.base_type_modified = TrimVkFromAll(self.base_type) 406 | # special case cause of bitfields 407 | if self.base_type == 'VkGeometryInstanceFlagsKHR': 408 | self.base_type = 'uint32_t' 409 | self.base_type_modified = 'uint32_t' 410 | 411 | if node.find('comment') is not None: 412 | node.remove(node.find('comment')) 413 | 414 | self.raw_xml_text = ' '.join(node.itertext()) 415 | type_list = self.raw_xml_text.split() 416 | 417 | # type parsing 418 | cur = 0 419 | if type_list[cur] == 'const': 420 | self.is_const = True 421 | self.const = 'const' 422 | cur += 1 423 | if type_list[cur] == 'struct': 424 | cur += 1 425 | if type_list[cur] == self.base_type: 426 | cur += 1 427 | if type_list[cur] == '*': 428 | self.pointer_type = 'single' 429 | cur += 1 430 | if type_list[cur] == '**': 431 | self.pointer_type = 'double' 432 | cur += 1 433 | if type_list[cur] == 'const*': 434 | self.pointer_type = 'const double' 435 | cur += 1 436 | if type_list[cur] == self.name: 437 | cur += 1 438 | 439 | while len(type_list) > cur: 440 | if type_list[cur] == '[': 441 | cur += 1 442 | arr_len = type_list[cur] 443 | cur += 2 444 | elif len(type_list[cur]) > 0 and type_list[cur][0] == '[': 445 | next_bracket = 1 446 | for t in type_list[cur][1:]: 447 | if t == ']': 448 | break 449 | next_bracket += 1 450 | arr_len = type_list[cur][1:next_bracket] 451 | type_list[cur] = type_list[cur][next_bracket + 1:] 452 | else: 453 | break 454 | if arr_len in api_constants: 455 | arr_len = arr_len[3:] 456 | self.array_lengths.append(arr_len) 457 | for t in type_list: 458 | if len(t) > 0 and t[0] == ':': 459 | self.bitfield = t[1:] 460 | if self.base_type in default_values: 461 | self.default_value = default_values[self.base_type] 462 | if self.name == 'sType' and self.sType_value is not None: 463 | self.default_value = f'StructureType::{MorphVkEnumName(self.sType_value, 3)}' 464 | if self.name == 'sType' and self.sType_value is not None: 465 | self.base_default_value = f'VkStructureType::{MorphVkEnumName(self.sType_value, 3)}' 466 | 467 | self.is_handle = self.base_type in handles 468 | 469 | def is_ptr(self): 470 | return self.pointer_type != 'none' 471 | 472 | def get_raw_xml(self): 473 | return self.raw_xml_text 474 | 475 | 476 | def MakeBuilderName(in_str): 477 | return in_str[0:1].capitalize() + in_str[1:] 478 | 479 | def MakeBuilderFunctionNames(in_str): 480 | if in_str.find('ppEnabled') != -1: 481 | return in_str[2:] 482 | if in_str[0] == 'p' and in_str[1].isupper(): 483 | return in_str[1:] 484 | else: 485 | return in_str[0:1].capitalize() + in_str[1:] 486 | 487 | # Contains both structs and unions 488 | class Structure: 489 | def __init__(self, node, handles, default_values): 490 | self.name = node.get('name') 491 | self.alias = node.get('alias') 492 | self.category = node.get('category') # struct or union 493 | self.members = [] 494 | self.platform = None 495 | self.returnedonly = node.get('returnedonly') is not None 496 | self.structextends = node.get('structextends') 497 | 498 | for member in node.findall('member'): 499 | self.members.append(Variable(member, handles, default_values)) 500 | 501 | 502 | def print(self, file): 503 | if self.alias is not None: 504 | file.write(f'using {self.name} = {self.alias};\n') 505 | else: 506 | should_init = self.category == 'struct' 507 | file.write(f'{self.category} {self.name} {{\n') 508 | for member in self.members: 509 | if self.name in['VkAccelerationStructureInstanceKHR', 'VkAccelerationStructureMatrixMotionInstanceNV','VkAccelerationStructureSRTMotionInstanceNV']: 510 | file.write(f' {member.get_raw_xml().replace("VkGeometryInstanceFlagsKHR", "uint32_t")}') 511 | else: 512 | file.write(f' {member.get_raw_xml()}') 513 | if member.name == 'sType' and member.sType_value is not None: 514 | file.write(f' = {member.base_default_value};\n') 515 | elif should_init and member.bitfield is None: 516 | file.write('{};\n') 517 | else: 518 | file.write(';\n') 519 | file.write('};\n') 520 | 521 | class Function: 522 | def __init__(self, node, handles, dispatchable_handles, default_values): 523 | self.success_codes = node.get('successcodes', default='').split(',') 524 | self.error_codes = node.get('errorcodes', default='').split(',') 525 | 526 | self.platform = None 527 | proto = node.find('proto') 528 | self.name = proto.find('name').text if proto is not None else node.get('name') 529 | self.alias = node.get('alias') if proto is None else None 530 | self.return_type = proto.find('type').text if proto is not None else None 531 | 532 | self.pfn_name = f'pfn_{self.name[2:]}' 533 | self.pfn_type = f'PFN_{self.name[2:]}' 534 | 535 | self.parameters = [] 536 | for param in node.findall('param'): 537 | self.parameters.append( Variable(param, handles, default_values)) 538 | self.dispatch_type = None 539 | if len(self.parameters) > 0: 540 | self.free_function = self.parameters[0].base_type not in dispatchable_handles 541 | 542 | if self.name == 'vkGetInstanceProcAddr' or self.free_function: 543 | self.dispatch_type = 'global' 544 | elif self.name == 'vkGetDeviceProcAddr' or self.parameters[0].base_type in ['VkInstance', 'VkPhysicalDevice']: 545 | self.dispatch_type = 'instance' 546 | else: 547 | self.dispatch_type = 'device' 548 | 549 | self.dispatch_handle = None 550 | if len(self.parameters) > 0 and self.parameters[0].base_type in dispatchable_handles: 551 | self.dispatch_handle = self.parameters[0].base_type 552 | 553 | def print_pfn_variable_decl(self, file): 554 | file.write(f' detail::{self.pfn_type} {self.pfn_name} = nullptr;\n') 555 | 556 | def print_get_pfn_statement(self, file, gpa_name, gpa_val): 557 | file.write(f' pfn_{self.name[2:]} = ') 558 | file.write(f'reinterpret_cast({gpa_name}({gpa_val},\"{self.name}\"));\n') 559 | 560 | def print_extern_decl(self, file, parent_dispatch_type): 561 | if parent_dispatch_type == 'instance' and self.name == 'vkGetInstanceProcAddr': 562 | return #halt duplicate vkGetInstanceProcAddr's being defined 563 | file.write(f'extern PFN_{self.name} {self.name};\n') 564 | 565 | def print_function_def(self, file, parent_dispatch_type): 566 | if parent_dispatch_type == 'instance' and self.name == 'vkGetInstanceProcAddr': 567 | return #halt duplicate vkGetInstanceProcAddr's being defined 568 | file.write(f'PFN_{self.name} {self.name};\n') 569 | 570 | def print_init_global_functions(self, file, dispatch_name): 571 | file.write(f' {self.name} = reinterpret_cast(vkGet{dispatch_name}ProcAddr({dispatch_name}, \"{self.name}\"));\n') 572 | 573 | def print_init_dispatch_table(self, file, dispatch_name): 574 | file.write(f' table.{self.name} = reinterpret_cast(vkGet{dispatch_name}ProcAddr({dispatch_name}, \"{self.name}\"));\n') 575 | 576 | def print_pfn_func_decl(self, file): 577 | if self.alias is not None: 578 | file.write(f'using PFN_{self.name} = PFN_{self.alias};\n') 579 | return 580 | file.write(f'using PFN_{self.name} = {self.return_type} (*) (') 581 | for param in self.parameters: 582 | if param != self.parameters[0]: 583 | file.write(', ') 584 | file.write(f'{param.get_raw_xml()}') 585 | file.write(");\n") 586 | 587 | def print_function(self, file, dispatch_handle = None, dispatch_handle_name = None, pfn_source=None): 588 | if self.alias is not None: 589 | file.write(f'const auto {self.name[2:]} = {self.alias[2:]};\n') 590 | return 591 | self.inner_print_function(file, dispatch_handle, dispatch_handle_name, pfn_source) 592 | 593 | class FuncPointer: 594 | def __init__(self, node): 595 | self.name = node.find('name').text 596 | self.raw_text = ' '.join(node.itertext()) 597 | self.text = '' 598 | for t in node.itertext(): 599 | t.replace('VkBool32', 'Bool32') 600 | self.text += TrimVkFromAll(t.replace('VkBool32', 'Bool32')) 601 | 602 | def print(self, file): 603 | file.write(self.raw_text + '\n') 604 | 605 | class ExtEnum: 606 | def __init__(self, name, value): 607 | self.name = name 608 | self.value = value 609 | 610 | class ExtBitmask: 611 | def __init__(self, name, bitpos): 612 | self.name = name 613 | self.bitpos = bitpos 614 | 615 | def EnumExtValue(ext_num, offset, direction): 616 | enum_value = 1000000000 + 1000 * (ext_num - 1) + offset 617 | enum_value = -enum_value if direction == '-' else enum_value 618 | return enum_value 619 | 620 | def AppendToDictOfLists(dict, key, val): 621 | if key not in dict: 622 | dict[key] = [] 623 | dict[key].append(val) 624 | 625 | class Requires: 626 | def __init__(self, node, ext_num = None): 627 | self.feature = node.get('feature') 628 | self.extension = node.get('extension') 629 | self.enum_dict = {} 630 | self.bitmask_dict = {} 631 | self.types = set() 632 | self.commands = set() 633 | self.functions = [] 634 | 635 | for e_type in node.findall('type'): 636 | self.types.add(e_type.get('name')) 637 | for command in node.findall('command'): 638 | self.commands.add(command.get('name')) 639 | 640 | for enum in node.findall('enum'): 641 | extends = enum.get('extends') 642 | if extends is None: 643 | continue 644 | name = enum.get('name') 645 | value = enum.get('value') 646 | bitpos = enum.get('bitpos') 647 | offset = enum.get('offset') 648 | extnumber = enum.get('extnumber') 649 | 650 | if offset is not None: 651 | offset = int(offset) 652 | 653 | if value is not None: # core enums 654 | if value == '0': 655 | AppendToDictOfLists(self.bitmask_dict, extends, ExtBitmask(name, 0)) 656 | else: 657 | AppendToDictOfLists(self.enum_dict, extends, ExtEnum(name, value)) 658 | elif offset is not None: 659 | if extnumber is None and ext_num is not None: 660 | extnumber = ext_num 661 | enum_value = EnumExtValue(int(extnumber), offset, enum.get('dir')) 662 | AppendToDictOfLists(self.enum_dict, extends, ExtEnum(name, enum_value)) 663 | elif bitpos is not None: 664 | AppendToDictOfLists(self.bitmask_dict, extends, ExtBitmask(name, 1 << int(bitpos))) 665 | 666 | def fill(self, enum_dict, bitmask_dict, functions): 667 | for key in self.enum_dict.keys(): 668 | enum_dict[key].fill(self.enum_dict[key]) 669 | [bitmask_dict[key].fill(self.bitmask_dict[key]) for key in self.bitmask_dict.keys()] 670 | self.functions.extend([function for function in functions if function.name in self.commands]) 671 | 672 | def check_platform(self, platform, enum_dict, flags_dict, bitmask_dict, structures, functions): 673 | [platform_check(enum, platform, self.types) for enum in enum_dict.values()] 674 | [platform_check(flag, platform, self.types) for flag in flags_dict.values()] 675 | [platform_check(bitmask, platform, self.types) for bitmask in bitmask_dict.values()] 676 | [platform_check(struct, platform, self.types) for struct in structures] 677 | [platform_check(function, platform, self.commands) for function in functions] 678 | 679 | class Extension: 680 | def __init__(self, node, platforms): 681 | self.name = node.get('name') 682 | self.ext_num = int(node.get('number')) 683 | self.ext_type = node.get('type') 684 | self.supported = node.get('supported') 685 | self.platform = None 686 | if node.get('platform') is not None: 687 | self.platform = platforms[node.get('platform')] 688 | self.requires = [] 689 | for requires in node.findall('require'): 690 | self.requires.append(Requires(requires, self.ext_num)) 691 | if self.supported != "disabled": 692 | self.str_name = node.findall('require')[0].findall('enum')[1].get('name') 693 | 694 | 695 | class VulkanFeatureLevel: 696 | def __init__(self,node): 697 | self.api = node.get('api') 698 | self.name = node.get('name') 699 | self.number = node.get('number') 700 | self.requires = [] 701 | for require in node.findall('require'): 702 | self.requires.append(Requires(require)) 703 | 704 | class DispatchTable: 705 | def __init__(self, name, dispatch_type, ext_or_feature_list): 706 | self.name = name 707 | self.dispatch_type = dispatch_type 708 | self.functions = {} 709 | for ext_or_feature in ext_or_feature_list: 710 | for require in ext_or_feature.requires: 711 | for function in require.functions: 712 | if function.dispatch_type == dispatch_type or dispatch_type == 'instance' and function.name == 'vkGetInstanceProcAddr': 713 | self.functions[function.name] = function 714 | 715 | self.gpa_type = 'PFN_GetDeviceProcAddr' if self.dispatch_type == 'device' else 'PFN_GetInstanceProcAddr' 716 | self.gpa_name = 'get_device_proc_addr' if self.dispatch_type == 'device' else 'get_instance_proc_addr' 717 | self.dispatch_handle = f'Vk{self.dispatch_type.title()}' if self.dispatch_type != 'global' else None 718 | self.gpa_val = f'{self.dispatch_type}' if self.dispatch_type != 'global' else 'nullptr' 719 | 720 | def print_extern_decl(self, file): 721 | PrintConsecutivePlatforms(file, self.functions.values(), 'print_extern_decl', self.dispatch_type) 722 | 723 | def print_function_def(self, file): 724 | PrintConsecutivePlatforms(file, self.functions.values(), 'print_function_def', self.dispatch_type) 725 | 726 | def print_init_global_functions(self, file): 727 | file.write(f'void vkSimpleCppInitialize{self.name}Functions (Vk{self.name} {self.name}) {{\n') 728 | PrintConsecutivePlatforms(file, self.functions.values(), 'print_init_global_functions', self.name) 729 | file.write('};\n') 730 | 731 | def print_dispatch_table(self, file): 732 | file.write(f'struct Vk{self.name}DispatchTable {{\n') 733 | for function in self.functions.values(): 734 | if function.platform is not None: 735 | file.write(f'#if defined({function.platform})\n') 736 | file.write(f' PFN_{function.name} {function.name} = nullptr;\n') 737 | if function.platform is not None: 738 | file.write(f'#else\n') 739 | file.write(f' void* z_padding_{function.name} = nullptr;\n') 740 | file.write(f'#endif // defined({function.platform})\n') 741 | file.write('};\n') 742 | 743 | def print_init_dispatch_table(self, file): 744 | file.write(f'void vkSimpleCppInitialize{self.name}DispatchTable (Vk{self.name} {self.name}, Vk{self.name}DispatchTable & table) {{\n') 745 | for function in self.functions.values(): 746 | if function.platform is not None: 747 | file.write(f'#if defined({function.platform})\n') 748 | file.write(f' table.{function.name} = reinterpret_cast(vkGet{self.name}ProcAddr({self.name}, \"{function.name}\"));\n') 749 | if function.platform is not None: 750 | file.write(f'#endif // defined({function.platform})\n') 751 | file.write('};\n') 752 | 753 | class BindingGenerator: 754 | def __init__(self, root): 755 | 756 | self.platforms = {} 757 | self.default_values = {} 758 | self.requires = [] 759 | self.macro_defines = [] 760 | self.base_types = [] 761 | self.func_pointers = [] 762 | self.flags_dict = {} 763 | self.enum_dict = {} 764 | self.handles = {} 765 | self.dispatchable_handles = [] 766 | self.structures = [] 767 | self.bitmask_dict = {} 768 | self.functions = [] 769 | self.vk_feature_levels = [] 770 | self.ext_list = [] 771 | self.dispatch_tables = [] 772 | self.dispatchable_handle_tables = [] 773 | 774 | for platform in root.find('platforms'): 775 | self.platforms[platform.get('name')] = platform.get('protect') 776 | 777 | for key, value in base_type_default_values.items(): 778 | self.default_values[key] = value 779 | 780 | for enum in root.findall("enums"): 781 | if enum.attrib.get('name') == "API Constants": 782 | for constant in enum.iter(): 783 | api_constant = ApiConstant(constant) 784 | api_constants[api_constant.name] = api_constant 785 | break 786 | 787 | for xml_type in root.find('types'): 788 | category = xml_type.get('category') 789 | if category is None and xml_type.get('requires') is not None: 790 | self.requires.append(PlatformRequires(xml_type)) 791 | elif category == 'define': 792 | self.macro_defines.append(MacroDefine(xml_type)) 793 | elif category == 'basetype': 794 | base_type = BaseType(xml_type) 795 | self.base_types.append(base_type) 796 | if base_type.type is not None: 797 | self.default_values[base_type.name] = base_type.default_value 798 | if base_type.name not in base_type_implicit_conversions: 799 | base_type_implicit_conversions[base_type.name] = base_type.type 800 | elif category == 'funcpointer': 801 | self.func_pointers.append(FuncPointer(xml_type)) 802 | elif category == 'bitmask': 803 | flag = Flags(xml_type) 804 | self.flags_dict[flag.name] = flag 805 | elif category == 'enum': 806 | enum = Enum(xml_type) 807 | if enum.name.find('Flag') == -1 or enum.name.find('FlagBits') == -1: 808 | self.enum_dict[enum.name] = Enum(xml_type) 809 | self.default_values[enum.name] = f'static_cast<{enum.name[2:]}>(0)' 810 | elif category == 'handle': 811 | handle = Handle(xml_type) 812 | self.handles[handle.name] = handle 813 | if handle.alias is None and handle.dispatchable: 814 | self.dispatchable_handles.append(handle.name) 815 | elif category == 'union' or category == 'struct': 816 | self.structures.append(Structure(xml_type, self.handles, self.default_values)) 817 | 818 | #fixup the list so that members using a type appear after that type is defined 819 | outer_counter = 0 820 | inner_counter = 0 821 | while outer_counter < len(self.structures): 822 | moved = False 823 | for m in self.structures[outer_counter].members: 824 | inner_counter = outer_counter 825 | for t2 in self.structures[outer_counter:]: 826 | if m.base_type == t2.name and inner_counter > outer_counter: 827 | self.structures.insert(outer_counter, self.structures.pop(inner_counter)) 828 | moved = True 829 | inner_counter = inner_counter + 1 830 | if not moved: 831 | outer_counter = outer_counter + 1 832 | 833 | for enum in root.findall("enums"): 834 | if enum.get('type') == 'enum': 835 | self.enum_dict[enum.get('name')] = Enum(enum) 836 | elif enum.get('type') == 'bitmask': 837 | self.bitmask_dict[enum.get('name')] = Bitmask(enum) 838 | 839 | # add in flags which have no bitmask 840 | for f in self.flags_dict.values(): 841 | if f.need_empty and f.flag_bits_name not in self.bitmask_dict: 842 | self.bitmask_dict[f.flag_bits_name] = EmptyBitmask(f.flag_bits_name) 843 | 844 | for commands in root.findall('commands'): 845 | for command in commands.findall('command'): 846 | new_function = Function(command, self.handles, self.dispatchable_handles, self.default_values) 847 | if new_function.name not in ['vkEnumerateDeviceLayerProperties']: 848 | self.functions.append(new_function) 849 | 850 | for ext in root.find('extensions'): 851 | if ext.tag == 'extension': 852 | new_ext = Extension(ext, self.platforms) 853 | if new_ext.supported == 'vulkan': 854 | for require in new_ext.requires: 855 | require.check_platform(new_ext.platform, self.enum_dict, self.flags_dict, self.bitmask_dict, 856 | self.structures, self.functions) 857 | require.fill(self.enum_dict, self.bitmask_dict, self.functions) 858 | self.ext_list.append(new_ext) 859 | elif new_ext.supported == 'disabled': 860 | for require in new_ext.requires: 861 | for req_type in require.types: 862 | if req_type in self.enum_dict: 863 | self.enum_dict.pop(req_type) 864 | if req_type in self.bitmask_dict: 865 | self.bitmask_dict.pop(req_type) 866 | if req_type in self.flags_dict: 867 | self.flags_dict.pop(req_type) 868 | for structure in self.structures: 869 | if structure.name == req_type: 870 | self.structures.remove(structure) 871 | for command in require.commands: 872 | for function in self.functions: 873 | if function.name == command: 874 | self.functions.remove(function) 875 | for feature in root.findall('feature'): 876 | feat_level = VulkanFeatureLevel(feature) 877 | for require in feat_level.requires: 878 | require.fill(self.enum_dict, self.bitmask_dict, self.functions) 879 | self.vk_feature_levels.append(feat_level) 880 | 881 | features_and_extensions = self.vk_feature_levels 882 | features_and_extensions.extend(self.ext_list) 883 | 884 | self.dispatch_tables.append(DispatchTable("Global", "global", features_and_extensions)) 885 | self.dispatch_tables.append(DispatchTable("Instance", "instance", features_and_extensions)) 886 | self.dispatch_tables.append(DispatchTable("Device", "device", features_and_extensions)) 887 | 888 | def print_bindings(bindings): 889 | with open(f'include/vulkan/vulkan.h', 'w') as vulkan_core: 890 | vulkan_core.write(license_header) 891 | vulkan_core.write(cpp_header_guard + '\n') 892 | vulkan_core.write(cpp_platform_headers + '\n') 893 | for macro in bindings.macro_defines: 894 | vulkan_core.write(f'{macro.text}\n\n') 895 | PrintConsecutivePlatforms(vulkan_core, api_constants.values(), 'print') 896 | PrintConsecutivePlatforms(vulkan_core, bindings.base_types, 'print') 897 | for ext in bindings.ext_list: 898 | if ext.supported != "disabled": 899 | vulkan_core.write(f'#define {ext.str_name} "{ext.name}"\n') 900 | PrintConsecutivePlatforms(vulkan_core, bindings.enum_dict.values(), 'print') 901 | PrintConsecutivePlatforms(vulkan_core, bindings.bitmask_dict.values(), 'print') 902 | vulkan_core.write(bitmask_flags_macro + '\n') 903 | PrintConsecutivePlatforms(vulkan_core, bindings.flags_dict.values(), 'print') 904 | [ handle.print_vk_handle(vulkan_core) for handle in bindings.handles.values() ] 905 | vulkan_core.write('struct VkDebugUtilsMessengerCallbackDataEXT;\n') 906 | vulkan_core.write('struct VkDeviceMemoryReportCallbackDataEXT;\n') 907 | vulkan_core.write(begin_extern_c) 908 | PrintConsecutivePlatforms(vulkan_core, bindings.func_pointers, 'print') 909 | PrintConsecutivePlatforms(vulkan_core, bindings.structures, 'print') 910 | PrintConsecutivePlatforms(vulkan_core, bindings.functions, 'print_pfn_func_decl') 911 | [ table.print_extern_decl(vulkan_core) for table in bindings.dispatch_tables ] 912 | for dispatch_table in bindings.dispatch_tables: 913 | if dispatch_table.name in ['Device']: 914 | dispatch_table.print_dispatch_table(vulkan_core) 915 | vulkan_core.write(cpp_footer) 916 | 917 | with open(f'include/vulkan/vulkan.cpp', 'w') as vulkan_impl: 918 | vulkan_impl.write(license_header) 919 | vulkan_impl.write('// clang-format off\n#include "vulkan.h"\n') 920 | vulkan_impl.write(cpp_definition) 921 | vulkan_impl.write(begin_extern_c) 922 | vulkan_impl.write('#if defined(__GNUC__)\n#if defined(VK_SIMPLE_USE_DEFAULT_VISIBILITY)\n') 923 | vulkan_impl.write('# pragma GCC visibility push(default)\n#else\n') 924 | vulkan_impl.write('# pragma GCC visibility push(hidden)\n#endif\n#endif\n') 925 | for dispatch_table in bindings.dispatch_tables: 926 | if dispatch_table.name == 'Global': 927 | dispatch_table.print_function_def(vulkan_impl) 928 | elif dispatch_table.name == 'Instance': 929 | dispatch_table.print_function_def(vulkan_impl) 930 | dispatch_table.print_init_global_functions(vulkan_impl) 931 | elif dispatch_table.name == 'Device': 932 | dispatch_table.print_function_def(vulkan_impl) 933 | dispatch_table.print_init_global_functions(vulkan_impl) 934 | dispatch_table.print_init_dispatch_table(vulkan_impl) 935 | vulkan_impl.write('#if defined(__GNUC__)\n# pragma GCC visibility pop\n#endif\n') 936 | vulkan_impl.write(end_extern_c) 937 | vulkan_impl.write('\n// clang-format on\n') 938 | 939 | with open(f'include/vulkan/vulkan_string.h', 'w') as vulkan_string: 940 | vulkan_string.write(license_header) 941 | vulkan_string.write('// clang-format off\n#pragma once\n#include "vulkan.h"\n#include \n') 942 | PrintConsecutivePlatforms(vulkan_string, bindings.enum_dict.values(), 'print_string_forward_def') 943 | PrintConsecutivePlatforms(vulkan_string, bindings.bitmask_dict.values(), 'print_string_forward_def') 944 | vulkan_string.write('\n// clang-format on\n') 945 | 946 | with open(f'include/vulkan/vulkan_string.cpp', 'w') as vulkan_string_impl: 947 | vulkan_string_impl.write(license_header) 948 | vulkan_string_impl.write('// clang-format off\n#include "vulkan_string.h"\n') 949 | vulkan_string_impl.write('''#define UNUSED_VARIABLE(x) (void)(x)\n''') 950 | PrintConsecutivePlatforms(vulkan_string_impl, bindings.enum_dict.values(), 'print_string_impl') 951 | PrintConsecutivePlatforms(vulkan_string_impl, bindings.bitmask_dict.values(), 'print_string_impl') 952 | vulkan_string_impl.write('\n// clang-format on\n') 953 | 954 | def main(): 955 | tree = xml.etree.ElementTree.parse('registry/vk.xml') 956 | root = tree.getroot() 957 | 958 | for tag in root.find('tags'): 959 | vendor_abbreviations.append(tag.get('name')) 960 | 961 | bindings = BindingGenerator(root) 962 | 963 | print_bindings(bindings) 964 | 965 | if __name__ == "__main__": 966 | main() 967 | -------------------------------------------------------------------------------- /include/vulkan/vk_platform.h: -------------------------------------------------------------------------------- 1 | // 2 | // File: vk_platform.h 3 | // 4 | /* 5 | ** Copyright 2014-2022 The Khronos Group Inc. 6 | ** 7 | ** SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | 11 | #ifndef VK_PLATFORM_H_ 12 | #define VK_PLATFORM_H_ 13 | 14 | #ifdef __cplusplus 15 | extern "C" 16 | { 17 | #endif // __cplusplus 18 | 19 | /* 20 | *************************************************************************************************** 21 | * Platform-specific directives and type declarations 22 | *************************************************************************************************** 23 | */ 24 | 25 | /* Platform-specific calling convention macros. 26 | * 27 | * Platforms should define these so that Vulkan clients call Vulkan commands 28 | * with the same calling conventions that the Vulkan implementation expects. 29 | * 30 | * VKAPI_ATTR - Placed before the return type in function declarations. 31 | * Useful for C++11 and GCC/Clang-style function attribute syntax. 32 | * VKAPI_CALL - Placed after the return type in function declarations. 33 | * Useful for MSVC-style calling convention syntax. 34 | * VKAPI_PTR - Placed between the '(' and '*' in function pointer types. 35 | * 36 | * Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void); 37 | * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void); 38 | */ 39 | #if defined(_WIN32) 40 | // On Windows, Vulkan commands use the stdcall convention 41 | #define VKAPI_ATTR 42 | #define VKAPI_CALL __stdcall 43 | #define VKAPI_PTR VKAPI_CALL 44 | #elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 45 | #error "Vulkan is not supported for the 'armeabi' NDK ABI" 46 | #elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) 47 | // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" 48 | // calling convention, i.e. float parameters are passed in registers. This 49 | // is true even if the rest of the application passes floats on the stack, 50 | // as it does by default when compiling for the armeabi-v7a NDK ABI. 51 | #define VKAPI_ATTR __attribute__((pcs("aapcs-vfp"))) 52 | #define VKAPI_CALL 53 | #define VKAPI_PTR VKAPI_ATTR 54 | #else 55 | // On other platforms, use the default calling convention 56 | #define VKAPI_ATTR 57 | #define VKAPI_CALL 58 | #define VKAPI_PTR 59 | #endif 60 | 61 | #if !defined(VK_NO_STDDEF_H) 62 | #include 63 | #endif // !defined(VK_NO_STDDEF_H) 64 | 65 | #if !defined(VK_NO_STDINT_H) 66 | #if defined(_MSC_VER) && (_MSC_VER < 1600) 67 | typedef signed __int8 int8_t; 68 | typedef unsigned __int8 uint8_t; 69 | typedef signed __int16 int16_t; 70 | typedef unsigned __int16 uint16_t; 71 | typedef signed __int32 int32_t; 72 | typedef unsigned __int32 uint32_t; 73 | typedef signed __int64 int64_t; 74 | typedef unsigned __int64 uint64_t; 75 | #else 76 | #include 77 | #endif 78 | #endif // !defined(VK_NO_STDINT_H) 79 | 80 | #ifdef __cplusplus 81 | } // extern "C" 82 | #endif // __cplusplus 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /include/vulkan/vulkan_string.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Charles Giessen (cdgiessen@gmail.com) 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 5 | * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 6 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | * furnished to do so, subject to the following conditions: 8 | * 9 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 12 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 13 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | // clang-format off 17 | #pragma once 18 | #include "vulkan.h" 19 | #include 20 | const char * to_string(VkAttachmentLoadOp val); 21 | const char * to_string(VkAttachmentStoreOp val); 22 | const char * to_string(VkBlendFactor val); 23 | const char * to_string(VkBlendOp val); 24 | const char * to_string(VkBorderColor val); 25 | const char * to_string(VkPipelineCacheHeaderVersion val); 26 | const char * to_string(VkComponentSwizzle val); 27 | const char * to_string(VkCommandBufferLevel val); 28 | const char * to_string(VkCompareOp val); 29 | const char * to_string(VkDescriptorType val); 30 | const char * to_string(VkDynamicState val); 31 | const char * to_string(VkPolygonMode val); 32 | const char * to_string(VkFormat val); 33 | const char * to_string(VkFrontFace val); 34 | const char * to_string(VkImageLayout val); 35 | const char * to_string(VkImageTiling val); 36 | const char * to_string(VkImageType val); 37 | const char * to_string(VkImageViewType val); 38 | const char * to_string(VkSharingMode val); 39 | const char * to_string(VkIndexType val); 40 | const char * to_string(VkLogicOp val); 41 | const char * to_string(VkPhysicalDeviceType val); 42 | const char * to_string(VkPipelineBindPoint val); 43 | const char * to_string(VkPrimitiveTopology val); 44 | const char * to_string(VkQueryType val); 45 | const char * to_string(VkSubpassContents val); 46 | const char * to_string(VkResult val); 47 | const char * to_string(VkStencilOp val); 48 | const char * to_string(VkStructureType val); 49 | const char * to_string(VkSystemAllocationScope val); 50 | const char * to_string(VkInternalAllocationType val); 51 | const char * to_string(VkSamplerAddressMode val); 52 | const char * to_string(VkFilter val); 53 | const char * to_string(VkSamplerMipmapMode val); 54 | const char * to_string(VkVertexInputRate val); 55 | const char * to_string(VkObjectType val); 56 | const char * to_string(VkIndirectCommandsTokenTypeNV val); 57 | const char * to_string(VkDescriptorUpdateTemplateType val); 58 | const char * to_string(VkViewportCoordinateSwizzleNV val); 59 | const char * to_string(VkDiscardRectangleModeEXT val); 60 | const char * to_string(VkPointClippingBehavior val); 61 | const char * to_string(VkCoverageModulationModeNV val); 62 | const char * to_string(VkCoverageReductionModeNV val); 63 | const char * to_string(VkValidationCacheHeaderVersionEXT val); 64 | const char * to_string(VkShaderInfoTypeAMD val); 65 | const char * to_string(VkQueueGlobalPriorityKHR val); 66 | const char * to_string(VkTimeDomainEXT val); 67 | const char * to_string(VkConservativeRasterizationModeEXT val); 68 | const char * to_string(VkSemaphoreType val); 69 | const char * to_string(VkBuildAccelerationStructureModeKHR val); 70 | const char * to_string(VkCopyAccelerationStructureModeKHR val); 71 | const char * to_string(VkAccelerationStructureTypeKHR val); 72 | const char * to_string(VkGeometryTypeKHR val); 73 | const char * to_string(VkRayTracingShaderGroupTypeKHR val); 74 | const char * to_string(VkAccelerationStructureMemoryRequirementsTypeNV val); 75 | const char * to_string(VkAccelerationStructureBuildTypeKHR val); 76 | const char * to_string(VkAccelerationStructureCompatibilityKHR val); 77 | const char * to_string(VkShaderGroupShaderKHR val); 78 | const char * to_string(VkMemoryOverallocationBehaviorAMD val); 79 | const char * to_string(VkScopeNV val); 80 | const char * to_string(VkComponentTypeNV val); 81 | const char * to_string(VkPerformanceCounterScopeKHR val); 82 | const char * to_string(VkPerformanceCounterUnitKHR val); 83 | const char * to_string(VkPerformanceCounterStorageKHR val); 84 | const char * to_string(VkPerformanceConfigurationTypeINTEL val); 85 | const char * to_string(VkQueryPoolSamplingModeINTEL val); 86 | const char * to_string(VkPerformanceOverrideTypeINTEL val); 87 | const char * to_string(VkPerformanceParameterTypeINTEL val); 88 | const char * to_string(VkPerformanceValueTypeINTEL val); 89 | const char * to_string(VkLineRasterizationModeEXT val); 90 | const char * to_string(VkFragmentShadingRateNV val); 91 | const char * to_string(VkFragmentShadingRateTypeNV val); 92 | const char * to_string(VkProvokingVertexModeEXT val); 93 | const char * to_string(VkColorSpaceKHR val); 94 | const char * to_string(VkPresentModeKHR val); 95 | const char * to_string(VkDebugReportObjectTypeEXT val); 96 | const char * to_string(VkDeviceMemoryReportEventTypeEXT val); 97 | const char * to_string(VkRasterizationOrderAMD val); 98 | const char * to_string(VkValidationCheckEXT val); 99 | const char * to_string(VkValidationFeatureEnableEXT val); 100 | const char * to_string(VkValidationFeatureDisableEXT val); 101 | const char * to_string(VkDisplayPowerStateEXT val); 102 | const char * to_string(VkDeviceEventTypeEXT val); 103 | const char * to_string(VkDisplayEventTypeEXT val); 104 | const char * to_string(VkTessellationDomainOrigin val); 105 | const char * to_string(VkSamplerYcbcrModelConversion val); 106 | const char * to_string(VkSamplerYcbcrRange val); 107 | const char * to_string(VkChromaLocation val); 108 | const char * to_string(VkSamplerReductionMode val); 109 | const char * to_string(VkBlendOverlapEXT val); 110 | #if defined(VK_USE_PLATFORM_WIN32_KHR) 111 | const char * to_string(VkFullScreenExclusiveEXT val); 112 | #endif // defined(VK_USE_PLATFORM_WIN32_KHR) 113 | const char * to_string(VkShaderFloatControlsIndependence val); 114 | const char * to_string(VkFragmentShadingRateCombinerOpKHR val); 115 | const char * to_string(VkVendorId val); 116 | const char * to_string(VkDriverId val); 117 | const char * to_string(VkShadingRatePaletteEntryNV val); 118 | const char * to_string(VkCoarseSampleOrderTypeNV val); 119 | const char * to_string(VkPipelineExecutableStatisticFormatKHR val); 120 | #if defined(VK_ENABLE_BETA_EXTENSIONS) 121 | const char * to_string(VkQueryResultStatusKHR val); 122 | #endif // defined(VK_ENABLE_BETA_EXTENSIONS) 123 | const char * to_string(VkAccelerationStructureMotionInstanceTypeNV val); 124 | const char * to_string(VkPipelineCacheCreateFlagBits val); 125 | std::string to_string(VkPipelineCacheCreateFlags flag); 126 | const char * to_string(VkQueueFlagBits val); 127 | std::string to_string(VkQueueFlags flag); 128 | const char * to_string(VkCullModeFlagBits val); 129 | std::string to_string(VkCullModeFlags flag); 130 | const char * to_string(VkRenderPassCreateFlagBits val); 131 | std::string to_string(VkRenderPassCreateFlags flag); 132 | const char * to_string(VkDeviceQueueCreateFlagBits val); 133 | std::string to_string(VkDeviceQueueCreateFlags flag); 134 | const char * to_string(VkMemoryPropertyFlagBits val); 135 | std::string to_string(VkMemoryPropertyFlags flag); 136 | const char * to_string(VkMemoryHeapFlagBits val); 137 | std::string to_string(VkMemoryHeapFlags flag); 138 | const char * to_string(VkAccessFlagBits val); 139 | std::string to_string(VkAccessFlags flag); 140 | const char * to_string(VkBufferUsageFlagBits val); 141 | std::string to_string(VkBufferUsageFlags flag); 142 | const char * to_string(VkBufferCreateFlagBits val); 143 | std::string to_string(VkBufferCreateFlags flag); 144 | const char * to_string(VkShaderStageFlagBits val); 145 | std::string to_string(VkShaderStageFlags flag); 146 | const char * to_string(VkImageUsageFlagBits val); 147 | std::string to_string(VkImageUsageFlags flag); 148 | const char * to_string(VkImageCreateFlagBits val); 149 | std::string to_string(VkImageCreateFlags flag); 150 | const char * to_string(VkImageViewCreateFlagBits val); 151 | std::string to_string(VkImageViewCreateFlags flag); 152 | const char * to_string(VkSamplerCreateFlagBits val); 153 | std::string to_string(VkSamplerCreateFlags flag); 154 | const char * to_string(VkPipelineCreateFlagBits val); 155 | std::string to_string(VkPipelineCreateFlags flag); 156 | const char * to_string(VkPipelineShaderStageCreateFlagBits val); 157 | std::string to_string(VkPipelineShaderStageCreateFlags flag); 158 | const char * to_string(VkColorComponentFlagBits val); 159 | std::string to_string(VkColorComponentFlags flag); 160 | const char * to_string(VkFenceCreateFlagBits val); 161 | std::string to_string(VkFenceCreateFlags flag); 162 | const char * to_string(VkSemaphoreCreateFlagBits val); 163 | std::string to_string(VkSemaphoreCreateFlags flag); 164 | const char * to_string(VkFormatFeatureFlagBits val); 165 | std::string to_string(VkFormatFeatureFlags flag); 166 | const char * to_string(VkQueryControlFlagBits val); 167 | std::string to_string(VkQueryControlFlags flag); 168 | const char * to_string(VkQueryResultFlagBits val); 169 | std::string to_string(VkQueryResultFlags flag); 170 | const char * to_string(VkCommandBufferUsageFlagBits val); 171 | std::string to_string(VkCommandBufferUsageFlags flag); 172 | const char * to_string(VkQueryPipelineStatisticFlagBits val); 173 | std::string to_string(VkQueryPipelineStatisticFlags flag); 174 | const char * to_string(VkImageAspectFlagBits val); 175 | std::string to_string(VkImageAspectFlags flag); 176 | const char * to_string(VkSparseImageFormatFlagBits val); 177 | std::string to_string(VkSparseImageFormatFlags flag); 178 | const char * to_string(VkSparseMemoryBindFlagBits val); 179 | std::string to_string(VkSparseMemoryBindFlags flag); 180 | const char * to_string(VkPipelineStageFlagBits val); 181 | std::string to_string(VkPipelineStageFlags flag); 182 | const char * to_string(VkCommandPoolCreateFlagBits val); 183 | std::string to_string(VkCommandPoolCreateFlags flag); 184 | const char * to_string(VkCommandPoolResetFlagBits val); 185 | std::string to_string(VkCommandPoolResetFlags flag); 186 | const char * to_string(VkCommandBufferResetFlagBits val); 187 | std::string to_string(VkCommandBufferResetFlags flag); 188 | const char * to_string(VkSampleCountFlagBits val); 189 | std::string to_string(VkSampleCountFlags flag); 190 | const char * to_string(VkAttachmentDescriptionFlagBits val); 191 | std::string to_string(VkAttachmentDescriptionFlags flag); 192 | const char * to_string(VkStencilFaceFlagBits val); 193 | std::string to_string(VkStencilFaceFlags flag); 194 | const char * to_string(VkDescriptorPoolCreateFlagBits val); 195 | std::string to_string(VkDescriptorPoolCreateFlags flag); 196 | const char * to_string(VkDependencyFlagBits val); 197 | std::string to_string(VkDependencyFlags flag); 198 | const char * to_string(VkSemaphoreWaitFlagBits val); 199 | std::string to_string(VkSemaphoreWaitFlags flag); 200 | const char * to_string(VkDisplayPlaneAlphaFlagBitsKHR val); 201 | std::string to_string(VkDisplayPlaneAlphaFlagsKHR flag); 202 | const char * to_string(VkCompositeAlphaFlagBitsKHR val); 203 | std::string to_string(VkCompositeAlphaFlagsKHR flag); 204 | const char * to_string(VkSurfaceTransformFlagBitsKHR val); 205 | std::string to_string(VkSurfaceTransformFlagsKHR flag); 206 | const char * to_string(VkDebugReportFlagBitsEXT val); 207 | std::string to_string(VkDebugReportFlagsEXT flag); 208 | const char * to_string(VkExternalMemoryHandleTypeFlagBitsNV val); 209 | std::string to_string(VkExternalMemoryHandleTypeFlagsNV flag); 210 | const char * to_string(VkExternalMemoryFeatureFlagBitsNV val); 211 | std::string to_string(VkExternalMemoryFeatureFlagsNV flag); 212 | const char * to_string(VkSubgroupFeatureFlagBits val); 213 | std::string to_string(VkSubgroupFeatureFlags flag); 214 | const char * to_string(VkIndirectCommandsLayoutUsageFlagBitsNV val); 215 | std::string to_string(VkIndirectCommandsLayoutUsageFlagsNV flag); 216 | const char * to_string(VkIndirectStateFlagBitsNV val); 217 | std::string to_string(VkIndirectStateFlagsNV flag); 218 | const char * to_string(VkPrivateDataSlotCreateFlagBits val); 219 | std::string to_string(VkPrivateDataSlotCreateFlags flag); 220 | const char * to_string(VkDescriptorSetLayoutCreateFlagBits val); 221 | std::string to_string(VkDescriptorSetLayoutCreateFlags flag); 222 | const char * to_string(VkExternalMemoryHandleTypeFlagBits val); 223 | std::string to_string(VkExternalMemoryHandleTypeFlags flag); 224 | const char * to_string(VkExternalMemoryFeatureFlagBits val); 225 | std::string to_string(VkExternalMemoryFeatureFlags flag); 226 | const char * to_string(VkExternalSemaphoreHandleTypeFlagBits val); 227 | std::string to_string(VkExternalSemaphoreHandleTypeFlags flag); 228 | const char * to_string(VkExternalSemaphoreFeatureFlagBits val); 229 | std::string to_string(VkExternalSemaphoreFeatureFlags flag); 230 | const char * to_string(VkSemaphoreImportFlagBits val); 231 | std::string to_string(VkSemaphoreImportFlags flag); 232 | const char * to_string(VkExternalFenceHandleTypeFlagBits val); 233 | std::string to_string(VkExternalFenceHandleTypeFlags flag); 234 | const char * to_string(VkExternalFenceFeatureFlagBits val); 235 | std::string to_string(VkExternalFenceFeatureFlags flag); 236 | const char * to_string(VkFenceImportFlagBits val); 237 | std::string to_string(VkFenceImportFlags flag); 238 | const char * to_string(VkSurfaceCounterFlagBitsEXT val); 239 | std::string to_string(VkSurfaceCounterFlagsEXT flag); 240 | const char * to_string(VkPeerMemoryFeatureFlagBits val); 241 | std::string to_string(VkPeerMemoryFeatureFlags flag); 242 | const char * to_string(VkMemoryAllocateFlagBits val); 243 | std::string to_string(VkMemoryAllocateFlags flag); 244 | const char * to_string(VkDeviceGroupPresentModeFlagBitsKHR val); 245 | std::string to_string(VkDeviceGroupPresentModeFlagsKHR flag); 246 | const char * to_string(VkSwapchainCreateFlagBitsKHR val); 247 | std::string to_string(VkSwapchainCreateFlagsKHR flag); 248 | const char * to_string(VkSubpassDescriptionFlagBits val); 249 | std::string to_string(VkSubpassDescriptionFlags flag); 250 | const char * to_string(VkDebugUtilsMessageSeverityFlagBitsEXT val); 251 | std::string to_string(VkDebugUtilsMessageSeverityFlagsEXT flag); 252 | const char * to_string(VkDebugUtilsMessageTypeFlagBitsEXT val); 253 | std::string to_string(VkDebugUtilsMessageTypeFlagsEXT flag); 254 | const char * to_string(VkDescriptorBindingFlagBits val); 255 | std::string to_string(VkDescriptorBindingFlags flag); 256 | const char * to_string(VkConditionalRenderingFlagBitsEXT val); 257 | std::string to_string(VkConditionalRenderingFlagsEXT flag); 258 | const char * to_string(VkResolveModeFlagBits val); 259 | std::string to_string(VkResolveModeFlags flag); 260 | const char * to_string(VkGeometryInstanceFlagBitsKHR val); 261 | std::string to_string(VkGeometryInstanceFlagsKHR flag); 262 | const char * to_string(VkGeometryFlagBitsKHR val); 263 | std::string to_string(VkGeometryFlagsKHR flag); 264 | const char * to_string(VkBuildAccelerationStructureFlagBitsKHR val); 265 | std::string to_string(VkBuildAccelerationStructureFlagsKHR flag); 266 | const char * to_string(VkAccelerationStructureCreateFlagBitsKHR val); 267 | std::string to_string(VkAccelerationStructureCreateFlagsKHR flag); 268 | const char * to_string(VkFramebufferCreateFlagBits val); 269 | std::string to_string(VkFramebufferCreateFlags flag); 270 | const char * to_string(VkDeviceDiagnosticsConfigFlagBitsNV val); 271 | std::string to_string(VkDeviceDiagnosticsConfigFlagsNV flag); 272 | const char * to_string(VkPipelineCreationFeedbackFlagBits val); 273 | std::string to_string(VkPipelineCreationFeedbackFlags flag); 274 | const char * to_string(VkPerformanceCounterDescriptionFlagBitsKHR val); 275 | std::string to_string(VkPerformanceCounterDescriptionFlagsKHR flag); 276 | const char * to_string(VkAcquireProfilingLockFlagBitsKHR val); 277 | std::string to_string(VkAcquireProfilingLockFlagsKHR flag); 278 | const char * to_string(VkShaderCorePropertiesFlagBitsAMD val); 279 | std::string to_string(VkShaderCorePropertiesFlagsAMD flag); 280 | const char * to_string(VkShaderModuleCreateFlagBits val); 281 | std::string to_string(VkShaderModuleCreateFlags flag); 282 | const char * to_string(VkPipelineCompilerControlFlagBitsAMD val); 283 | std::string to_string(VkPipelineCompilerControlFlagsAMD flag); 284 | const char * to_string(VkToolPurposeFlagBits val); 285 | std::string to_string(VkToolPurposeFlags flag); 286 | const char * to_string(VkAccessFlagBits2 val); 287 | std::string to_string(VkAccessFlags2 flag); 288 | const char * to_string(VkPipelineStageFlagBits2 val); 289 | std::string to_string(VkPipelineStageFlags2 flag); 290 | const char * to_string(VkSubmitFlagBits val); 291 | std::string to_string(VkSubmitFlags flag); 292 | const char * to_string(VkEventCreateFlagBits val); 293 | std::string to_string(VkEventCreateFlags flag); 294 | const char * to_string(VkPipelineLayoutCreateFlagBits val); 295 | std::string to_string(VkPipelineLayoutCreateFlags flag); 296 | const char * to_string(VkPipelineColorBlendStateCreateFlagBits val); 297 | std::string to_string(VkPipelineColorBlendStateCreateFlags flag); 298 | const char * to_string(VkPipelineDepthStencilStateCreateFlagBits val); 299 | std::string to_string(VkPipelineDepthStencilStateCreateFlags flag); 300 | #if defined(VK_ENABLE_BETA_EXTENSIONS) 301 | const char * to_string(VkVideoCodecOperationFlagBitsKHR val); 302 | std::string to_string(VkVideoCodecOperationFlagsKHR flag); 303 | const char * to_string(VkVideoChromaSubsamplingFlagBitsKHR val); 304 | std::string to_string(VkVideoChromaSubsamplingFlagsKHR flag); 305 | const char * to_string(VkVideoComponentBitDepthFlagBitsKHR val); 306 | std::string to_string(VkVideoComponentBitDepthFlagsKHR flag); 307 | const char * to_string(VkVideoCapabilityFlagBitsKHR val); 308 | std::string to_string(VkVideoCapabilityFlagsKHR flag); 309 | const char * to_string(VkVideoSessionCreateFlagBitsKHR val); 310 | std::string to_string(VkVideoSessionCreateFlagsKHR flag); 311 | const char * to_string(VkVideoCodingQualityPresetFlagBitsKHR val); 312 | std::string to_string(VkVideoCodingQualityPresetFlagsKHR flag); 313 | const char * to_string(VkVideoDecodeH264PictureLayoutFlagBitsEXT val); 314 | std::string to_string(VkVideoDecodeH264PictureLayoutFlagsEXT flag); 315 | const char * to_string(VkVideoCodingControlFlagBitsKHR val); 316 | std::string to_string(VkVideoCodingControlFlagsKHR flag); 317 | const char * to_string(VkVideoDecodeFlagBitsKHR val); 318 | std::string to_string(VkVideoDecodeFlagsKHR flag); 319 | const char * to_string(VkVideoEncodeFlagBitsKHR val); 320 | std::string to_string(VkVideoEncodeFlagsKHR flag); 321 | const char * to_string(VkVideoEncodeRateControlFlagBitsKHR val); 322 | std::string to_string(VkVideoEncodeRateControlFlagsKHR flag); 323 | const char * to_string(VkVideoEncodeRateControlModeFlagBitsKHR val); 324 | std::string to_string(VkVideoEncodeRateControlModeFlagsKHR flag); 325 | const char * to_string(VkVideoEncodeH264CapabilityFlagBitsEXT val); 326 | std::string to_string(VkVideoEncodeH264CapabilityFlagsEXT flag); 327 | const char * to_string(VkVideoEncodeH264InputModeFlagBitsEXT val); 328 | std::string to_string(VkVideoEncodeH264InputModeFlagsEXT flag); 329 | const char * to_string(VkVideoEncodeH264OutputModeFlagBitsEXT val); 330 | std::string to_string(VkVideoEncodeH264OutputModeFlagsEXT flag); 331 | const char * to_string(VkVideoEncodeH264CreateFlagBitsEXT val); 332 | std::string to_string(VkVideoEncodeH264CreateFlagsEXT flag); 333 | const char * to_string(VkVideoEncodeH264RateControlStructureFlagBitsEXT val); 334 | std::string to_string(VkVideoEncodeH264RateControlStructureFlagsEXT flag); 335 | #endif // defined(VK_ENABLE_BETA_EXTENSIONS) 336 | #if defined(VK_USE_PLATFORM_FUCHSIA) 337 | const char * to_string(VkImageFormatConstraintsFlagBitsFUCHSIA val); 338 | std::string to_string(VkImageFormatConstraintsFlagsFUCHSIA flag); 339 | const char * to_string(VkImageConstraintsInfoFlagBitsFUCHSIA val); 340 | std::string to_string(VkImageConstraintsInfoFlagsFUCHSIA flag); 341 | #endif // defined(VK_USE_PLATFORM_FUCHSIA) 342 | const char * to_string(VkFormatFeatureFlagBits2 val); 343 | std::string to_string(VkFormatFeatureFlags2 flag); 344 | const char * to_string(VkRenderingFlagBits val); 345 | std::string to_string(VkRenderingFlags flag); 346 | #if defined(VK_ENABLE_BETA_EXTENSIONS) 347 | const char * to_string(VkVideoEncodeH265InputModeFlagBitsEXT val); 348 | std::string to_string(VkVideoEncodeH265InputModeFlagsEXT flag); 349 | const char * to_string(VkVideoEncodeH265OutputModeFlagBitsEXT val); 350 | std::string to_string(VkVideoEncodeH265OutputModeFlagsEXT flag); 351 | const char * to_string(VkVideoEncodeH265CtbSizeFlagBitsEXT val); 352 | std::string to_string(VkVideoEncodeH265CtbSizeFlagsEXT flag); 353 | const char * to_string(VkVideoEncodeH265RateControlStructureFlagBitsEXT val); 354 | std::string to_string(VkVideoEncodeH265RateControlStructureFlagsEXT flag); 355 | #endif // defined(VK_ENABLE_BETA_EXTENSIONS) 356 | #if defined(VK_USE_PLATFORM_ANDROID_KHR) 357 | #endif // defined(VK_USE_PLATFORM_ANDROID_KHR) 358 | #if defined(VK_USE_PLATFORM_VI_NN) 359 | #endif // defined(VK_USE_PLATFORM_VI_NN) 360 | #if defined(VK_USE_PLATFORM_WAYLAND_KHR) 361 | #endif // defined(VK_USE_PLATFORM_WAYLAND_KHR) 362 | #if defined(VK_USE_PLATFORM_WIN32_KHR) 363 | #endif // defined(VK_USE_PLATFORM_WIN32_KHR) 364 | #if defined(VK_USE_PLATFORM_XLIB_KHR) 365 | #endif // defined(VK_USE_PLATFORM_XLIB_KHR) 366 | #if defined(VK_USE_PLATFORM_XCB_KHR) 367 | #endif // defined(VK_USE_PLATFORM_XCB_KHR) 368 | #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) 369 | #endif // defined(VK_USE_PLATFORM_DIRECTFB_EXT) 370 | #if defined(VK_USE_PLATFORM_IOS_MVK) 371 | #endif // defined(VK_USE_PLATFORM_IOS_MVK) 372 | #if defined(VK_USE_PLATFORM_MACOS_MVK) 373 | #endif // defined(VK_USE_PLATFORM_MACOS_MVK) 374 | #if defined(VK_USE_PLATFORM_METAL_EXT) 375 | #endif // defined(VK_USE_PLATFORM_METAL_EXT) 376 | #if defined(VK_USE_PLATFORM_FUCHSIA) 377 | #endif // defined(VK_USE_PLATFORM_FUCHSIA) 378 | #if defined(VK_USE_PLATFORM_GGP) 379 | #endif // defined(VK_USE_PLATFORM_GGP) 380 | #if defined(VK_USE_PLATFORM_SCREEN_QNX) 381 | #endif // defined(VK_USE_PLATFORM_SCREEN_QNX) 382 | #if defined(VK_ENABLE_BETA_EXTENSIONS) 383 | #endif // defined(VK_ENABLE_BETA_EXTENSIONS) 384 | 385 | // clang-format on 386 | -------------------------------------------------------------------------------- /sample/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Charles Giessen (cdgiessen@gmail.com) 2 | 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 4 | # (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 5 | # publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do 6 | # so, subject to the following conditions: 7 | 8 | # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 11 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 12 | # FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 13 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | 15 | option(GLFW_BUILD_TESTS "" OFF) 16 | option(GLFW_BUILD_DOCS "" OFF) 17 | option(GLFW_INSTALL "" OFF) 18 | option(GLFW_BUILD_EXAMPLES "" OFF) 19 | 20 | include(FetchContent) 21 | FetchContent_Declare( 22 | glfw_repo 23 | GIT_REPOSITORY https://github.com/glfw/glfw 24 | GIT_TAG 3.3.2 25 | ) 26 | FetchContent_MakeAvailable(glfw_repo) 27 | 28 | add_executable(vk-triangle triangle.cpp) 29 | target_link_libraries(vk-triangle 30 | PRIVATE 31 | vk-simple-cpp-compiler-options 32 | vulkan-simple-cpp 33 | glfw 34 | ) 35 | 36 | add_custom_target(copy-shader-files ALL 37 | COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/sample/shaders ${CMAKE_CURRENT_BINARY_DIR} 38 | DEPENDS vk-triangle) 39 | 40 | if (SET_COMPILE_TIME_TRACE) 41 | target_compile_options(vk-triangle PUBLIC -ftime-trace) 42 | endif(SET_COMPILE_TIME_TRACE) -------------------------------------------------------------------------------- /sample/shaders/frag.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_ARB_separate_shader_objects : enable 3 | 4 | layout (location = 0) in vec3 fragColor; 5 | 6 | layout (location = 0) out vec4 outColor; 7 | 8 | void main () { outColor = vec4 (fragColor, 1.0); } 9 | -------------------------------------------------------------------------------- /sample/shaders/frag.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cdgiessen/vk-simple-cpp/09c6e3ac33f4cda8910ca4a0a0d6a27822370ffb/sample/shaders/frag.spv -------------------------------------------------------------------------------- /sample/shaders/vert.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_ARB_separate_shader_objects : enable 3 | 4 | layout (location = 0) out vec3 fragColor; 5 | 6 | vec2 positions[3] = vec2[](vec2 (0.0, -0.5), vec2 (0.5, 0.5), vec2 (-0.5, 0.5)); 7 | 8 | vec3 colors[3] = vec3[](vec3 (1.0, 0.0, 0.0), vec3 (0.0, 1.0, 0.0), vec3 (0.0, 0.0, 1.0)); 9 | 10 | void main () 11 | { 12 | gl_Position = vec4 (positions[gl_VertexIndex], 0.0, 1.0); 13 | fragColor = colors[gl_VertexIndex]; 14 | } -------------------------------------------------------------------------------- /sample/shaders/vert.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cdgiessen/vk-simple-cpp/09c6e3ac33f4cda8910ca4a0a0d6a27822370ffb/sample/shaders/vert.spv -------------------------------------------------------------------------------- /sample/triangle.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Charles Giessen (cdgiessen@gmail.com) 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 5 | * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 6 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | * furnished to do so, subject to the following conditions: 8 | * 9 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 12 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 13 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #include "vulkan/vulkan.h" 18 | #include "vulkan/vulkan_string.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | constexpr uint32_t width = 512; 31 | constexpr uint32_t height = 512; 32 | 33 | struct RendererContext 34 | { 35 | GLFWwindow* window; 36 | VkInstance instance; 37 | VkSurfaceKHR surface; 38 | VkPhysicalDevice physical_device; 39 | VkDevice device; 40 | VkDeviceDispatchTable functions; 41 | VkQueue graphics_queue; 42 | VkSwapchainKHR swapchain; 43 | std::vector swapchain_images; 44 | uint32_t image_count = 0; 45 | std::vector swapchain_image_views; 46 | VkFormat swapchain_img_format; 47 | VkRenderPass render_pass; 48 | std::vector framebuffers; 49 | VkPipelineLayout pipeline_layout; 50 | VkPipeline pipeline; 51 | VkCommandPool cmd_pool; 52 | std::vector cmd_buffers; 53 | uint32_t current_frame = 0; 54 | std::vector fences; 55 | std::vector available_semaphores; 56 | std::vector finished_semaphores; 57 | 58 | operator VkDevice() { return device; } 59 | VkDeviceDispatchTable* operator->() { return &functions; } 60 | }; 61 | void check_res(bool result, const char* msg) 62 | { 63 | if (!result) { 64 | std::cerr << msg << "\n"; 65 | assert(false); 66 | } 67 | } 68 | void check_res(VkResult result, const char* msg) 69 | { 70 | if (result != VkResult::Success) { 71 | std::cerr << msg << ": Result = " << to_string(result) << "\n"; 72 | assert(false); 73 | } 74 | } 75 | GLFWwindow* create_window_glfw(const char* window_name = "", bool resize = true) 76 | { 77 | glfwInit(); 78 | glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); 79 | if (!resize) 80 | glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); 81 | 82 | return glfwCreateWindow(width, height, window_name, NULL, NULL); 83 | } 84 | void destroy_window_glfw(GLFWwindow* window) 85 | { 86 | glfwDestroyWindow(window); 87 | glfwTerminate(); 88 | } 89 | VkSurfaceKHR create_surface_glfw(VkInstance instance, GLFWwindow* window) 90 | { 91 | VkSurfaceKHR surface = VK_NULL_HANDLE; 92 | VkResult err = glfwCreateWindowSurface(instance, window, NULL, &surface); 93 | if (err != VkResult::Success) { 94 | const char* error_msg; 95 | int ret = glfwGetError(&error_msg); 96 | if (ret != 0) { 97 | std::cerr << ret << " "; 98 | if (error_msg != nullptr) 99 | std::cerr << error_msg; 100 | std::cerr << "\n"; 101 | } 102 | surface = VK_NULL_HANDLE; 103 | } 104 | return surface; 105 | } 106 | 107 | // Helper for robustly executing the two-call pattern 108 | // NOTE: doesn't work on functions that dont return VkResult 109 | template 110 | auto GetVectorInit(F&& f, T init, Ts&&... ts) -> std::vector 111 | { 112 | uint32_t count = 0; 113 | std::vector results; 114 | VkResult err; 115 | do { 116 | err = f(ts..., &count, nullptr); 117 | check_res(err, "failed to get size"); 118 | results.resize(count, init); 119 | err = f(ts..., &count, results.data()); 120 | results.resize(count); 121 | } while (err == VK_INCOMPLETE); 122 | check_res(err, "failed to get data"); 123 | return results; 124 | } 125 | 126 | template 127 | auto GetVector(F&& f, Ts&&... ts) -> std::vector 128 | { 129 | return GetVectorInit(f, T(), ts...); 130 | } 131 | 132 | void create_renderer_context(RendererContext& context) 133 | { 134 | 135 | check_res(vkSimpleCppInitializeLoaderLibrary(), "Failed to initialize the loader library"); 136 | 137 | context.window = create_window_glfw("Sample Triangle", false); 138 | check_res(context.window != nullptr, "Failed to create glfw window"); 139 | 140 | uint32_t glfw_extension_count = 0; 141 | const char** glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count); 142 | VkInstanceCreateInfo inst_info{}; 143 | inst_info.enabledExtensionCount = glfw_extension_count; 144 | inst_info.ppEnabledExtensionNames = glfw_extensions; 145 | 146 | auto layer_props = GetVector(vkEnumerateInstanceLayerProperties); 147 | 148 | const char* layer_names[] = { "VK_LAYER_KHRONOS_validation" }; 149 | for (auto& layer : layer_props) { 150 | if (std::strcmp(layer.layerName, "VK_LAYER_KHRONOS_validation") == 0) { 151 | inst_info.ppEnabledLayerNames = layer_names; 152 | inst_info.enabledLayerCount = 1; 153 | break; 154 | } 155 | } 156 | 157 | check_res(vkCreateInstance(&inst_info, nullptr, &context.instance), "Failed to init Vulkan Instance"); 158 | 159 | vkSimpleCppInitializeInstanceFunctions(context.instance); 160 | 161 | context.surface = create_surface_glfw(context.instance, context.window); 162 | check_res(context.surface != VK_NULL_HANDLE, "Failed to create glfw surface"); 163 | 164 | auto physical_devices = GetVector(vkEnumeratePhysicalDevices, context.instance); 165 | 166 | context.physical_device = physical_devices[0]; // get first physical device returned 167 | VkBool32 suppprted = 0; 168 | check_res(vkGetPhysicalDeviceSurfaceSupportKHR(context.physical_device, 0, context.surface, &suppprted), 169 | "Failed to query surface support"); 170 | check_res(suppprted, "Surface doesn't support present"); 171 | } 172 | 173 | void create_device_context(RendererContext& context) 174 | { 175 | const char* extensions[] = { "VK_KHR_swapchain" }; 176 | float priority = 1.f; 177 | VkDeviceQueueCreateInfo queue_infos; 178 | queue_infos.pQueuePriorities = &priority; 179 | queue_infos.queueCount = 1; 180 | queue_infos.queueFamilyIndex = 0; 181 | VkDeviceCreateInfo info; 182 | info.enabledExtensionCount = 1; 183 | info.ppEnabledExtensionNames = extensions; 184 | info.queueCreateInfoCount = 1; 185 | info.pQueueCreateInfos = &queue_infos; 186 | check_res(vkCreateDevice(context.physical_device, &info, nullptr, &context.device), "Failed to create a vulkan device"); 187 | 188 | vkSimpleCppInitializeDeviceDispatchTable(context.device, context.functions); 189 | } 190 | 191 | void setup_queues(RendererContext& context) 192 | { 193 | uint32_t queue_family_size = 0; 194 | vkGetPhysicalDeviceQueueFamilyProperties(context.physical_device, &queue_family_size, nullptr); 195 | std::vector queue_family_props(queue_family_size); 196 | vkGetPhysicalDeviceQueueFamilyProperties(context.physical_device, &queue_family_size, queue_family_props.data()); 197 | 198 | uint32_t graphics_queue_family = 0; 199 | for (uint32_t i = 0; i < queue_family_props.size(); i++) { 200 | if (queue_family_props[0].queueFlags & VkQueueFlagBits::Graphics && queue_family_props[0].queueCount > 0) { 201 | graphics_queue_family = i; 202 | break; 203 | } 204 | } 205 | check_res(graphics_queue_family == 0, "First queue isn't the graphics queue, implicit assumptions failed"); 206 | 207 | context->vkGetDeviceQueue(context.device, graphics_queue_family, 0, &context.graphics_queue); 208 | } 209 | 210 | void setup_swapchain(RendererContext& context) 211 | { 212 | auto surf_formats = 213 | GetVector(vkGetPhysicalDeviceSurfaceFormatsKHR, context.physical_device, context.surface); 214 | 215 | VkSurfaceCapabilitiesKHR surf_caps; 216 | check_res(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(context.physical_device, context.surface, &surf_caps), 217 | "Failed to get surface capabilities"); 218 | 219 | context.swapchain_img_format = surf_formats[0].format; 220 | context.image_count = 3; 221 | 222 | VkSwapchainCreateInfoKHR info; 223 | info.surface = context.surface; 224 | info.minImageCount = 3; 225 | info.imageFormat = context.swapchain_img_format; 226 | info.imageColorSpace = surf_formats[0].colorSpace; 227 | info.imageExtent = { width, height }; 228 | info.imageArrayLayers = 1; 229 | info.imageUsage = VkImageUsageFlagBits::ColorAttachment; 230 | info.imageSharingMode = VkSharingMode::Exclusive; 231 | info.pQueueFamilyIndices = nullptr; 232 | info.preTransform = surf_caps.currentTransform; 233 | info.compositeAlpha = VkCompositeAlphaFlagBitsKHR::OpaqueBitKHR; 234 | info.presentMode = VkPresentModeKHR::FifoKHR; 235 | 236 | check_res(context->vkCreateSwapchainKHR(context, &info, nullptr, &context.swapchain), "Unable to create Swapchain"); 237 | 238 | context.swapchain_images = GetVector(context->vkGetSwapchainImagesKHR, context.device, context.swapchain); 239 | 240 | for (auto& image : context.swapchain_images) { 241 | VkImageViewCreateInfo view_info; 242 | view_info.image = image; 243 | view_info.viewType = VkImageViewType::e2D; 244 | view_info.format = context.swapchain_img_format; 245 | view_info.subresourceRange = { VkImageAspectFlagBits::Color, 0, 1, 0, 1 }; 246 | VkImageView view; 247 | check_res(context->vkCreateImageView(context, &view_info, nullptr, &view), "Failed to create swapchain image view"); 248 | 249 | context.swapchain_image_views.push_back(view); 250 | } 251 | } 252 | 253 | void setup_renderpass(RendererContext& context) 254 | { 255 | VkAttachmentDescription desc; 256 | desc.format = context.swapchain_img_format; 257 | desc.samples = VkSampleCountFlagBits::e1; 258 | desc.loadOp = VkAttachmentLoadOp::Clear; 259 | desc.storeOp = VkAttachmentStoreOp::Store; 260 | desc.stencilLoadOp = VkAttachmentLoadOp::DontCare; 261 | desc.stencilStoreOp = VkAttachmentStoreOp::DontCare; 262 | desc.initialLayout = VkImageLayout::Undefined; 263 | desc.finalLayout = VkImageLayout::PresentSrcKHR; 264 | 265 | VkAttachmentReference ref{ 0, VkImageLayout::ColorAttachmentOptimal }; 266 | VkSubpassDescription sub_desc; 267 | sub_desc.pipelineBindPoint = VkPipelineBindPoint::Graphics; 268 | sub_desc.pColorAttachments = &ref; 269 | sub_desc.colorAttachmentCount = 1; 270 | VkSubpassDependency dep; 271 | dep.srcSubpass = VK_SUBPASS_EXTERNAL; 272 | dep.dstSubpass = 0; 273 | dep.srcStageMask = VkPipelineStageFlagBits::ColorAttachmentOutput; 274 | dep.dstStageMask = VkPipelineStageFlagBits::ColorAttachmentOutput; 275 | dep.dstAccessMask = VkAccessFlagBits::ColorAttachmentRead | VkAccessFlagBits::ColorAttachmentWrite; 276 | 277 | VkRenderPassCreateInfo info; 278 | info.attachmentCount = 1; 279 | info.pAttachments = &desc; 280 | info.dependencyCount = 1; 281 | info.pDependencies = &dep; 282 | info.subpassCount = 1; 283 | info.pSubpasses = &sub_desc; 284 | check_res(context->vkCreateRenderPass(context, &info, nullptr, &context.render_pass), "Failed to create renderpass"); 285 | } 286 | void create_framebuffers(RendererContext& context) 287 | { 288 | for (auto& view : context.swapchain_image_views) { 289 | VkFramebufferCreateInfo info; 290 | info.renderPass = context.render_pass; 291 | info.attachmentCount = 1; 292 | info.pAttachments = &view; 293 | info.width = width; 294 | info.height = height; 295 | info.layers = 1; 296 | VkFramebuffer framebuffer; 297 | check_res(context->vkCreateFramebuffer(context, &info, nullptr, &framebuffer), "Failed to create framebuffer"); 298 | context.framebuffers.push_back(framebuffer); 299 | } 300 | } 301 | 302 | std::vector read_file(const std::string& filename) 303 | { 304 | std::ifstream file(filename, std::ios::ate | std::ios::binary); 305 | check_res(file.is_open(), "Failed to open shader file"); 306 | 307 | size_t file_size = (size_t)file.tellg(); 308 | std::vector buffer(file_size); 309 | file.seekg(0); 310 | file.read(buffer.data(), static_cast(file_size)); 311 | file.close(); 312 | return buffer; 313 | } 314 | 315 | VkShaderModule create_shader_module(RendererContext& context, std::string const& filename) 316 | { 317 | auto code = read_file(filename); 318 | VkShaderModule mod; 319 | VkShaderModuleCreateInfo info; 320 | info.codeSize = code.size(); 321 | info.pCode = reinterpret_cast(code.data()); 322 | check_res(context->vkCreateShaderModule(context, &info, nullptr, &mod), "Failed to create shader module"); 323 | return mod; 324 | } 325 | 326 | void create_pipeline(RendererContext& context) 327 | { 328 | VkShaderModule vert = create_shader_module(context, "vert.spv"); 329 | VkShaderModule frag = create_shader_module(context, "frag.spv"); 330 | VkPipelineLayoutCreateInfo p_info_cr; 331 | check_res(context->vkCreatePipelineLayout(context, &p_info_cr, nullptr, &context.pipeline_layout), 332 | "Failed to create pipeline layout"); 333 | 334 | VkViewport viewport = { 0.f, 0.f, static_cast(width), static_cast(height), 0.f, 1.f }; 335 | VkRect2D scissor = { { 0, 0 }, { width, height } }; 336 | VkPipelineShaderStageCreateInfo vert_stage; 337 | vert_stage.stage = VkShaderStageFlagBits::Vertex; 338 | vert_stage.module = vert; 339 | vert_stage.pName = "main"; 340 | VkPipelineShaderStageCreateInfo frag_stage; 341 | frag_stage.stage = VkShaderStageFlagBits::Fragment; 342 | frag_stage.module = frag; 343 | frag_stage.pName = "main"; 344 | VkPipelineShaderStageCreateInfo shaders[2] = { vert_stage, frag_stage }; 345 | VkPipelineVertexInputStateCreateInfo vert_input; 346 | VkPipelineInputAssemblyStateCreateInfo input_assembly; 347 | input_assembly.topology = VkPrimitiveTopology::TriangleList; 348 | VkPipelineViewportStateCreateInfo viewport_state; 349 | viewport_state.viewportCount = 1; 350 | viewport_state.pViewports = &viewport; 351 | viewport_state.scissorCount = 1; 352 | viewport_state.pScissors = &scissor; 353 | VkPipelineRasterizationStateCreateInfo rasterization; 354 | rasterization.polygonMode = VkPolygonMode::Fill; 355 | rasterization.cullMode = VkCullModeFlagBits::Back; 356 | rasterization.frontFace = VkFrontFace::Clockwise; 357 | rasterization.lineWidth = 1.f; 358 | VkPipelineMultisampleStateCreateInfo multisample; 359 | multisample.rasterizationSamples = VkSampleCountFlagBits::e1; 360 | multisample.sampleShadingEnable = false; 361 | VkPipelineColorBlendAttachmentState blend_attachment; 362 | blend_attachment.blendEnable = false; 363 | blend_attachment.colorWriteMask = 364 | VkColorComponentFlagBits::R | VkColorComponentFlagBits::G | VkColorComponentFlagBits::B | VkColorComponentFlagBits::A; 365 | VkPipelineColorBlendStateCreateInfo color_blend; 366 | color_blend.logicOpEnable = false; 367 | color_blend.pAttachments = &blend_attachment; 368 | color_blend.attachmentCount = 1; 369 | 370 | VkDynamicState states[2] = { VkDynamicState::Viewport, VkDynamicState::Scissor }; 371 | VkPipelineDynamicStateCreateInfo dynamic_state; 372 | dynamic_state.dynamicStateCount = 2; 373 | dynamic_state.pDynamicStates = states; 374 | 375 | VkGraphicsPipelineCreateInfo info; 376 | info.renderPass = context.render_pass; 377 | info.layout = context.pipeline_layout; 378 | info.stageCount = 2; 379 | info.pStages = &shaders[0]; 380 | info.pVertexInputState = &vert_input; 381 | info.pInputAssemblyState = &input_assembly; 382 | info.pViewportState = &viewport_state; 383 | info.pRasterizationState = &rasterization; 384 | info.pMultisampleState = &multisample; 385 | info.pColorBlendState = &color_blend; 386 | info.pDynamicState = &dynamic_state; 387 | 388 | check_res(context->vkCreateGraphicsPipelines(context, VK_NULL_HANDLE, 1, &info, nullptr, &context.pipeline), 389 | "Failed to create graphipcs pipeline"); 390 | context->vkDestroyShaderModule(context, vert, nullptr); 391 | context->vkDestroyShaderModule(context, frag, nullptr); 392 | } 393 | 394 | void create_command_buffers(RendererContext& context) 395 | { 396 | VkCommandPoolCreateInfo pool_info; 397 | check_res(context->vkCreateCommandPool(context, &pool_info, nullptr, &context.cmd_pool), "Failed to create command pool"); 398 | 399 | VkCommandBufferAllocateInfo alloc_info; 400 | alloc_info.commandPool = context.cmd_pool; 401 | alloc_info.level = VkCommandBufferLevel::Primary; 402 | alloc_info.commandBufferCount = context.image_count; 403 | context.cmd_buffers.resize(3); 404 | check_res(context->vkAllocateCommandBuffers(context, &alloc_info, context.cmd_buffers.data()), 405 | "Failed to create command buffers"); 406 | 407 | size_t i = 0; 408 | for (auto& cmd_buf : context.cmd_buffers) { 409 | 410 | VkCommandBufferBeginInfo begin_info{}; 411 | check_res(context->vkBeginCommandBuffer(cmd_buf, &begin_info), "Failed to begin command buffer"); 412 | 413 | VkViewport viewport = { 0.f, 0.f, static_cast(width), static_cast(height), 0.f, 1.f }; 414 | VkRect2D scissor = { { 0, 0 }, { width, height } }; 415 | VkClearValue clear_colors = { { 0.f, 0.f, 0.f, 1.f } }; 416 | 417 | VkRenderPassBeginInfo renderpass_info; 418 | renderpass_info.renderPass = context.render_pass; 419 | renderpass_info.framebuffer = context.framebuffers[i++]; 420 | renderpass_info.renderArea = scissor; 421 | renderpass_info.clearValueCount = 4; 422 | renderpass_info.pClearValues = &clear_colors; 423 | 424 | context->vkCmdBeginRenderPass(cmd_buf, &renderpass_info, VkSubpassContents::Inline); 425 | context->vkCmdBindPipeline(cmd_buf, VkPipelineBindPoint::Graphics, context.pipeline); 426 | context->vkCmdSetViewport(cmd_buf, 0, 1, &viewport); 427 | context->vkCmdSetScissor(cmd_buf, 0, 1, &scissor); 428 | context->vkCmdDraw(cmd_buf, 3, 1, 0, 0); 429 | context->vkCmdEndRenderPass(cmd_buf); 430 | check_res(context->vkEndCommandBuffer(cmd_buf), "Failed to end command buffer"); 431 | } 432 | } 433 | 434 | void setup_sync_objects(RendererContext& context) 435 | { 436 | context.fences.resize(context.image_count); 437 | context.available_semaphores.resize(context.image_count); 438 | context.finished_semaphores.resize(context.image_count); 439 | for (uint32_t i = 0; i < context.image_count; i++) { 440 | VkFenceCreateInfo fence_info; 441 | fence_info.flags = VkFenceCreateFlagBits::Signaled; 442 | check_res(context->vkCreateFence(context, &fence_info, nullptr, &context.fences[i]), "Failed to create fence"); 443 | VkSemaphoreCreateInfo sem_info; 444 | check_res(context->vkCreateSemaphore(context, &sem_info, nullptr, &context.available_semaphores[i]), 445 | "Failed to create semaphore"); 446 | check_res(context->vkCreateSemaphore(context, &sem_info, nullptr, &context.finished_semaphores[i]), 447 | "Failed to create semaphore"); 448 | } 449 | } 450 | 451 | void recreate_swapchain(RendererContext& context) 452 | { 453 | check_res(context->vkQueueWaitIdle(context.graphics_queue), ""); 454 | context->vkDestroyCommandPool(context, context.cmd_pool, nullptr); 455 | 456 | for (auto& framebuffer : context.framebuffers) { 457 | context->vkDestroyFramebuffer(context, framebuffer, nullptr); 458 | } 459 | for (auto& image_view : context.swapchain_image_views) { 460 | context->vkDestroyImageView(context, image_view, nullptr); 461 | } 462 | 463 | setup_swapchain(context); 464 | create_framebuffers(context); 465 | create_command_buffers(context); 466 | } 467 | 468 | void draw_frame(RendererContext& context) 469 | { 470 | check_res(context->vkWaitForFences(context, 1, &context.fences[context.current_frame], true, UINT64_MAX), 471 | "Failed to wait for fence"); 472 | 473 | check_res(context->vkResetFences(context, 1, &context.fences[context.current_frame]), "Failed to reset fence"); 474 | 475 | uint32_t image_index; 476 | auto image_index_ret = context->vkAcquireNextImageKHR( 477 | context, context.swapchain, UINT64_MAX, context.available_semaphores[context.current_frame], nullptr, &image_index); 478 | if (image_index_ret == VkResult::ErrorOutOfDateKHR) { 479 | return recreate_swapchain(context); 480 | } else if (image_index_ret != VkResult::Success && image_index_ret != VkResult::SuboptimalKHR) { 481 | std::cerr << "failed to acquire swapchain image. Error " << to_string(image_index_ret) << "\n"; 482 | } 483 | VkPipelineStageFlags dst_stage_mask = VkPipelineStageFlagBits::ColorAttachmentOutput; 484 | VkSubmitInfo submit_info; 485 | submit_info.waitSemaphoreCount = 1; 486 | submit_info.pWaitSemaphores = &context.available_semaphores[context.current_frame]; 487 | submit_info.pWaitDstStageMask = &dst_stage_mask; 488 | submit_info.commandBufferCount = 1; 489 | submit_info.pCommandBuffers = &context.cmd_buffers[image_index]; 490 | submit_info.signalSemaphoreCount = 1; 491 | submit_info.pSignalSemaphores = &context.finished_semaphores[context.current_frame]; 492 | check_res(context->vkQueueSubmit(context.graphics_queue, 1, &submit_info, context.fences[context.current_frame]), 493 | "Failed to submit command buffer"); 494 | 495 | VkPresentInfoKHR present_info; 496 | present_info.waitSemaphoreCount = 1; 497 | present_info.pWaitSemaphores = &context.finished_semaphores[context.current_frame]; 498 | present_info.swapchainCount = 1; 499 | present_info.pSwapchains = &context.swapchain; 500 | present_info.pImageIndices = &image_index; 501 | auto present_ret = context->vkQueuePresentKHR(context.graphics_queue, &present_info); 502 | if (present_ret == VkResult::ErrorOutOfDateKHR || present_ret == VkResult::SuboptimalKHR) { 503 | return recreate_swapchain(context); 504 | } 505 | check_res(present_ret, "Failed to present"); 506 | 507 | context.current_frame = (context.current_frame + 1) % context.image_count; 508 | } 509 | 510 | void destroy_device(RendererContext& context) 511 | { 512 | for (auto& sem : context.available_semaphores) { 513 | context->vkDestroySemaphore(context, sem, nullptr); 514 | } 515 | for (auto& sem : context.finished_semaphores) { 516 | context->vkDestroySemaphore(context, sem, nullptr); 517 | } 518 | for (auto& fence : context.fences) { 519 | context->vkDestroyFence(context, fence, nullptr); 520 | } 521 | context->vkDestroyCommandPool(context, context.cmd_pool, nullptr); 522 | for (auto& framebuffer : context.framebuffers) { 523 | context->vkDestroyFramebuffer(context, framebuffer, nullptr); 524 | } 525 | context->vkDestroyPipeline(context, context.pipeline, nullptr); 526 | context->vkDestroyPipelineLayout(context, context.pipeline_layout, nullptr); 527 | context->vkDestroyRenderPass(context, context.render_pass, nullptr); 528 | for (auto& image_view : context.swapchain_image_views) { 529 | context->vkDestroyImageView(context, image_view, nullptr); 530 | } 531 | context->vkDestroySwapchainKHR(context, context.swapchain, nullptr); 532 | context->vkDestroyDevice(context, nullptr); 533 | } 534 | 535 | void destroy_renderer(RendererContext& context) 536 | { 537 | vkDestroySurfaceKHR(context.instance, context.surface, nullptr); 538 | vkDestroyInstance(context.instance, nullptr); 539 | vkSimpleCppCloseLoaderLibrary(); 540 | destroy_window_glfw(context.window); 541 | } 542 | 543 | int main() 544 | { 545 | RendererContext context; 546 | 547 | create_renderer_context(context); 548 | create_device_context(context); 549 | setup_queues(context); 550 | setup_swapchain(context); 551 | setup_renderpass(context); 552 | create_framebuffers(context); 553 | create_pipeline(context); 554 | create_command_buffers(context); 555 | setup_sync_objects(context); 556 | 557 | while (!glfwWindowShouldClose(context.window)) { 558 | glfwPollEvents(); 559 | draw_frame(context); 560 | } 561 | check_res(context->vkQueueWaitIdle(context.graphics_queue), "Couldn't wait to shut down"); 562 | destroy_device(context); 563 | destroy_renderer(context); 564 | return 0; 565 | } -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Charles Giessen (cdgiessen@gmail.com) 2 | 3 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 4 | # (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 5 | # publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do 6 | # so, subject to the following conditions: 7 | 8 | # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 11 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 12 | # FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 13 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | 15 | include(FetchContent) 16 | FetchContent_Declare( 17 | catch2 18 | GIT_REPOSITORY https://github.com/catchorg/Catch2 19 | GIT_TAG v2.13.1 20 | ) 21 | FetchContent_Declare( 22 | vma_repo 23 | GIT_REPOSITORY https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator 24 | GIT_TAG 59ec0809a7176ce6b9fa3d6341b477102ac3d3aa 25 | ) 26 | FetchContent_Declare( 27 | vk_bootstrap 28 | GIT_REPOSITORY https://github.com/charles-lunarg/vk-bootstrap 29 | GIT_TAG 7aef0dc1c191dbe3392e8abc1b71fd40529295c7 30 | ) 31 | FetchContent_MakeAvailable(catch2 vk_bootstrap) 32 | 33 | FetchContent_GetProperties(vma_repo) 34 | if(NOT vma_repoPOPULATED) 35 | FetchContent_Populate(vma_repo) 36 | add_library(VulkanMemoryAllocator INTERFACE) 37 | target_include_directories(VulkanMemoryAllocator INTERFACE ${vma_repo_SOURCE_DIR}/include) 38 | endif() 39 | 40 | cmake_policy(SET CMP0079 NEW) 41 | target_link_libraries(vk-bootstrap PUBLIC vulkan-simple-cpp) -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Charles Giessen (cdgiessen@gmail.com) 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 5 | * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 6 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 7 | * furnished to do so, subject to the following conditions: 8 | * 9 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 12 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 13 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #define CATCH_CONFIG_MAIN 18 | #include 19 | 20 | #include "vulkan/vulkan.h" 21 | --------------------------------------------------------------------------------