sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_cocoavulkan.m (8646B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
      4 
      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.
      8 
      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:
     12 
     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.
     20 */
     21 
     22 /*
     23  * @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's
     24  * SDL_x11vulkan.c.
     25  */
     26 #include "../../SDL_internal.h"
     27 
     28 #if SDL_VIDEO_VULKAN && SDL_VIDEO_DRIVER_COCOA
     29 
     30 #include "SDL_cocoavideo.h"
     31 #include "SDL_cocoawindow.h"
     32 
     33 #include "SDL_loadso.h"
     34 #include "SDL_cocoametalview.h"
     35 #include "SDL_cocoavulkan.h"
     36 #include "SDL_syswm.h"
     37 
     38 #include <dlfcn.h>
     39 
     40 const char* defaultPaths[] = {
     41     "vulkan.framework/vulkan",
     42     "libvulkan.1.dylib",
     43     "libvulkan.dylib",
     44     "MoltenVK.framework/MoltenVK",
     45     "libMoltenVK.dylib"
     46 };
     47 
     48 /* Since libSDL is most likely a .dylib, need RTLD_DEFAULT not RTLD_SELF. */
     49 #define DEFAULT_HANDLE RTLD_DEFAULT
     50 
     51 int Cocoa_Vulkan_LoadLibrary(_THIS, const char *path)
     52 {
     53     VkExtensionProperties *extensions = NULL;
     54     Uint32 extensionCount = 0;
     55     SDL_bool hasSurfaceExtension = SDL_FALSE;
     56     SDL_bool hasMacOSSurfaceExtension = SDL_FALSE;
     57     PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
     58 
     59     if (_this->vulkan_config.loader_handle) {
     60         return SDL_SetError("Vulkan Portability library is already loaded.");
     61     }
     62 
     63     /* Load the Vulkan loader library */
     64     if (!path) {
     65         path = SDL_getenv("SDL_VULKAN_LIBRARY");
     66     }
     67 
     68     if (!path) {
     69         /* Handle the case where Vulkan Portability is linked statically. */
     70         vkGetInstanceProcAddr =
     71          (PFN_vkGetInstanceProcAddr)dlsym(DEFAULT_HANDLE,
     72                                           "vkGetInstanceProcAddr");
     73     }
     74 
     75     if (vkGetInstanceProcAddr) {
     76         _this->vulkan_config.loader_handle = DEFAULT_HANDLE;
     77     } else {
     78         const char** paths;
     79         const char *foundPath = NULL;
     80         int numPaths;
     81         int i;
     82 
     83         if (path) {
     84             paths = &path;
     85             numPaths = 1;
     86         } else {
     87             /* Look for framework or .dylib packaged with the application
     88              * instead. */
     89             paths = defaultPaths;
     90             numPaths = SDL_arraysize(defaultPaths);
     91         }
     92 
     93         for (i = 0; i < numPaths && _this->vulkan_config.loader_handle == NULL; i++) {
     94             foundPath = paths[i];
     95             _this->vulkan_config.loader_handle = SDL_LoadObject(foundPath);
     96         }
     97 
     98         if (_this->vulkan_config.loader_handle == NULL) {
     99             return SDL_SetError("Failed to load Vulkan Portability library");
    100         }
    101 
    102         SDL_strlcpy(_this->vulkan_config.loader_path, foundPath,
    103                     SDL_arraysize(_this->vulkan_config.loader_path));
    104         vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction(
    105             _this->vulkan_config.loader_handle, "vkGetInstanceProcAddr");
    106     }
    107 
    108     if (!vkGetInstanceProcAddr) {
    109         SDL_SetError("Failed to find %s in either executable or %s: %s",
    110                      "vkGetInstanceProcAddr",
    111                      _this->vulkan_config.loader_path,
    112                      (const char *) dlerror());
    113         goto fail;
    114     }
    115 
    116     _this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr;
    117     _this->vulkan_config.vkEnumerateInstanceExtensionProperties =
    118         (void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)(
    119             VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties");
    120     if (!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) {
    121         goto fail;
    122     }
    123     extensions = SDL_Vulkan_CreateInstanceExtensionsList(
    124         (PFN_vkEnumerateInstanceExtensionProperties)
    125             _this->vulkan_config.vkEnumerateInstanceExtensionProperties,
    126         &extensionCount);
    127     if (!extensions) {
    128         goto fail;
    129     }
    130     for (Uint32 i = 0; i < extensionCount; i++) {
    131         if (SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
    132             hasSurfaceExtension = SDL_TRUE;
    133         } else if (SDL_strcmp(VK_MVK_MACOS_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
    134             hasMacOSSurfaceExtension = SDL_TRUE;
    135         }
    136     }
    137     SDL_free(extensions);
    138     if (!hasSurfaceExtension) {
    139         SDL_SetError("Installed Vulkan Portability library doesn't implement the "
    140                      VK_KHR_SURFACE_EXTENSION_NAME " extension");
    141         goto fail;
    142     } else if (!hasMacOSSurfaceExtension) {
    143         SDL_SetError("Installed Vulkan Portability library doesn't implement the "
    144                      VK_MVK_MACOS_SURFACE_EXTENSION_NAME "extension");
    145         goto fail;
    146     }
    147     return 0;
    148 
    149 fail:
    150     SDL_UnloadObject(_this->vulkan_config.loader_handle);
    151     _this->vulkan_config.loader_handle = NULL;
    152     return -1;
    153 }
    154 
    155 void Cocoa_Vulkan_UnloadLibrary(_THIS)
    156 {
    157     if (_this->vulkan_config.loader_handle) {
    158         if (_this->vulkan_config.loader_handle != DEFAULT_HANDLE) {
    159             SDL_UnloadObject(_this->vulkan_config.loader_handle);
    160         }
    161         _this->vulkan_config.loader_handle = NULL;
    162     }
    163 }
    164 
    165 SDL_bool Cocoa_Vulkan_GetInstanceExtensions(_THIS,
    166                                           SDL_Window *window,
    167                                           unsigned *count,
    168                                           const char **names)
    169 {
    170     static const char *const extensionsForCocoa[] = {
    171         VK_KHR_SURFACE_EXTENSION_NAME, VK_MVK_MACOS_SURFACE_EXTENSION_NAME
    172     };
    173     if (!_this->vulkan_config.loader_handle) {
    174         SDL_SetError("Vulkan is not loaded");
    175         return SDL_FALSE;
    176     }
    177     return SDL_Vulkan_GetInstanceExtensions_Helper(
    178             count, names, SDL_arraysize(extensionsForCocoa),
    179             extensionsForCocoa);
    180 }
    181 
    182 SDL_bool Cocoa_Vulkan_CreateSurface(_THIS,
    183                                   SDL_Window *window,
    184                                   VkInstance instance,
    185                                   VkSurfaceKHR *surface)
    186 {
    187     PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
    188         (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr;
    189     PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK =
    190         (PFN_vkCreateMacOSSurfaceMVK)vkGetInstanceProcAddr(
    191                                             (VkInstance)instance,
    192                                             "vkCreateMacOSSurfaceMVK");
    193     VkMacOSSurfaceCreateInfoMVK createInfo = {};
    194     VkResult result;
    195     SDL_MetalView metalview;
    196 
    197     if (!_this->vulkan_config.loader_handle) {
    198         SDL_SetError("Vulkan is not loaded");
    199         return SDL_FALSE;
    200     }
    201 
    202     if (!vkCreateMacOSSurfaceMVK) {
    203         SDL_SetError(VK_MVK_MACOS_SURFACE_EXTENSION_NAME
    204                      " extension is not enabled in the Vulkan instance.");
    205         return SDL_FALSE;
    206     }
    207 
    208     metalview = Cocoa_Metal_CreateView(_this, window);
    209     if (metalview == NULL) {
    210         return SDL_FALSE;
    211     }
    212 
    213     createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
    214     createInfo.pNext = NULL;
    215     createInfo.flags = 0;
    216     createInfo.pView = (const void *)metalview;
    217     result = vkCreateMacOSSurfaceMVK(instance, &createInfo,
    218                                        NULL, surface);
    219     if (result != VK_SUCCESS) {
    220         Cocoa_Metal_DestroyView(_this, metalview);
    221         SDL_SetError("vkCreateMacOSSurfaceMVK failed: %s",
    222                      SDL_Vulkan_GetResultString(result));
    223         return SDL_FALSE;
    224     }
    225 
    226     /* Unfortunately there's no SDL_Vulkan_DestroySurface function we can call
    227      * Metal_DestroyView from. Right now the metal view's ref count is +2 (one
    228      * from returning a new view object in CreateView, and one because it's
    229      * a subview of the window.) If we release the view here to make it +1, it
    230      * will be destroyed when the window is destroyed. */
    231     CFBridgingRelease(metalview);
    232 
    233     return SDL_TRUE;
    234 }
    235 
    236 void Cocoa_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h)
    237 {
    238     Cocoa_Metal_GetDrawableSize(_this, window, w, h);
    239 }
    240 
    241 #endif
    242 
    243 /* vim: set ts=4 sw=4 expandtab: */