1//======================================================================== 2// GLFW 3.5 - 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 42GLFWbool _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 else if (strcmp(ep[i].extensionName, "VK_EXT_headless_surface") == 0) 146 _glfw.vk.EXT_headless_surface = GLFW_TRUE; 147 } 148 149 _glfw_free(ep); 150 151 _glfw.vk.available = GLFW_TRUE; 152 153 _glfw.platform.getRequiredInstanceExtensions(_glfw.vk.extensions); 154 155 return GLFW_TRUE; 156} 157 158void _glfwTerminateVulkan(void) 159{ 160 if (_glfw.vk.handle) 161 _glfwPlatformFreeModule(_glfw.vk.handle); 162} 163 164const char* _glfwGetVulkanResultString(VkResult result) 165{ 166 switch (result) 167 { 168 case VK_SUCCESS: 169 return "Success"; 170 case VK_NOT_READY: 171 return "A fence or query has not yet completed"; 172 case VK_TIMEOUT: 173 return "A wait operation has not completed in the specified time"; 174 case VK_EVENT_SET: 175 return "An event is signaled"; 176 case VK_EVENT_RESET: 177 return "An event is unsignaled"; 178 case VK_INCOMPLETE: 179 return "A return array was too small for the result"; 180 case VK_ERROR_OUT_OF_HOST_MEMORY: 181 return "A host memory allocation has failed"; 182 case VK_ERROR_OUT_OF_DEVICE_MEMORY: 183 return "A device memory allocation has failed"; 184 case VK_ERROR_INITIALIZATION_FAILED: 185 return "Initialization of an object could not be completed for implementation-specific reasons"; 186 case VK_ERROR_DEVICE_LOST: 187 return "The logical or physical device has been lost"; 188 case VK_ERROR_MEMORY_MAP_FAILED: 189 return "Mapping of a memory object has failed"; 190 case VK_ERROR_LAYER_NOT_PRESENT: 191 return "A requested layer is not present or could not be loaded"; 192 case VK_ERROR_EXTENSION_NOT_PRESENT: 193 return "A requested extension is not supported"; 194 case VK_ERROR_FEATURE_NOT_PRESENT: 195 return "A requested feature is not supported"; 196 case VK_ERROR_INCOMPATIBLE_DRIVER: 197 return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible"; 198 case VK_ERROR_TOO_MANY_OBJECTS: 199 return "Too many objects of the type have already been created"; 200 case VK_ERROR_FORMAT_NOT_SUPPORTED: 201 return "A requested format is not supported on this device"; 202 case VK_ERROR_SURFACE_LOST_KHR: 203 return "A surface is no longer available"; 204 case VK_SUBOPTIMAL_KHR: 205 return "A swapchain no longer matches the surface properties exactly, but can still be used"; 206 case VK_ERROR_OUT_OF_DATE_KHR: 207 return "A surface has changed in such a way that it is no longer compatible with the swapchain"; 208 case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: 209 return "The display used by a swapchain does not use the same presentable image layout"; 210 case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: 211 return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API"; 212 case VK_ERROR_VALIDATION_FAILED_EXT: 213 return "A validation layer found an error"; 214 default: 215 return "ERROR: UNKNOWN VULKAN ERROR"; 216 } 217} 218 219 220////////////////////////////////////////////////////////////////////////// 221////// GLFW public API ////// 222////////////////////////////////////////////////////////////////////////// 223 224GLFWAPI int glfwVulkanSupported(void) 225{ 226 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 227 return _glfwInitVulkan(_GLFW_FIND_LOADER); 228} 229 230GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count) 231{ 232 assert(count != NULL); 233 234 *count = 0; 235 236 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 237 238 if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) 239 return NULL; 240 241 if (!_glfw.vk.extensions[0]) 242 return NULL; 243 244 *count = 2; 245 return (const char**) _glfw.vk.extensions; 246} 247 248GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, 249 const char* procname) 250{ 251 GLFWvkproc proc; 252 assert(procname != NULL); 253 254 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 255 256 if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) 257 return NULL; 258 259 // NOTE: Vulkan 1.0 and 1.1 vkGetInstanceProcAddr cannot return itself 260 if (strcmp(procname, "vkGetInstanceProcAddr") == 0) 261 return (GLFWvkproc) vkGetInstanceProcAddr; 262 263 proc = (GLFWvkproc) vkGetInstanceProcAddr(instance, procname); 264 if (!proc) 265 { 266 if (_glfw.vk.handle) 267 proc = (GLFWvkproc) _glfwPlatformGetModuleSymbol(_glfw.vk.handle, procname); 268 } 269 270 return proc; 271} 272 273GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, 274 VkPhysicalDevice device, 275 uint32_t queuefamily) 276{ 277 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 278 279 assert(instance != VK_NULL_HANDLE); 280 assert(device != VK_NULL_HANDLE); 281 282 if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) 283 return GLFW_FALSE; 284 285 if (!_glfw.vk.extensions[0]) 286 { 287 _glfwInputError(GLFW_API_UNAVAILABLE, 288 "Vulkan: Window surface creation extensions not found"); 289 return GLFW_FALSE; 290 } 291 292 return _glfw.platform.getPhysicalDevicePresentationSupport(instance, 293 device, 294 queuefamily); 295} 296 297GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, 298 GLFWwindow* handle, 299 const VkAllocationCallbacks* allocator, 300 VkSurfaceKHR* surface) 301{ 302 assert(surface != NULL); 303 304 *surface = VK_NULL_HANDLE; 305 306 _GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED); 307 308 _GLFWwindow* window = (_GLFWwindow*) handle; 309 assert(window != NULL); 310 assert(instance != VK_NULL_HANDLE); 311 312 if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER)) 313 return VK_ERROR_INITIALIZATION_FAILED; 314 315 if (!_glfw.vk.extensions[0]) 316 { 317 _glfwInputError(GLFW_API_UNAVAILABLE, 318 "Vulkan: Window surface creation extensions not found"); 319 return VK_ERROR_EXTENSION_NOT_PRESENT; 320 } 321 322 if (window->context.client != GLFW_NO_API) 323 { 324 _glfwInputError(GLFW_INVALID_VALUE, 325 "Vulkan: Window surface creation requires the window to have the client API set to GLFW_NO_API"); 326 return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR; 327 } 328 329 return _glfw.platform.createWindowSurface(instance, window, allocator, surface); 330} 331 332