2 Simple DirectMedia Layer
3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
23 * @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's
27 #include "../../SDL_internal.h"
29 #if SDL_VIDEO_VULKAN && SDL_VIDEO_DRIVER_UIKIT
31 #include "SDL_uikitvideo.h"
32 #include "SDL_uikitwindow.h"
34 #include "SDL_loadso.h"
35 #include "SDL_uikitvulkan.h"
36 #include "SDL_uikitmetalview.h"
37 #include "SDL_syswm.h"
41 const char* defaultPaths[] = {
45 /* Since libSDL is static, could use RTLD_SELF. Using RTLD_DEFAULT is future
47 #define DEFAULT_HANDLE RTLD_DEFAULT
49 int UIKit_Vulkan_LoadLibrary(_THIS, const char *path)
51 VkExtensionProperties *extensions = NULL;
52 Uint32 extensionCount = 0;
53 SDL_bool hasSurfaceExtension = SDL_FALSE;
54 SDL_bool hasIOSSurfaceExtension = SDL_FALSE;
55 PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
57 if (_this->vulkan_config.loader_handle) {
58 return SDL_SetError("Vulkan Portability library is already loaded.");
61 /* Load the Vulkan loader library */
63 path = SDL_getenv("SDL_VULKAN_LIBRARY");
67 /* Handle the case where Vulkan Portability is linked statically. */
68 vkGetInstanceProcAddr =
69 (PFN_vkGetInstanceProcAddr)dlsym(DEFAULT_HANDLE,
70 "vkGetInstanceProcAddr");
73 if (vkGetInstanceProcAddr) {
74 _this->vulkan_config.loader_handle = DEFAULT_HANDLE;
77 const char *foundPath = NULL;
85 /* Look for the .dylib packaged with the application instead. */
87 numPaths = SDL_arraysize(defaultPaths);
90 for (i = 0; i < numPaths && _this->vulkan_config.loader_handle == NULL; i++) {
92 _this->vulkan_config.loader_handle = SDL_LoadObject(foundPath);
95 if (_this->vulkan_config.loader_handle == NULL) {
96 return SDL_SetError("Failed to load Vulkan Portability library");
99 SDL_strlcpy(_this->vulkan_config.loader_path, path,
100 SDL_arraysize(_this->vulkan_config.loader_path));
101 vkGetInstanceProcAddr =
102 (PFN_vkGetInstanceProcAddr)SDL_LoadFunction(
103 _this->vulkan_config.loader_handle,
104 "vkGetInstanceProcAddr");
107 if (!vkGetInstanceProcAddr) {
108 SDL_SetError("Failed to find %s in either executable or %s: %s",
109 "vkGetInstanceProcAddr",
110 "linked Vulkan Portability library",
111 (const char *) dlerror());
115 _this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr;
116 _this->vulkan_config.vkEnumerateInstanceExtensionProperties =
117 (void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)(
118 VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties");
120 if (!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) {
121 SDL_SetError("No vkEnumerateInstanceExtensionProperties found.");
125 extensions = SDL_Vulkan_CreateInstanceExtensionsList(
126 (PFN_vkEnumerateInstanceExtensionProperties)
127 _this->vulkan_config.vkEnumerateInstanceExtensionProperties,
134 for (Uint32 i = 0; i < extensionCount; i++) {
135 if (SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
136 hasSurfaceExtension = SDL_TRUE;
137 } else if (SDL_strcmp(VK_MVK_IOS_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
138 hasIOSSurfaceExtension = SDL_TRUE;
142 SDL_free(extensions);
144 if (!hasSurfaceExtension) {
145 SDL_SetError("Installed Vulkan Portability doesn't implement the "
146 VK_KHR_SURFACE_EXTENSION_NAME " extension");
148 } else if (!hasIOSSurfaceExtension) {
149 SDL_SetError("Installed Vulkan Portability doesn't implement the "
150 VK_MVK_IOS_SURFACE_EXTENSION_NAME "extension");
157 _this->vulkan_config.loader_handle = NULL;
161 void UIKit_Vulkan_UnloadLibrary(_THIS)
163 if (_this->vulkan_config.loader_handle) {
164 if (_this->vulkan_config.loader_handle != DEFAULT_HANDLE) {
165 SDL_UnloadObject(_this->vulkan_config.loader_handle);
167 _this->vulkan_config.loader_handle = NULL;
171 SDL_bool UIKit_Vulkan_GetInstanceExtensions(_THIS,
176 static const char *const extensionsForUIKit[] = {
177 VK_KHR_SURFACE_EXTENSION_NAME, VK_MVK_IOS_SURFACE_EXTENSION_NAME
179 if (!_this->vulkan_config.loader_handle) {
180 SDL_SetError("Vulkan is not loaded");
184 return SDL_Vulkan_GetInstanceExtensions_Helper(
185 count, names, SDL_arraysize(extensionsForUIKit),
189 SDL_bool UIKit_Vulkan_CreateSurface(_THIS,
192 VkSurfaceKHR *surface)
194 PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
195 (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr;
196 PFN_vkCreateIOSSurfaceMVK vkCreateIOSSurfaceMVK =
197 (PFN_vkCreateIOSSurfaceMVK)vkGetInstanceProcAddr(
198 (VkInstance)instance,
199 "vkCreateIOSSurfaceMVK");
200 VkIOSSurfaceCreateInfoMVK createInfo = {};
202 SDL_MetalView metalview;
204 if (!_this->vulkan_config.loader_handle) {
205 SDL_SetError("Vulkan is not loaded");
209 if (!vkCreateIOSSurfaceMVK) {
210 SDL_SetError(VK_MVK_IOS_SURFACE_EXTENSION_NAME
211 " extension is not enabled in the Vulkan instance.");
215 metalview = UIKit_Metal_CreateView(_this, window);
216 if (metalview == NULL) {
220 createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
221 createInfo.pNext = NULL;
222 createInfo.flags = 0;
223 createInfo.pView = (const void *)metalview;
224 result = vkCreateIOSSurfaceMVK(instance, &createInfo,
226 if (result != VK_SUCCESS) {
227 UIKit_Metal_DestroyView(_this, metalview);
228 SDL_SetError("vkCreateIOSSurfaceMVK failed: %s",
229 SDL_Vulkan_GetResultString(result));
233 /* Unfortunately there's no SDL_Vulkan_DestroySurface function we can call
234 * Metal_DestroyView from. Right now the metal view's ref count is +2 (one
235 * from returning a new view object in CreateView, and one because it's
236 * a subview of the window.) If we release the view here to make it +1, it
237 * will be destroyed when the window is destroyed. */
238 CFBridgingRelease(metalview);
243 void UIKit_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h)
245 UIKit_Metal_GetDrawableSize(_this, window, w, h);
250 /* vi: set ts=4 sw=4 expandtab: */