vulkan_loader.cpp (4510B)
1 // SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 // No better place for this.. 5 #define VMA_IMPLEMENTATION 6 7 #include "vulkan_loader.h" 8 9 #include "common/assert.h" 10 #include "common/dynamic_library.h" 11 #include "common/log.h" 12 13 #include <cstdarg> 14 #include <cstdio> 15 #include <cstdlib> 16 #include <cstring> 17 #include <string> 18 19 Log_SetChannel(VulkanDevice); 20 21 extern "C" { 22 23 #define VULKAN_MODULE_ENTRY_POINT(name, required) PFN_##name name; 24 #define VULKAN_INSTANCE_ENTRY_POINT(name, required) PFN_##name name; 25 #define VULKAN_DEVICE_ENTRY_POINT(name, required) PFN_##name name; 26 #include "vulkan_entry_points.inl" 27 #undef VULKAN_DEVICE_ENTRY_POINT 28 #undef VULKAN_INSTANCE_ENTRY_POINT 29 #undef VULKAN_MODULE_ENTRY_POINT 30 } 31 32 void Vulkan::ResetVulkanLibraryFunctionPointers() 33 { 34 #define VULKAN_MODULE_ENTRY_POINT(name, required) name = nullptr; 35 #define VULKAN_INSTANCE_ENTRY_POINT(name, required) name = nullptr; 36 #define VULKAN_DEVICE_ENTRY_POINT(name, required) name = nullptr; 37 #include "vulkan_entry_points.inl" 38 #undef VULKAN_DEVICE_ENTRY_POINT 39 #undef VULKAN_INSTANCE_ENTRY_POINT 40 #undef VULKAN_MODULE_ENTRY_POINT 41 } 42 43 static DynamicLibrary s_vulkan_library; 44 45 bool Vulkan::IsVulkanLibraryLoaded() 46 { 47 return s_vulkan_library.IsOpen(); 48 } 49 50 bool Vulkan::LoadVulkanLibrary(Error* error) 51 { 52 AssertMsg(!s_vulkan_library.IsOpen(), "Vulkan module is not loaded."); 53 54 #ifdef __APPLE__ 55 // Check if a path to a specific Vulkan library has been specified. 56 char* libvulkan_env = getenv("LIBVULKAN_PATH"); 57 if (libvulkan_env) 58 s_vulkan_library.Open(libvulkan_env, error); 59 if (!s_vulkan_library.IsOpen() && 60 !s_vulkan_library.Open(DynamicLibrary::GetVersionedFilename("MoltenVK").c_str(), error)) 61 { 62 return false; 63 } 64 #else 65 // try versioned first, then unversioned. 66 if (!s_vulkan_library.Open(DynamicLibrary::GetVersionedFilename("vulkan", 1).c_str(), error) && 67 !s_vulkan_library.Open(DynamicLibrary::GetVersionedFilename("vulkan").c_str(), error)) 68 { 69 return false; 70 } 71 #endif 72 73 bool required_functions_missing = false; 74 75 #define VULKAN_MODULE_ENTRY_POINT(name, required) \ 76 if (!s_vulkan_library.GetSymbol(#name, &name)) \ 77 { \ 78 ERROR_LOG("Vulkan: Failed to load required module function {}", #name); \ 79 required_functions_missing = true; \ 80 } 81 #include "vulkan_entry_points.inl" 82 #undef VULKAN_MODULE_ENTRY_POINT 83 84 if (required_functions_missing) 85 { 86 ResetVulkanLibraryFunctionPointers(); 87 s_vulkan_library.Close(); 88 return false; 89 } 90 91 return true; 92 } 93 94 void Vulkan::UnloadVulkanLibrary() 95 { 96 ResetVulkanLibraryFunctionPointers(); 97 s_vulkan_library.Close(); 98 } 99 100 bool Vulkan::LoadVulkanInstanceFunctions(VkInstance instance) 101 { 102 bool required_functions_missing = false; 103 auto LoadFunction = [&](PFN_vkVoidFunction* func_ptr, const char* name, bool is_required) { 104 *func_ptr = vkGetInstanceProcAddr(instance, name); 105 if (!(*func_ptr) && is_required) 106 { 107 ERROR_LOG("Vulkan: Failed to load required instance function {}", name); 108 required_functions_missing = true; 109 } 110 }; 111 112 #define VULKAN_INSTANCE_ENTRY_POINT(name, required) \ 113 LoadFunction(reinterpret_cast<PFN_vkVoidFunction*>(&name), #name, required); 114 #include "vulkan_entry_points.inl" 115 #undef VULKAN_INSTANCE_ENTRY_POINT 116 117 return !required_functions_missing; 118 } 119 120 bool Vulkan::LoadVulkanDeviceFunctions(VkDevice device) 121 { 122 bool required_functions_missing = false; 123 auto LoadFunction = [&](PFN_vkVoidFunction* func_ptr, const char* name, bool is_required) { 124 *func_ptr = vkGetDeviceProcAddr(device, name); 125 if (!(*func_ptr) && is_required) 126 { 127 ERROR_LOG("Vulkan: Failed to load required device function {}", name); 128 required_functions_missing = true; 129 } 130 }; 131 132 #define VULKAN_DEVICE_ENTRY_POINT(name, required) \ 133 LoadFunction(reinterpret_cast<PFN_vkVoidFunction*>(&name), #name, required); 134 #include "vulkan_entry_points.inl" 135 #undef VULKAN_DEVICE_ENTRY_POINT 136 137 return !required_functions_missing; 138 }