• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
_glfwInitVulkan(int mode)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         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 
_glfwTerminateVulkan(void)158 void _glfwTerminateVulkan(void)
159 {
160     if (_glfw.vk.handle)
161         _glfwPlatformFreeModule(_glfw.vk.handle);
162 }
163 
_glfwGetVulkanResultString(VkResult result)164 const 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 
glfwVulkanSupported(void)224 GLFWAPI int glfwVulkanSupported(void)
225 {
226     _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
227     return _glfwInitVulkan(_GLFW_FIND_LOADER);
228 }
229 
glfwGetRequiredInstanceExtensions(uint32_t * count)230 GLFWAPI 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 
glfwGetInstanceProcAddress(VkInstance instance,const char * procname)248 GLFWAPI 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 
glfwGetPhysicalDevicePresentationSupport(VkInstance instance,VkPhysicalDevice device,uint32_t queuefamily)273 GLFWAPI 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 
glfwCreateWindowSurface(VkInstance instance,GLFWwindow * handle,const VkAllocationCallbacks * allocator,VkSurfaceKHR * surface)297 GLFWAPI 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