vulkan.cc (11169B)
1 //======================================================================== 2 // GLFW 3.3 - www.glfw.org 3 //------------------------------------------------------------------------ 4 // Copyright (c) 2002-2006 Marcus Geelnard 5 // Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org> 6 // 7 // This software is provided 'as-is', without any express or implied 8 // warranty. In no event will the authors be held liable for any damages 9 // arising from the use of this software. 10 // 11 // Permission is granted to anyone to use this software for any purpose, 12 // including commercial applications, and to alter it and redistribute it 13 // freely, subject to the following restrictions: 14 // 15 // 1. The origin of this software must not be misrepresented; you must not 16 // claim that you wrote the original software. If you use this software 17 // in a product, an acknowledgment in the product documentation would 18 // be appreciated but is not required. 19 // 20 // 2. Altered source versions must be plainly marked as such, and must not 21 // be misrepresented as being the original software. 22 // 23 // 3. This notice may not be removed or altered from any source 24 // distribution. 25 // 26 //======================================================================== 27 28 #include "internal.h" 29 30 #include <assert.h> 31 #include <string.h> 32 #include <stdlib.h> 33 34 #define _GLFW_FIND_LOADER 1 35 #define _GLFW_REQUIRE_LOADER 2 36 37 38 ////////////////////////////////////////////////////////////////////////// 39 ////// GLFW internal API ////// 40 ////////////////////////////////////////////////////////////////////////// 41 42 GLFWbool _glfwInitVulkan(int mode) 43 { 44 VkResult err; 45 VkExtensionProperties* ep; 46 uint32_t i, count; 47 48 if (_glfw.vk.available) 49 return GLFW_TRUE; 50 51 #if !defined(_GLFW_VULKAN_STATIC) 52 #if defined(_GLFW_WIN32) 53 _glfw.vk.handle = _glfw_dlopen("vulkan-1.dll"); 54 #elif defined(_GLFW_COCOA) 55 _glfw.vk.handle = _glfw_dlopen("libMoltenVK.dylib"); 56 #else 57 _glfw.vk.handle = _glfw_dlopen("libvulkan.so.1"); 58 #endif 59 if (!_glfw.vk.handle) 60 { 61 if (mode == _GLFW_REQUIRE_LOADER) 62 _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found"); 63 64 return GLFW_FALSE; 65 } 66 67 _glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) 68 _glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr"); 69 if (!_glfw.vk.GetInstanceProcAddr) 70 { 71 _glfwInputError(GLFW_API_UNAVAILABLE, 72 "Vulkan: Loader does not export vkGetInstanceProcAddr"); 73 74 _glfwTerminateVulkan(); 75 return GLFW_FALSE; 76 } 77 78 _glfw.vk.EnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties) 79 vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties"); 80 if (!_glfw.vk.EnumerateInstanceExtensionProperties) 81 { 82 _glfwInputError(GLFW_API_UNAVAILABLE, 83 "Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties"); 84 85 _glfwTerminateVulkan(); 86 return GLFW_FALSE; 87 } 88 #endif // _GLFW_VULKAN_STATIC 89 90 err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL); 91 if (err) 92 { 93 // NOTE: This happens on systems with a loader but without any Vulkan ICD 94 if (mode == _GLFW_REQUIRE_LOADER) 95 { 96 _glfwInputError(GLFW_API_UNAVAILABLE, 97 "Vulkan: Failed to query instance extension count: %s", 98 _glfwGetVulkanResultString(err)); 99 } 100 101 _glfwTerminateVulkan(); 102 return GLFW_FALSE; 103 } 104 105 ep = calloc(count, sizeof(VkExtensionProperties)); 106 107 err = vkEnumerateInstanceExtensionProperties(NULL, &count, ep); 108 if (err) 109 { 110 _glfwInputError(GLFW_API_UNAVAILABLE, 111 "Vulkan: Failed to query instance extensions: %s", 112 _glfwGetVulkanResultString(err)); 113 114 free(ep); 115 _glfwTerminateVulkan(); 116 return GLFW_FALSE; 117 } 118 119 for (i = 0; i < count; i++) 120 { 121 if (strcmp(ep[i].extensionName, "VK_KHR_surface") == 0) 122 _glfw.vk.KHR_surface = GLFW_TRUE; 123 #if defined(_GLFW_WIN32) 124 else if (strcmp(ep[i].extensionName, "VK_KHR_win32_surface") == 0) 125 _glfw.vk.KHR_win32_surface = GLFW_TRUE; 126 #elif defined(_GLFW_COCOA) 127 else if (strcmp(ep[i].extensionName, "VK_MVK_macos_surface") == 0) 128 _glfw.vk.MVK_macos_surface = GLFW_TRUE; 129 #elif defined(_GLFW_X11) 130 else if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0) 131 _glfw.vk.KHR_xlib_surface = GLFW_TRUE; 132 else if (strcmp(ep[i].extensionName, "VK_KHR_xcb_surface") == 0) 133 _glfw.vk.KHR_xcb_surface = GLFW_TRUE; 134 #elif defined(_GLFW_WAYLAND) 135 else if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0) 136 _glfw.vk.KHR_wayland_surface = GLFW_TRUE; 137 #elif defined(_GLFW_MIR) 138 else if (strcmp(ep[i].extensionName, "VK_KHR_mir_surface") == 0) 139 _glfw.vk.KHR_mir_surface = GLFW_TRUE; 140 #endif 141 } 142 143 free(ep); 144 145 _glfw.vk.available = GLFW_TRUE; 146 147 _glfwPlatformGetRequiredInstanceExtensions(_glfw.vk.extensions); 148 149 return GLFW_TRUE; 150 } 151 152 void _glfwTerminateVulkan(void) 153 { 154 #if !defined(_GLFW_VULKAN_STATIC) 155 if (_glfw.vk.handle) 156 _glfw_dlclose(_glfw.vk.handle); 157 #endif 158 } 159 160 const char* _glfwGetVulkanResultString(VkResult result) 161 { 162 switch (result) 163 { 164 case VK_SUCCESS: 165 return "Success"; 166 case VK_NOT_READY: 167 return "A fence or query has not yet completed"; 168 case VK_TIMEOUT: 169 return "A wait operation has not completed in the specified time"; 170 case VK_EVENT_SET: 171 return "An event is signaled"; 172 case VK_EVENT_RESET: 173 return "An event is unsignaled"; 174 case VK_INCOMPLETE: 175 return "A return array was too small for the result"; 176 case VK_ERROR_OUT_OF_HOST_MEMORY: 177 return "A host memory allocation has failed"; 178 case VK_ERROR_OUT_OF_DEVICE_MEMORY: 179 return "A device memory allocation has failed"; 180 case VK_ERROR_INITIALIZATION_FAILED: 181 return "Initialization of an object could not be completed for implementation-specific reasons"; 182 case VK_ERROR_DEVICE_LOST: 183 return "The logical or physical device has been lost"; 184 case VK_ERROR_MEMORY_MAP_FAILED: 185 return "Mapping of a memory object has failed"; 186 case VK_ERROR_LAYER_NOT_PRESENT: 187 return "A requested layer is not present or could not be loaded"; 188 case VK_ERROR_EXTENSION_NOT_PRESENT: 189 return "A requested extension is not supported"; 190 case VK_ERROR_FEATURE_NOT_PRESENT: 191 return "A requested feature is not supported"; 192 case VK_ERROR_INCOMPATIBLE_DRIVER: 193 return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible"; 194 case VK_ERROR_TOO_MANY_OBJECTS: 195 return "Too many objects of the type have already been created"; 196 case VK_ERROR_FORMAT_NOT_SUPPORTED: 197 return "A requested format is not supported on this device"; 198 case VK_ERROR_SURFACE_LOST_KHR: 199 return "A surface is no longer available"; 200 case VK_SUBOPTIMAL_KHR: 201 return "A swapchain no longer matches the surface properties exactly, but can still be used"; 202 case VK_ERROR_OUT_OF_DATE_KHR: 203 return "A surface has changed in such a way that it is no longer compatible with the swapchain"; 204 case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: 205 return "The display used by a swapchain does not use the same presentable image layout"; 206 case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: 207 return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API"; 208 case VK_ERROR_VALIDATION_FAILED_EXT: 209 return "A validation layer found an error"; 210 default: 211 return "ERROR: UNKNOWN VULKAN ERROR"; 212 } 213 } 214 215 216 ////////////////////////////////////////////////////////////////////////// 217 ////// GLFW public API ////// 218 ////////////////////////////////////////////////////////////////////////// 219 220 GLFWAPI int glfwVulkanSupported(void) 221 { 222 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 223 return _glfwInitVulkan(_GLFW_FIND_LOADER); 224 } 225 226 GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count) 227 { 228 assert(count != NULL); 229 230 *count = 0; 231 232 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 233 234 if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) 235 return NULL; 236 237 if (!_glfw.vk.extensions[0]) 238 return NULL; 239 240 *count = 2; 241 return (const char**) _glfw.vk.extensions; 242 } 243 244 GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, 245 const char* procname) 246 { 247 GLFWvkproc proc; 248 assert(procname != NULL); 249 250 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 251 252 if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) 253 return NULL; 254 255 proc = (GLFWvkproc) vkGetInstanceProcAddr(instance, procname); 256 #if defined(_GLFW_VULKAN_STATIC) 257 if (!proc) 258 { 259 if (strcmp(procname, "vkGetInstanceProcAddr") == 0) 260 return (GLFWvkproc) vkGetInstanceProcAddr; 261 } 262 #else 263 if (!proc) 264 proc = (GLFWvkproc) _glfw_dlsym(_glfw.vk.handle, procname); 265 #endif 266 267 return proc; 268 } 269 270 GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, 271 VkPhysicalDevice device, 272 uint32_t queuefamily) 273 { 274 assert(instance != VK_NULL_HANDLE); 275 assert(device != VK_NULL_HANDLE); 276 277 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 278 279 if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) 280 return GLFW_FALSE; 281 282 if (!_glfw.vk.extensions[0]) 283 { 284 _glfwInputError(GLFW_API_UNAVAILABLE, 285 "Vulkan: Window surface creation extensions not found"); 286 return GLFW_FALSE; 287 } 288 289 return _glfwPlatformGetPhysicalDevicePresentationSupport(instance, 290 device, 291 queuefamily); 292 } 293 294 GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, 295 GLFWwindow* handle, 296 const VkAllocationCallbacks* allocator, 297 VkSurfaceKHR* surface) 298 { 299 _GLFWwindow* window = (_GLFWwindow*) handle; 300 assert(instance != VK_NULL_HANDLE); 301 assert(window != NULL); 302 assert(surface != NULL); 303 304 *surface = VK_NULL_HANDLE; 305 306 _GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED); 307 308 if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) 309 return VK_ERROR_INITIALIZATION_FAILED; 310 311 if (!_glfw.vk.extensions[0]) 312 { 313 _glfwInputError(GLFW_API_UNAVAILABLE, 314 "Vulkan: Window surface creation extensions not found"); 315 return VK_ERROR_EXTENSION_NOT_PRESENT; 316 } 317 318 return _glfwPlatformCreateWindowSurface(instance, window, allocator, surface); 319 } 320