1//========================================================================
2// GLFW 3.4 - www.glfw.org
3//------------------------------------------------------------------------
4// Copyright (c) 2002-2006 Marcus Geelnard
5// Copyright (c) 2006-2018 Camilla Löwy <[email protected]>
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
30#include "internal.h"
31
32#include <assert.h>
33#include <string.h>
34#include <stdlib.h>
35
36#define _GLFW_FIND_LOADER 1
37#define _GLFW_REQUIRE_LOADER 2
38
39
40//////////////////////////////////////////////////////////////////////////
41////// GLFW internal API //////
42//////////////////////////////////////////////////////////////////////////
43
44GLFWbool _glfwInitVulkan(int mode)
45{
46 VkResult err;
47 VkExtensionProperties* ep;
48 PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
49 uint32_t i, count;
50
51 if (_glfw.vk.available)
52 return GLFW_TRUE;
53
54 if (_glfw.hints.init.vulkanLoader)
55 _glfw.vk.GetInstanceProcAddr = _glfw.hints.init.vulkanLoader;
56 else
57 {
58#if defined(_GLFW_VULKAN_LIBRARY)
59 _glfw.vk.handle = _glfwPlatformLoadModule(_GLFW_VULKAN_LIBRARY);
60#elif defined(_GLFW_WIN32)
61 _glfw.vk.handle = _glfwPlatformLoadModule("vulkan-1.dll");
62#elif defined(_GLFW_COCOA)
63 _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.1.dylib");
64 if (!_glfw.vk.handle)
65 _glfw.vk.handle = _glfwLoadLocalVulkanLoaderCocoa();
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
156void _glfwTerminateVulkan(void)
157{
158 if (_glfw.vk.handle)
159 _glfwPlatformFreeModule(_glfw.vk.handle);
160}
161
162const 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
222GLFWAPI int glfwVulkanSupported(void)
223{
224 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
225 return _glfwInitVulkan(_GLFW_FIND_LOADER);
226}
227
228GLFWAPI 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
246GLFWAPI 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
271GLFWAPI 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
295GLFWAPI 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
329