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