vulkan.c (11947B)
1 //======================================================================== 2 // GLFW 3.4 - www.glfw.org 3 //------------------------------------------------------------------------ 4 // Copyright (c) 2002-2006 Marcus Geelnard 5 // Copyright (c) 2006-2018 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 PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; 47 uint32_t i, count; 48 49 if (_glfw.vk.available) 50 return GLFW_TRUE; 51 52 if (_glfw.hints.init.vulkanLoader) 53 _glfw.vk.GetInstanceProcAddr = _glfw.hints.init.vulkanLoader; 54 else 55 { 56 #if defined(_GLFW_VULKAN_LIBRARY) 57 _glfw.vk.handle = _glfwPlatformLoadModule(_GLFW_VULKAN_LIBRARY); 58 #elif defined(_GLFW_WIN32) 59 _glfw.vk.handle = _glfwPlatformLoadModule("vulkan-1.dll"); 60 #elif defined(_GLFW_COCOA) 61 _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.1.dylib"); 62 if (!_glfw.vk.handle) 63 _glfw.vk.handle = _glfwLoadLocalVulkanLoaderCocoa(); 64 #elif defined(__OpenBSD__) || defined(__NetBSD__) 65 _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so"); 66 #else 67 _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so.1"); 68 #endif 69 if (!_glfw.vk.handle) 70 { 71 if (mode == _GLFW_REQUIRE_LOADER) 72 _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found"); 73 74 return GLFW_FALSE; 75 } 76 77 _glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) 78 _glfwPlatformGetModuleSymbol(_glfw.vk.handle, "vkGetInstanceProcAddr"); 79 if (!_glfw.vk.GetInstanceProcAddr) 80 { 81 _glfwInputError(GLFW_API_UNAVAILABLE, 82 "Vulkan: Loader does not export vkGetInstanceProcAddr"); 83 84 _glfwTerminateVulkan(); 85 return GLFW_FALSE; 86 } 87 } 88 89 vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties) 90 vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties"); 91 if (!vkEnumerateInstanceExtensionProperties) 92 { 93 _glfwInputError(GLFW_API_UNAVAILABLE, 94 "Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties"); 95 96 _glfwTerminateVulkan(); 97 return GLFW_FALSE; 98 } 99 100 err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL); 101 if (err) 102 { 103 // NOTE: This happens on systems with a loader but without any Vulkan ICD 104 if (mode == _GLFW_REQUIRE_LOADER) 105 { 106 _glfwInputError(GLFW_API_UNAVAILABLE, 107 "Vulkan: Failed to query instance extension count: %s", 108 _glfwGetVulkanResultString(err)); 109 } 110 111 _glfwTerminateVulkan(); 112 return GLFW_FALSE; 113 } 114 115 ep = _glfw_calloc(count, sizeof(VkExtensionProperties)); 116 117 err = vkEnumerateInstanceExtensionProperties(NULL, &count, ep); 118 if (err) 119 { 120 _glfwInputError(GLFW_API_UNAVAILABLE, 121 "Vulkan: Failed to query instance extensions: %s", 122 _glfwGetVulkanResultString(err)); 123 124 _glfw_free(ep); 125 _glfwTerminateVulkan(); 126 return GLFW_FALSE; 127 } 128 129 for (i = 0; i < count; i++) 130 { 131 if (strcmp(ep[i].extensionName, "VK_KHR_surface") == 0) 132 _glfw.vk.KHR_surface = GLFW_TRUE; 133 else if (strcmp(ep[i].extensionName, "VK_KHR_win32_surface") == 0) 134 _glfw.vk.KHR_win32_surface = GLFW_TRUE; 135 else if (strcmp(ep[i].extensionName, "VK_MVK_macos_surface") == 0) 136 _glfw.vk.MVK_macos_surface = GLFW_TRUE; 137 else if (strcmp(ep[i].extensionName, "VK_EXT_metal_surface") == 0) 138 _glfw.vk.EXT_metal_surface = GLFW_TRUE; 139 else if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0) 140 _glfw.vk.KHR_xlib_surface = GLFW_TRUE; 141 else if (strcmp(ep[i].extensionName, "VK_KHR_xcb_surface") == 0) 142 _glfw.vk.KHR_xcb_surface = GLFW_TRUE; 143 else if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0) 144 _glfw.vk.KHR_wayland_surface = GLFW_TRUE; 145 } 146 147 _glfw_free(ep); 148 149 _glfw.vk.available = GLFW_TRUE; 150 151 _glfw.platform.getRequiredInstanceExtensions(_glfw.vk.extensions); 152 153 return GLFW_TRUE; 154 } 155 156 void _glfwTerminateVulkan(void) 157 { 158 if (_glfw.vk.handle) 159 _glfwPlatformFreeModule(_glfw.vk.handle); 160 } 161 162 const char* _glfwGetVulkanResultString(VkResult result) 163 { 164 switch (result) 165 { 166 case VK_SUCCESS: 167 return "Success"; 168 case VK_NOT_READY: 169 return "A fence or query has not yet completed"; 170 case VK_TIMEOUT: 171 return "A wait operation has not completed in the specified time"; 172 case VK_EVENT_SET: 173 return "An event is signaled"; 174 case VK_EVENT_RESET: 175 return "An event is unsignaled"; 176 case VK_INCOMPLETE: 177 return "A return array was too small for the result"; 178 case VK_ERROR_OUT_OF_HOST_MEMORY: 179 return "A host memory allocation has failed"; 180 case VK_ERROR_OUT_OF_DEVICE_MEMORY: 181 return "A device memory allocation has failed"; 182 case VK_ERROR_INITIALIZATION_FAILED: 183 return "Initialization of an object could not be completed for implementation-specific reasons"; 184 case VK_ERROR_DEVICE_LOST: 185 return "The logical or physical device has been lost"; 186 case VK_ERROR_MEMORY_MAP_FAILED: 187 return "Mapping of a memory object has failed"; 188 case VK_ERROR_LAYER_NOT_PRESENT: 189 return "A requested layer is not present or could not be loaded"; 190 case VK_ERROR_EXTENSION_NOT_PRESENT: 191 return "A requested extension is not supported"; 192 case VK_ERROR_FEATURE_NOT_PRESENT: 193 return "A requested feature is not supported"; 194 case VK_ERROR_INCOMPATIBLE_DRIVER: 195 return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible"; 196 case VK_ERROR_TOO_MANY_OBJECTS: 197 return "Too many objects of the type have already been created"; 198 case VK_ERROR_FORMAT_NOT_SUPPORTED: 199 return "A requested format is not supported on this device"; 200 case VK_ERROR_SURFACE_LOST_KHR: 201 return "A surface is no longer available"; 202 case VK_SUBOPTIMAL_KHR: 203 return "A swapchain no longer matches the surface properties exactly, but can still be used"; 204 case VK_ERROR_OUT_OF_DATE_KHR: 205 return "A surface has changed in such a way that it is no longer compatible with the swapchain"; 206 case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: 207 return "The display used by a swapchain does not use the same presentable image layout"; 208 case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: 209 return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API"; 210 case VK_ERROR_VALIDATION_FAILED_EXT: 211 return "A validation layer found an error"; 212 default: 213 return "ERROR: UNKNOWN VULKAN ERROR"; 214 } 215 } 216 217 218 ////////////////////////////////////////////////////////////////////////// 219 ////// GLFW public API ////// 220 ////////////////////////////////////////////////////////////////////////// 221 222 GLFWAPI int glfwVulkanSupported(void) 223 { 224 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 225 return _glfwInitVulkan(_GLFW_FIND_LOADER); 226 } 227 228 GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count) 229 { 230 assert(count != NULL); 231 232 *count = 0; 233 234 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 235 236 if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) 237 return NULL; 238 239 if (!_glfw.vk.extensions[0]) 240 return NULL; 241 242 *count = 2; 243 return (const char**) _glfw.vk.extensions; 244 } 245 246 GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, 247 const char* procname) 248 { 249 GLFWvkproc proc; 250 assert(procname != NULL); 251 252 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 253 254 if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) 255 return NULL; 256 257 // NOTE: Vulkan 1.0 and 1.1 vkGetInstanceProcAddr cannot return itself 258 if (strcmp(procname, "vkGetInstanceProcAddr") == 0) 259 return (GLFWvkproc) vkGetInstanceProcAddr; 260 261 proc = (GLFWvkproc) vkGetInstanceProcAddr(instance, procname); 262 if (!proc) 263 { 264 if (_glfw.vk.handle) 265 proc = (GLFWvkproc) _glfwPlatformGetModuleSymbol(_glfw.vk.handle, procname); 266 } 267 268 return proc; 269 } 270 271 GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, 272 VkPhysicalDevice device, 273 uint32_t queuefamily) 274 { 275 assert(instance != VK_NULL_HANDLE); 276 assert(device != VK_NULL_HANDLE); 277 278 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 279 280 if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) 281 return GLFW_FALSE; 282 283 if (!_glfw.vk.extensions[0]) 284 { 285 _glfwInputError(GLFW_API_UNAVAILABLE, 286 "Vulkan: Window surface creation extensions not found"); 287 return GLFW_FALSE; 288 } 289 290 return _glfw.platform.getPhysicalDevicePresentationSupport(instance, 291 device, 292 queuefamily); 293 } 294 295 GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, 296 GLFWwindow* handle, 297 const VkAllocationCallbacks* allocator, 298 VkSurfaceKHR* surface) 299 { 300 _GLFWwindow* window = (_GLFWwindow*) handle; 301 assert(instance != VK_NULL_HANDLE); 302 assert(window != NULL); 303 assert(surface != NULL); 304 305 *surface = VK_NULL_HANDLE; 306 307 _GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED); 308 309 if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) 310 return VK_ERROR_INITIALIZATION_FAILED; 311 312 if (!_glfw.vk.extensions[0]) 313 { 314 _glfwInputError(GLFW_API_UNAVAILABLE, 315 "Vulkan: Window surface creation extensions not found"); 316 return VK_ERROR_EXTENSION_NOT_PRESENT; 317 } 318 319 if (window->context.client != GLFW_NO_API) 320 { 321 _glfwInputError(GLFW_INVALID_VALUE, 322 "Vulkan: Window surface creation requires the window to have the client API set to GLFW_NO_API"); 323 return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR; 324 } 325 326 return _glfw.platform.createWindowSurface(instance, window, allocator, surface); 327 } 328