vulkan.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  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. // Please use C89 style variable declarations in this file because VS 2010
  28. //========================================================================
  29. #include "internal.h"
  30. #include <assert.h>
  31. #include <string.h>
  32. #include <stdlib.h>
  33. #define _GLFW_FIND_LOADER 1
  34. #define _GLFW_REQUIRE_LOADER 2
  35. //////////////////////////////////////////////////////////////////////////
  36. ////// GLFW internal API //////
  37. //////////////////////////////////////////////////////////////////////////
  38. bool _glfwInitVulkan(int mode)
  39. {
  40. VkResult err;
  41. VkExtensionProperties* ep;
  42. uint32_t i, count;
  43. if (_glfw.vk.available)
  44. return true;
  45. #if !defined(_GLFW_VULKAN_STATIC)
  46. #if defined(_GLFW_VULKAN_LIBRARY)
  47. _glfw.vk.handle = _glfw_dlopen(_GLFW_VULKAN_LIBRARY);
  48. #elif defined(_GLFW_WIN32)
  49. _glfw.vk.handle = _glfw_dlopen("vulkan-1.dll");
  50. #elif defined(_GLFW_COCOA)
  51. _glfw.vk.handle = _glfw_dlopen("libvulkan.1.dylib");
  52. if (!_glfw.vk.handle)
  53. _glfw.vk.handle = _glfwLoadLocalVulkanLoaderNS();
  54. #else
  55. _glfw.vk.handle = _glfw_dlopen("libvulkan.so.1");
  56. #endif
  57. if (!_glfw.vk.handle)
  58. {
  59. if (mode == _GLFW_REQUIRE_LOADER)
  60. _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found");
  61. return false;
  62. }
  63. *(void **) &_glfw.vk.GetInstanceProcAddr =
  64. _glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr");
  65. if (!_glfw.vk.GetInstanceProcAddr)
  66. {
  67. _glfwInputError(GLFW_API_UNAVAILABLE,
  68. "Vulkan: Loader does not export vkGetInstanceProcAddr");
  69. _glfwTerminateVulkan();
  70. return false;
  71. }
  72. _glfw.vk.EnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)
  73. vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties");
  74. if (!_glfw.vk.EnumerateInstanceExtensionProperties)
  75. {
  76. _glfwInputError(GLFW_API_UNAVAILABLE,
  77. "Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties");
  78. _glfwTerminateVulkan();
  79. return false;
  80. }
  81. #endif // _GLFW_VULKAN_STATIC
  82. err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL);
  83. if (err)
  84. {
  85. // NOTE: This happens on systems with a loader but without any Vulkan ICD
  86. if (mode == _GLFW_REQUIRE_LOADER)
  87. {
  88. _glfwInputError(GLFW_API_UNAVAILABLE,
  89. "Vulkan: Failed to query instance extension count: %s",
  90. _glfwGetVulkanResultString(err));
  91. }
  92. _glfwTerminateVulkan();
  93. return false;
  94. }
  95. ep = calloc(count, sizeof(VkExtensionProperties));
  96. err = vkEnumerateInstanceExtensionProperties(NULL, &count, ep);
  97. if (err)
  98. {
  99. _glfwInputError(GLFW_API_UNAVAILABLE,
  100. "Vulkan: Failed to query instance extensions: %s",
  101. _glfwGetVulkanResultString(err));
  102. free(ep);
  103. _glfwTerminateVulkan();
  104. return false;
  105. }
  106. for (i = 0; i < count; i++)
  107. {
  108. if (strcmp(ep[i].extensionName, "VK_KHR_surface") == 0)
  109. _glfw.vk.KHR_surface = true;
  110. #if defined(_GLFW_WIN32)
  111. else if (strcmp(ep[i].extensionName, "VK_KHR_win32_surface") == 0)
  112. _glfw.vk.KHR_win32_surface = true;
  113. #elif defined(_GLFW_COCOA)
  114. else if (strcmp(ep[i].extensionName, "VK_MVK_macos_surface") == 0)
  115. _glfw.vk.MVK_macos_surface = true;
  116. else if (strcmp(ep[i].extensionName, "VK_EXT_metal_surface") == 0)
  117. _glfw.vk.EXT_metal_surface = true;
  118. #elif defined(_GLFW_X11)
  119. else if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0)
  120. _glfw.vk.KHR_xlib_surface = true;
  121. else if (strcmp(ep[i].extensionName, "VK_KHR_xcb_surface") == 0)
  122. _glfw.vk.KHR_xcb_surface = true;
  123. #elif defined(_GLFW_WAYLAND)
  124. else if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0)
  125. _glfw.vk.KHR_wayland_surface = true;
  126. #endif
  127. }
  128. free(ep);
  129. _glfw.vk.available = true;
  130. _glfwPlatformGetRequiredInstanceExtensions(_glfw.vk.extensions);
  131. return true;
  132. }
  133. void _glfwTerminateVulkan(void)
  134. {
  135. #if !defined(_GLFW_VULKAN_STATIC)
  136. if (_glfw.vk.handle)
  137. _glfw_dlclose(_glfw.vk.handle);
  138. #endif
  139. }
  140. const char* _glfwGetVulkanResultString(VkResult result)
  141. {
  142. switch (result)
  143. {
  144. case VK_SUCCESS:
  145. return "Success";
  146. case VK_NOT_READY:
  147. return "A fence or query has not yet completed";
  148. case VK_TIMEOUT:
  149. return "A wait operation has not completed in the specified time";
  150. case VK_EVENT_SET:
  151. return "An event is signaled";
  152. case VK_EVENT_RESET:
  153. return "An event is unsignaled";
  154. case VK_INCOMPLETE:
  155. return "A return array was too small for the result";
  156. case VK_ERROR_OUT_OF_HOST_MEMORY:
  157. return "A host memory allocation has failed";
  158. case VK_ERROR_OUT_OF_DEVICE_MEMORY:
  159. return "A device memory allocation has failed";
  160. case VK_ERROR_INITIALIZATION_FAILED:
  161. return "Initialization of an object could not be completed for implementation-specific reasons";
  162. case VK_ERROR_DEVICE_LOST:
  163. return "The logical or physical device has been lost";
  164. case VK_ERROR_MEMORY_MAP_FAILED:
  165. return "Mapping of a memory object has failed";
  166. case VK_ERROR_LAYER_NOT_PRESENT:
  167. return "A requested layer is not present or could not be loaded";
  168. case VK_ERROR_EXTENSION_NOT_PRESENT:
  169. return "A requested extension is not supported";
  170. case VK_ERROR_FEATURE_NOT_PRESENT:
  171. return "A requested feature is not supported";
  172. case VK_ERROR_INCOMPATIBLE_DRIVER:
  173. return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible";
  174. case VK_ERROR_TOO_MANY_OBJECTS:
  175. return "Too many objects of the type have already been created";
  176. case VK_ERROR_FORMAT_NOT_SUPPORTED:
  177. return "A requested format is not supported on this device";
  178. case VK_ERROR_SURFACE_LOST_KHR:
  179. return "A surface is no longer available";
  180. case VK_SUBOPTIMAL_KHR:
  181. return "A swapchain no longer matches the surface properties exactly, but can still be used";
  182. case VK_ERROR_OUT_OF_DATE_KHR:
  183. return "A surface has changed in such a way that it is no longer compatible with the swapchain";
  184. case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
  185. return "The display used by a swapchain does not use the same presentable image layout";
  186. case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
  187. return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API";
  188. case VK_ERROR_VALIDATION_FAILED_EXT:
  189. return "A validation layer found an error";
  190. default:
  191. return "ERROR: UNKNOWN VULKAN ERROR";
  192. }
  193. }
  194. //////////////////////////////////////////////////////////////////////////
  195. ////// GLFW public API //////
  196. //////////////////////////////////////////////////////////////////////////
  197. GLFWAPI int glfwVulkanSupported(void)
  198. {
  199. _GLFW_REQUIRE_INIT_OR_RETURN(false);
  200. return _glfwInitVulkan(_GLFW_FIND_LOADER);
  201. }
  202. GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count)
  203. {
  204. assert(count != NULL);
  205. *count = 0;
  206. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  207. if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
  208. return NULL;
  209. if (!_glfw.vk.extensions[0])
  210. return NULL;
  211. *count = 2;
  212. return (const char**) _glfw.vk.extensions;
  213. }
  214. GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance,
  215. const char* procname)
  216. {
  217. GLFWvkproc proc;
  218. assert(procname != NULL);
  219. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  220. if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
  221. return NULL;
  222. proc = (GLFWvkproc) vkGetInstanceProcAddr(instance, procname);
  223. #if defined(_GLFW_VULKAN_STATIC)
  224. if (!proc)
  225. {
  226. if (strcmp(procname, "vkGetInstanceProcAddr") == 0)
  227. return (GLFWvkproc) vkGetInstanceProcAddr;
  228. }
  229. #else
  230. if (!proc)
  231. *(void **) &proc = _glfw_dlsym(_glfw.vk.handle, procname);
  232. #endif
  233. return proc;
  234. }
  235. GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance,
  236. VkPhysicalDevice device,
  237. uint32_t queuefamily)
  238. {
  239. assert(instance != VK_NULL_HANDLE);
  240. assert(device != VK_NULL_HANDLE);
  241. _GLFW_REQUIRE_INIT_OR_RETURN(false);
  242. if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
  243. return false;
  244. if (!_glfw.vk.extensions[0])
  245. {
  246. _glfwInputError(GLFW_API_UNAVAILABLE,
  247. "Vulkan: Window surface creation extensions not found");
  248. return false;
  249. }
  250. return _glfwPlatformGetPhysicalDevicePresentationSupport(instance,
  251. device,
  252. queuefamily);
  253. }
  254. GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance,
  255. GLFWwindow* handle,
  256. const VkAllocationCallbacks* allocator,
  257. VkSurfaceKHR* surface)
  258. {
  259. _GLFWwindow* window = (_GLFWwindow*) handle;
  260. assert(instance != VK_NULL_HANDLE);
  261. assert(window != NULL);
  262. assert(surface != NULL);
  263. *surface = VK_NULL_HANDLE;
  264. _GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED);
  265. if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
  266. return VK_ERROR_INITIALIZATION_FAILED;
  267. if (!_glfw.vk.extensions[0])
  268. {
  269. _glfwInputError(GLFW_API_UNAVAILABLE,
  270. "Vulkan: Window surface creation extensions not found");
  271. return VK_ERROR_EXTENSION_NOT_PRESENT;
  272. }
  273. if (window->context.client != GLFW_NO_API)
  274. {
  275. _glfwInputError(GLFW_INVALID_VALUE,
  276. "Vulkan: Window surface creation requires the window to have the client API set to GLFW_NO_API");
  277. return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;
  278. }
  279. return _glfwPlatformCreateWindowSurface(instance, window, allocator, surface);
  280. }