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