1 /// Translated from C to D
2 module glfw3.vulkan;
3 
4 extern(C): @nogc: nothrow: __gshared:
5 //========================================================================
6 // GLFW 3.3 - www.glfw.org
7 //------------------------------------------------------------------------
8 // Copyright (c) 2002-2006 Marcus Geelnard
9 // Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
10 //
11 // This software is provided 'as-is', without any express or implied
12 // warranty. In no event will the authors be held liable for any damages
13 // arising from the use of this software.
14 //
15 // Permission is granted to anyone to use this software for any purpose,
16 // including commercial applications, and to alter it and redistribute it
17 // freely, subject to the following restrictions:
18 //
19 // 1. The origin of this software must not be misrepresented; you must not
20 //    claim that you wrote the original software. If you use this software
21 //    in a product, an acknowledgment in the product documentation would
22 //    be appreciated but is not required.
23 //
24 // 2. Altered source versions must be plainly marked as such, and must not
25 //    be misrepresented as being the original software.
26 //
27 // 3. This notice may not be removed or altered from any source
28 //    distribution.
29 //
30 //========================================================================
31 // Please use C89 style variable declarations in this file because VS 2010
32 //========================================================================
33 
34 import glfw3.internal;
35 
36 import core.stdc.assert_;
37 import core.stdc.string;
38 import core.stdc.stdlib;
39 
40 enum _GLFW_FIND_LOADER =    1;
41 enum _GLFW_REQUIRE_LOADER = 2;
42 
43 
44 //////////////////////////////////////////////////////////////////////////
45 //////                       GLFW internal API                      //////
46 //////////////////////////////////////////////////////////////////////////
47 
48 GLFWbool _glfwInitVulkan(int mode) {
49     VkResult err;
50     VkExtensionProperties* ep;
51     uint i;uint count;
52 
53     if (_glfw.vk.available)
54         return GLFW_TRUE;
55 
56 version (_GLFW_VULKAN_STATIC) {} else {
57 version (_GLFW_WIN32) {
58     _glfw.vk.handle = _glfw_dlopen("vulkan-1.dll");
59 } else version (_GLFW_COCOA) {
60     _glfw.vk.handle = _glfw_dlopen("libvulkan.1.dylib");
61     if (!_glfw.vk.handle)
62         _glfw.vk.handle = _glfwLoadLocalVulkanLoaderNS();
63 } else {
64     _glfw.vk.handle = _glfw_dlopen("libvulkan.so.1");
65 }
66     if (!_glfw.vk.handle)
67     {
68         if (mode == _GLFW_REQUIRE_LOADER)
69             _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found");
70 
71         return GLFW_FALSE;
72     }
73 
74     _glfw.vk.GetInstanceProcAddr = cast(PFN_vkGetInstanceProcAddr)
75         _glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr");
76     if (!_glfw.vk.GetInstanceProcAddr)
77     {
78         _glfwInputError(GLFW_API_UNAVAILABLE,
79                         "Vulkan: Loader does not export vkGetInstanceProcAddr");
80 
81         _glfwTerminateVulkan();
82         return GLFW_FALSE;
83     }
84 
85     _glfw.vk.EnumerateInstanceExtensionProperties = cast(PFN_vkEnumerateInstanceExtensionProperties)
86         _glfw.vk.GetInstanceProcAddr(null, "vkEnumerateInstanceExtensionProperties");
87     if (!_glfw.vk.EnumerateInstanceExtensionProperties)
88     {
89         _glfwInputError(GLFW_API_UNAVAILABLE,
90                         "Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties");
91 
92         _glfwTerminateVulkan();
93         return GLFW_FALSE;
94     }
95 } // _GLFW_VULKAN_STATIC
96 
97     err = _glfw.vk.EnumerateInstanceExtensionProperties(null, &count, null);
98     if (err)
99     {
100         // NOTE: This happens on systems with a loader but without any Vulkan ICD
101         if (mode == _GLFW_REQUIRE_LOADER)
102         {
103             _glfwInputError(GLFW_API_UNAVAILABLE,
104                             "Vulkan: Failed to query instance extension count: %s",
105                             _glfwGetVulkanResultString(err));
106         }
107 
108         _glfwTerminateVulkan();
109         return GLFW_FALSE;
110     }
111 
112     ep = cast(VkExtensionProperties*) calloc(count, VkExtensionProperties.sizeof);
113 
114     err = _glfw.vk.EnumerateInstanceExtensionProperties(null, &count, ep);
115     if (err)
116     {
117         _glfwInputError(GLFW_API_UNAVAILABLE,
118                         "Vulkan: Failed to query instance extensions: %s",
119                         _glfwGetVulkanResultString(err));
120 
121         free(ep);
122         _glfwTerminateVulkan();
123         return GLFW_FALSE;
124     }
125 
126     for (i = 0;  i < count;  i++)
127     {
128         if (strcmp(ep[i].extensionName.ptr, "VK_KHR_surface") == 0) {
129             _glfw.vk.KHR_surface = GLFW_TRUE;
130         } else {
131             version (_GLFW_WIN32) {
132                 if (strcmp(ep[i].extensionName.ptr, "VK_KHR_win32_surface") == 0) {
133                     _glfw.vk.KHR_win32_surface = GLFW_TRUE;
134                 }
135             } else version (_GLFW_COCOA) {
136                 if (strcmp(ep[i].extensionName.ptr, "VK_MVK_macos_surface") == 0)
137                     _glfw.vk.MVK_macos_surface = GLFW_TRUE;
138                 else if (strcmp(ep[i].extensionName.ptr, "VK_EXT_metal_surface") == 0)
139                     _glfw.vk.EXT_metal_surface = GLFW_TRUE;
140             } else version (_GLFW_X11) {
141                 if (strcmp(ep[i].extensionName.ptr, "VK_KHR_xlib_surface") == 0)
142                     _glfw.vk.KHR_xlib_surface = GLFW_TRUE;
143                 else if (strcmp(ep[i].extensionName.ptr, "VK_KHR_xcb_surface") == 0)
144                     _glfw.vk.KHR_xcb_surface = GLFW_TRUE;
145             } else version (_GLFW_WAYLAND) {
146                 if (strcmp(ep[i].extensionName.ptr, "VK_KHR_wayland_surface") == 0)
147                     _glfw.vk.KHR_wayland_surface = GLFW_TRUE;
148             }
149         }
150     }
151 
152     free(ep);
153 
154     _glfw.vk.available = GLFW_TRUE;
155 
156     _glfwPlatformGetRequiredInstanceExtensions(_glfw.vk.extensions.ptr);
157 
158     return GLFW_TRUE;
159 }
160 
161 void _glfwTerminateVulkan() {
162 version(_GLFW_VULKAN_STATIC) {} else {
163     if (_glfw.vk.handle)
164         _glfw_dlclose(_glfw.vk.handle);
165 }
166 }
167 
168 const(char)* _glfwGetVulkanResultString(VkResult result) {
169     switch (result)
170     {
171         case VkResult.VK_SUCCESS:
172             return "Success";
173         case VkResult.VK_NOT_READY:
174             return "A fence or query has not yet completed";
175         case VkResult.VK_TIMEOUT:
176             return "A wait operation has not completed in the specified time";
177         case VkResult.VK_EVENT_SET:
178             return "An event is signaled";
179         case VkResult.VK_EVENT_RESET:
180             return "An event is unsignaled";
181         case VkResult.VK_INCOMPLETE:
182             return "A return array was too small for the result";
183         case VkResult.VK_ERROR_OUT_OF_HOST_MEMORY:
184             return "A host memory allocation has failed";
185         case VkResult.VK_ERROR_OUT_OF_DEVICE_MEMORY:
186             return "A device memory allocation has failed";
187         case VkResult.VK_ERROR_INITIALIZATION_FAILED:
188             return "Initialization of an object could not be completed for implementation-specific reasons";
189         case VkResult.VK_ERROR_DEVICE_LOST:
190             return "The logical or physical device has been lost";
191         case VkResult.VK_ERROR_MEMORY_MAP_FAILED:
192             return "Mapping of a memory object has failed";
193         case VkResult.VK_ERROR_LAYER_NOT_PRESENT:
194             return "A requested layer is not present or could not be loaded";
195         case VkResult.VK_ERROR_EXTENSION_NOT_PRESENT:
196             return "A requested extension is not supported";
197         case VkResult.VK_ERROR_FEATURE_NOT_PRESENT:
198             return "A requested feature is not supported";
199         case VkResult.VK_ERROR_INCOMPATIBLE_DRIVER:
200             return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible";
201         case VkResult.VK_ERROR_TOO_MANY_OBJECTS:
202             return "Too many objects of the type have already been created";
203         case VkResult.VK_ERROR_FORMAT_NOT_SUPPORTED:
204             return "A requested format is not supported on this device";
205         case VkResult.VK_ERROR_SURFACE_LOST_KHR:
206             return "A surface is no longer available";
207         case VkResult.VK_SUBOPTIMAL_KHR:
208             return "A swapchain no longer matches the surface properties exactly, but can still be used";
209         case VkResult.VK_ERROR_OUT_OF_DATE_KHR:
210             return "A surface has changed in such a way that it is no longer compatible with the swapchain";
211         case VkResult.VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
212             return "The display used by a swapchain does not use the same presentable image layout";
213         case VkResult.VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
214             return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API";
215         case VkResult.VK_ERROR_VALIDATION_FAILED_EXT:
216             return "A validation layer found an error";
217         default:
218             return "ERROR: UNKNOWN VULKAN ERROR";
219     }
220 }
221 
222 
223 //////////////////////////////////////////////////////////////////////////
224 //////                        GLFW public API                       //////
225 //////////////////////////////////////////////////////////////////////////
226 
227 int glfwVulkanSupported() {
228     mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_FALSE");
229     return _glfwInitVulkan(_GLFW_FIND_LOADER);
230 }
231 
232 const(char)** glfwGetRequiredInstanceExtensions(uint* count) {
233     assert(count != null);
234 
235     *count = 0;
236 
237     mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null");
238 
239     if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
240         return null;
241 
242     if (!_glfw.vk.extensions[0])
243         return null;
244 
245     *count = 2;
246     return cast(const(char)**) _glfw.vk.extensions;
247 }
248 
249 GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const(char)* procname) {
250     GLFWvkproc proc;
251     assert(procname != null);
252 
253     mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null");
254 
255     if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
256         return null;
257 
258     proc = cast(GLFWvkproc) _glfw.vk.GetInstanceProcAddr(instance, procname);
259 version (_GLFW_VULKAN_STATIC) {
260     if (!proc)
261     {
262         if (strcmp(procname, "vkGetInstanceProcAddr") == 0)
263             return cast(GLFWvkproc) vkGetInstanceProcAddr;
264     }
265 } else {
266     if (!proc)
267         proc = cast(GLFWvkproc) _glfw_dlsym(_glfw.vk.handle, procname);
268 }
269 
270     return proc;
271 }
272 
273 int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint queuefamily) {
274     assert(instance != null);
275     assert(device != null);
276 
277     mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_FALSE");
278 
279     if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
280         return GLFW_FALSE;
281 
282     if (!_glfw.vk.extensions[0])
283     {
284         _glfwInputError(GLFW_API_UNAVAILABLE,
285                         "Vulkan: Window surface creation extensions not found");
286         return GLFW_FALSE;
287     }
288 
289     return _glfwPlatformGetPhysicalDevicePresentationSupport(instance,
290                                                              device,
291                                                              queuefamily);
292 }
293 
294 VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* handle, const(VkAllocationCallbacks)* allocator, VkSurfaceKHR* surface) {
295     _GLFWwindow* window = cast(_GLFWwindow*) handle;
296     assert(instance != null);
297     assert(window != null);
298     assert(surface != null);
299 
300     *surface = VK_NULL_HANDLE;
301 
302     mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"VkResult.VK_ERROR_INITIALIZATION_FAILED");
303 
304     if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
305         return VkResult.VK_ERROR_INITIALIZATION_FAILED;
306 
307     if (!_glfw.vk.extensions[0])
308     {
309         _glfwInputError(GLFW_API_UNAVAILABLE,
310                         "Vulkan: Window surface creation extensions not found");
311         return VkResult.VK_ERROR_EXTENSION_NOT_PRESENT;
312     }
313 
314     if (window.context.client != GLFW_NO_API)
315     {
316         _glfwInputError(GLFW_INVALID_VALUE,
317                         "Vulkan: Window surface creation requires the window to have the client API set to GLFW_NO_API");
318         return VkResult.VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;
319     }
320 
321     return _glfwPlatformCreateWindowSurface(instance, window, allocator, surface);
322 }