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