From 9ceac06c003b0bd2cc9005f200199b6393b9cc3d Mon Sep 17 00:00:00 2001 From: Karl Schultz Date: Tue, 12 Dec 2017 10:33:01 -0500 Subject: macOS: Add macOS support --- loader/CMakeLists.txt | 75 ++++++++++++++--- loader/LoaderAndLayerInterface.md | 167 +++++++++++++++++++++++++++----------- loader/loader.c | 47 +++++++++-- loader/loader.h | 6 ++ loader/vk_loader_platform.h | 2 +- loader/wsi.c | 163 ++++++++++++++++++++++++++++++++++++- loader/wsi.h | 13 ++- 7 files changed, 402 insertions(+), 71 deletions(-) (limited to 'loader') diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index 85282d03..779ebbd6 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -49,6 +49,8 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") add_definitions(-DVK_USE_PLATFORM_MIR_KHR) include_directories(${MIR_INCLUDE_DIR}) endif() +elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + add_definitions(-DVK_USE_PLATFORM_MACOS_MVK) else() message(FATAL_ERROR "Unsupported Platform!") endif() @@ -110,6 +112,11 @@ if (WIN32) set(OPT_LOADER_SRCS ${OPT_LOADER_SRCS} unknown_ext_chain.c) add_custom_target(loader_asm_gen_files) endif() +elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + # For MacOS, use the C code and force the compiler's tail-call optimization instead of using assembly code. + set(OPT_LOADER_SRCS ${OPT_LOADER_SRCS} unknown_ext_chain.c) + set_source_files_properties(${OPT_LOADER_SRCS} PROPERTIES COMPILE_FLAGS -O) + add_custom_target(loader_asm_gen_files) # This causes no assembly files to be generated. else() enable_language(ASM-ATT) set(CMAKE_ASM-ATT_COMPILE_FLAGS "${CMAKE_ASM-ATT_COMPILE_FLAGS} $ENV{ASFLAGS}") @@ -211,6 +218,7 @@ if (WIN32) COMMAND xcopy /Y /I ${COPY_SRC_PATH} ${COPY_DST_TEST_PATH}) else() + # Linux and MacOS set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wpointer-arith") # Clang (and not gcc) warns about redefining a typedef with the same types, so disable that warning. @@ -219,27 +227,70 @@ else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-typedef-redefinition") endif() - add_library(${API_LOWERCASE} SHARED ${NORMAL_LOADER_SRCS} ${OPT_LOADER_SRCS}) + add_library(${API_LOWERCASE} SHARED ${NORMAL_LOADER_SRCS} ${OPT_LOADER_SRCS} ${FRAMEWORK_HEADERS}) add_dependencies(${API_LOWERCASE} generate_helper_files loader_gen_files loader_asm_gen_files) target_compile_definitions(${API_LOWERCASE} PUBLIC -DLOADER_DYNAMIC_LIB) set_target_properties(${API_LOWERCASE} PROPERTIES SOVERSION "1" VERSION "1.0.${vk_header_version}") target_link_libraries(${API_LOWERCASE} -ldl -lpthread -lm) + if(APPLE) + find_library(COREFOUNDATION_LIBRARY NAMES CoreFoundation) + target_link_libraries(${API_LOWERCASE} "-framework CoreFoundation") + + # Build vulkan.framework + set(FRAMEWORK_HEADERS + ${PROJECT_SOURCE_DIR}/include/vulkan/vk_icd.h + ${PROJECT_SOURCE_DIR}/include/vulkan/vk_layer.h + ${PROJECT_SOURCE_DIR}/include/vulkan/vk_platform.h + ${PROJECT_SOURCE_DIR}/include/vulkan/vk_sdk_platform.h + ${PROJECT_SOURCE_DIR}/include/vulkan/vulkan.h + ${PROJECT_SOURCE_DIR}/include/vulkan/vulkan.hpp + ) + add_library(vulkan-framework SHARED ${NORMAL_LOADER_SRCS} ${OPT_LOADER_SRCS} ${FRAMEWORK_HEADERS}) + add_dependencies(vulkan-framework generate_helper_files loader_gen_files loader_asm_gen_files) + target_compile_definitions(vulkan-framework PUBLIC -DLOADER_DYNAMIC_LIB) + target_link_libraries(vulkan-framework -ldl -lpthread -lm "-framework CoreFoundation") + + # The FRAMEWORK_VERSION needs to be "A" here so that Xcode code-signing works when + # a user adds their framework to an Xcode project and does "Sign on Copy". + # It would have been nicer to use "1" to denote Vulkan 1. + # Although Apple docs say that a framework version does not have to be "A", + # this part of the Apple toolchain expects it. + # https://forums.developer.apple.com/thread/65963 + set_target_properties(vulkan-framework PROPERTIES + OUTPUT_NAME vulkan + FRAMEWORK TRUE + FRAMEWORK_VERSION A + VERSION "1.0.${vk_header_version}" # "current version" + SOVERSION "1.0.0" # "compatibility version" + MACOSX_FRAMEWORK_IDENTIFIER com.lunarg.vulkanFramework + PUBLIC_HEADER "${FRAMEWORK_HEADERS}" + ) + install(TARGETS vulkan-framework + PUBLIC_HEADER DESTINATION vulkan + FRAMEWORK DESTINATION loader + ) + endif(APPLE) + if(INSTALL_LVL_FILES) install(TARGETS ${API_LOWERCASE} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() - # Generate pkg-config file. - include(FindPkgConfig QUIET) - if(PKG_CONFIG_FOUND) - set(VK_API_VERSION "1.0.${vk_header_version}") - foreach(LIB ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES} ${PLATFORM_LIBS}) - set(PRIVATE_LIBS "${PRIVATE_LIBS} -l${LIB}") - endforeach() - configure_file("vulkan.pc.in" "vulkan.pc" @ONLY) - if(INSTALL_LVL_FILES) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/vulkan.pc" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + if(NOT APPLE) + # Generate pkg-config file. + include(FindPkgConfig QUIET) + if(PKG_CONFIG_FOUND) + set(VK_API_VERSION "1.0.${vk_header_version}") + foreach(LIB ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES} ${PLATFORM_LIBS}) + set(PRIVATE_LIBS "${PRIVATE_LIBS} -l${LIB}") + endforeach() + configure_file("vulkan.pc.in" "vulkan.pc" @ONLY) + if(INSTALL_LVL_FILES) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/vulkan.pc" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + endif() endif() endif() endif() + + diff --git a/loader/LoaderAndLayerInterface.md b/loader/LoaderAndLayerInterface.md index e61619c3..2e96ef6a 100644 --- a/loader/LoaderAndLayerInterface.md +++ b/loader/LoaderAndLayerInterface.md @@ -54,7 +54,7 @@ Vulkan is a layered architecture, made up of the following elements: ![High Level View of Loader](./images/high_level_loader.png) The general concepts in this document are applicable to the loaders available -for Windows, Linux and Android based systems. +for Windows, Linux, Android and MacOS based systems. #### Who Should Read This Document @@ -292,7 +292,7 @@ loader. ##### Vulkan Direct Exports -The loader library on Windows, Linux and Android will export all core Vulkan +The loader library on Windows, Linux, Android and MacOS will export all core Vulkan and all appropriate Window System Interface (WSI) extensions. This is done to make it simpler to get started with Vulkan development. When an application links directly to the loader library in this way, the Vulkan calls are simple @@ -304,7 +304,8 @@ object they are given. ###### Dynamic Linking The loader is ordinarily distributed as a dynamic library (.dll on Windows or -.so on Linux) which gets installed to the system path for dynamic libraries. +.so on Linux or .dylib on MacOS) which gets installed to the system path +for dynamic libraries. Linking to the dynamic library is generally the preferred method of linking to the loader, as doing so allows the loader to be updated for bug fixes and improvements. Furthermore, the dynamic library is generally installed to Windows @@ -363,8 +364,8 @@ view of an Instance call chain with 3 enabled layers: ![Instance Call Chain](./images/loader_instance_chain.png) This is also how a Vulkan Device function call chain looks if you query it -using `vkGetInstanceProcAddr`. On the otherhand, a Device -function doesn't need to worry about the broadcast becuase it knows specifically +using `vkGetInstanceProcAddr`. On the other hand, a Device +function doesn't need to worry about the broadcast because it knows specifically which associated ICD and which associated Physical Device the call should terminate at. Because of this, the loader doesn't need to get involved between any enabled layers and the ICD. Thus, if you used a loader-exported Vulkan @@ -415,11 +416,12 @@ in the windows/system32 directory (on 64-bit Windows installs, the 32-bit version of the loader with the same name can be found in the windows/sysWOW64 directory). -For Linux, shared libraries are versioned based on a suffix. Thus, the ABI +For Linux and MacOS, shared libraries are versioned based on a suffix. Thus, the ABI number is not encoded in the base of the library filename as on Windows. On Linux an application wanting to link to the latest Vulkan ABI version would just link to the name vulkan (libvulkan.so). A specific Vulkan ABI version can also be linked to by applications (e.g. libvulkan.so.1). +On MacOS, the libraries are libvulkan.dylib abd libvulkan.1.dylib. #### Application Layer Usage @@ -519,8 +521,8 @@ Implicit layers have an additional requirement over explicit layers in that they require being able to be disabled by an environmental variable. This is due to the fact that they are not visible to the application and could cause issues. A good principle to keep in mind would be to define both an enable and disable -environment variable so the users can deterministicly enable the functionality. -On Desktop platforms (Windows and Linux), these enable/disable settings are +environment variable so the users can deterministically enable the functionality. +On Desktop platforms (Windows, Linux, and MacOS), these enable/disable settings are defined in the layer's JSON file. Discovery of system-installed implicit and explicit layers is described later in @@ -533,6 +535,7 @@ system, as shown in the table below. | Windows | Implicit Layers are located in a different Windows registry location than Explicit Layers. | | Linux | Implicit Layers are located in a different directory location than Explicit Layers. | | Android | There is **No Support For Implicit Layers** on Android. | +| MacOS | Implicit Layers are located in a different directory location than Explicit Layers. | ##### Forcing Layer Source Folders @@ -541,10 +544,10 @@ Developers may need to use special, pre-production layers, without modifying the system-installed layers. You can direct the loader to look for layers in a specific folder by defining the "VK\_LAYER\_PATH" environment variable. This will override the mechanism used for finding system-installed layers. Because -layers of interest may exist in several disinct folders on a system, this -environment variable can containis several paths seperated by the operating +layers of interest may exist in several distinct folders on a system, this +environment variable can contains several paths separated by the operating specific path separator. On Windows, each separate folder should be separated -in the list using a semi-colon. On Linux, each folder name should be separated +in the list using a semi-colon. On Linux and MacOS, each folder name should be separated using a colon. If "VK\_LAYER\_PATH" exists, **only** the folders listed in it will be scanned @@ -552,13 +555,13 @@ for layers. Each directory listed should be the full pathname of a folder containing layer manifest files. -##### Forcing Layers to be Enabled on Windows and Linux +##### Forcing Layers to be Enabled on Windows, Linux and MacOS Developers may want to enable layers that are not enabled by the given -application they are using. On Linux and Windows, the environment variable +application they are using. On desktop systems, the environment variable "VK\_INSTANCE\_LAYERS" can be used to enable additional layers which are not specified (enabled) by the application at `vkCreateInstance`. -"VK\_INSTANCE\_LAYERS" is a colon (Linux)/semi-colon (Windows) separated +"VK\_INSTANCE\_LAYERS" is a colon (Linux and MacOS)/semi-colon (Windows) separated list of layer names to enable. Order is relevant with the first layer in the list being the top-most layer (closest to the application) and the last layer in the list being the bottom-most layer (closest to the driver). @@ -571,7 +574,7 @@ layers. Layers specified via environment variable are top-most (closest to the application) while layers specified by the application are bottommost. An example of using these environment variables to activate the validation -layer `VK_LAYER_LUNARG_parameter_validation` on Windows or Linux is as follows: +layer `VK_LAYER_LUNARG_parameter_validation` on Windows, Linux or MacOS is as follows: ``` > $ export VK_INSTANCE_LAYERS=VK_LAYER_LUNARG_parameter_validation @@ -666,7 +669,7 @@ Khronos approved WSI extensions are available and provide Windows System Integration support for various execution environments. It is important to understand that some WSI extensions are valid for all targets, but others are particular to a given execution environment (and loader). This desktop loader -(currently targeting Windows and Linux) only enables and directly exports those +(currently targeting Windows, Linux, and MacOS) only enables and directly exports those WSI extensions that are appropriate to the current environment. For the most part, the selection is done in the loader using compile-time preprocessor flags. All versions of the desktop loader currently expose at least the following WSI @@ -684,6 +687,7 @@ specific extensions: | Linux (Default) | VK_KHR_xcb_surface and VK_KHR_xlib_surface | | Linux (Wayland) | VK_KHR_wayland_surface | | Linux (Mir) | VK_KHR_mir_surface | +| MacOS (MoltenVK) | VK_MVK_macos_surface | **NOTE:** Wayland and Mir targets are not fully supported at this time. Wayland support is present, but should be considered Beta quality. Mir support is not @@ -708,7 +712,7 @@ With the ability to expand Vulkan so easily, extensions will be created that the loader knows nothing about. If the extension is a device extension, the loader will pass the unknown entry-point down the device call chain ending with the appropriate ICD entry-points. The same thing will happen, if the extension is -an instance extension which takes a physical device paramater as it's first +an instance extension which takes a physical device parameter as it's first component. However, for all other instance extensions the loader will fail to load it. @@ -743,7 +747,7 @@ For the above reasons, the loader will filter out the names of these unknown ins extensions when an application calls `vkEnumerateInstanceExtensionProperties`. Additionally, this behavior will cause the loader to throw an error during `vkCreateInstance` if you still attempt to use one of these extensions. The intent is -to protect applications so that they don't inadvertantly use functionality +to protect applications so that they don't inadvertently use functionality which could lead to a crash. On the other-hand, if you know you can safely use the extension, you may disable @@ -762,6 +766,7 @@ In this section we'll discuss how the loader interacts with layers, including: * [Android Layer Discovery](#android-layer-discovery) * [Windows Layer Discovery](#windows-layer-discovery) * [Linux Layer Discovery](#linux-layer-discovery) + * [MacOS Layer Discovery](#macos-layer-discovery) * [Layer Version Negotiation](#layer-version-negotiation) * [Layer Call Chains and Distributed Dispatch](#layer-call-chains-and-distributed-dispatch) * [Layer Unknown Physical Device Extensions](#layer-unknown-physical-device-extensions) @@ -796,7 +801,7 @@ layers can be categorized into two categories: * Explicit Layers The main difference between the two is that Implicit Layers are automatically -enabled, unless overriden, and Explicit Layers must be enabled. Remember, +enabled, unless overridden, and Explicit Layers must be enabled. Remember, Implicit Layers are not present on all Operating Systems (like Android). On any system, the loader looks in specific areas for information on the @@ -815,7 +820,7 @@ follow, especially with regards to interacting with the loader and other layers. ##### Layer Manifest File Usage -On Windows and Linux systems, JSON formatted manifest files are used to store +On Windows, Linux, and MacOS systems, JSON formatted manifest files are used to store layer information. In order to find system-installed layers, the Vulkan loader will read the JSON files to identify the names and attributes of layers and their extensions. The use of manifest files allows the loader to avoid loading @@ -890,7 +895,7 @@ which case the value will be interpreted as a list of paths to JSON manifest fil In general, applications should install layers into the `SOFTWARE\Khrosos\Vulkan` paths. The PnP registry locations are intended specifically for layers that are -distrubuted as part of a driver installation. An application installer should not +distributed as part of a driver installation. An application installer should not modify the device-specific registries, while a device driver should not modify the system wide registries. @@ -919,7 +924,7 @@ directories: $HOME/.local/share/vulkan/explicit_layer.d $HOME/.local/share/vulkan/implicit_layer.d -Of course, ther are some things you have to know about the above folders: +Of course, there are some things you have to know about the above folders: 1. The "/usr/local/*" directories can be configured to be other directories at build time. 2. $HOME is the current home directory of the application's user id; this path @@ -937,6 +942,33 @@ environment variables are only used for non-suid programs. See [Forcing Layer Source Folders](#forcing-layer-source-folders) for more information on this. +##### MacOS Layer Discovery + +On MacOS, the Vulkan loader will scan the files in the following directories: + + /Contents/Resources/vulkan/explicit_layer.d + /Contents/Resources/vulkan/implicit_layer.d + /etc/vulkan/explicit_layer.d + /etc/vulkan/implicit_layer.d + /usr/local/share/vulkan/explicit_layer.d + /usr/local/share/vulkan/implicit_layer.d + /usr/share/vulkan/explicit_layer.d + /usr/share/vulkan/implicit_layer.d + $HOME/.local/share/vulkan/explicit_layer.d + $HOME/.local/share/vulkan/implicit_layer.d + +1. <bundle> is the directory containing a bundled application. It is scanned first. +1. The "/usr/local/*" directories can be configured to be other directories at +build time. +1. $HOME is the current home directory of the application's user id; this path +will be ignored for suid programs. + +As on Windows, if VK\_LAYER\_PATH is defined, then the +loader will instead look at the paths defined by that variable instead of using +the information provided by these default paths. However, these +environment variables are only used for non-suid programs. See +[Forcing Layer Source Folders](#forcing-layer-source-folders) for more +information on this. #### Layer Version Negotiation @@ -969,11 +1001,11 @@ provided for this interface in include/vulkan/vk_layer.h: You'll notice the `VkNegotiateLayerInterface` structure is similar to other Vulkan structures. The "sType" field, in this case takes a new enum defined just for internal loader/layer interfacing use. The valid values for "sType" -could grow in the future, but right only havs the one value +could grow in the future, but right now only has the one value "LAYER_NEGOTIATE_INTERFACE_STRUCT". This function (`vkNegotiateLoaderLayerInterfaceVersion`) should be exported by -the layer so that using "GetProcAddress" on Windows or "dlsym" on Linux, should +the layer so that using "GetProcAddress" on Windows or "dlsym" on Linux or MacOS, should return a valid function pointer to it. Once the loader has grabbed a valid address to the layers function, the loader will create a variable of type `VkNegotiateLayerInterface` and initialize it in the following ways: @@ -1015,7 +1047,7 @@ If the layer supports the new interface and reports version 2 or greater, then the loader will use the “fpGetInstanceProcAddr” and “fpGetDeviceProcAddr” functions from the “VkNegotiateLayerInterface” structure. Prior to these changes, the loader would query each of those functions using "GetProcAddress" -on Windows or "dlsym" on Linux. +on Windows or "dlsym" on Linux or MacOS. #### Layer Call Chains and Distributed Dispatch @@ -1423,7 +1455,7 @@ a meta-layer's component layers, and report them as the meta-layer's properties to the application when queried. Restrictions to defining and using a meta-layer are: - 1. A Meta-layer Manifest file **must** be a properly formated that contains one + 1. A Meta-layer Manifest file **must** be a properly formatted that contains one or more component layers. 3. All component layers **must be** present on a system for the meta-layer to be used. @@ -1676,7 +1708,7 @@ dispatch pointer from the `VkDevice` object, which is the parent of the #### Layer Manifest File Format -On Windows and Linux (desktop), the loader uses manifest files to discover +On Windows, Linux and MacOS (desktop), the loader uses manifest files to discover layer libraries and layers. The desktop loader doesn't directly query the layer library except during chaining. This is to reduce the likelihood of loading a malicious layer into memory. Instead, details are read from the @@ -1779,7 +1811,7 @@ Here's an example of a meta-layer manifest file: | "name" | The string used to uniquely identify this layer to applications. | vkEnumerateInstanceLayerProperties | | "type" | This field indicates the type of layer. The values can be: GLOBAL, or INSTANCE | vkEnumerate*LayerProperties | | | **NOTES:** Prior to deprecation, the "type" node was used to indicate which layer chain(s) to activate the layer upon: instance, device, or both. Distinct instance and device layers are deprecated; there are now just layers. Allowable values for type (both before and after deprecation) are "INSTANCE", "GLOBAL" and, "DEVICE." "DEVICE" layers are skipped over by the loader as if they were not found. | | -| "library\_path" | The "library\_path" specifies either a filename, a relative pathname, or a full pathname to a layer shared library file. If "library\_path" specifies a relative pathname, it is relative to the path of the JSON manifest file (e.g. for cases when an application provides a layer that is in the same folder hierarchy as the rest of the application files). If "library\_path" specifies a filename, the library must live in the system's shared object search path. There are no rules about the name of the layer shared library files other than it should end with the appropriate suffix (".DLL" on Windows, and ".so" on Linux). **This field must not be present if "component_layers" is defined** | N/A | +| "library\_path" | The "library\_path" specifies either a filename, a relative pathname, or a full pathname to a layer shared library file. If "library\_path" specifies a relative pathname, it is relative to the path of the JSON manifest file (e.g. for cases when an application provides a layer that is in the same folder hierarchy as the rest of the application files). If "library\_path" specifies a filename, the library must live in the system's shared object search path. There are no rules about the name of the layer shared library files other than it should end with the appropriate suffix (".DLL" on Windows, ".so" on Linux, and ".dylib" on MacOS). **This field must not be present if "component_layers" is defined** | N/A | | "api\_version" | The major.minor.patch version number of the Vulkan API that the shared library file for the library was built against. For example: 1.0.33. | vkEnumerateInstanceLayerProperties | | "implementation_version" | The version of the layer implemented. If the layer itself has any major changes, this number should change so the loader and/or application can identify it properly. | vkEnumerateInstanceLayerProperties | | "description" | A high-level description of the layer and it's intended use. | vkEnumerateInstanceLayerProperties | @@ -1868,7 +1900,7 @@ the concept of [Layer Unknown Physical Device Extensions](#layer-unknown-physical-device- extensions) and the associated `vk_layerGetPhysicalDeviceProcAddr` function. Finally, it -changed the manifest file defition to 1.1.0. +changed the manifest file definition to 1.1.0. ##### Layer Library API Version 1 @@ -1939,7 +1971,8 @@ ICD to properly hand-shake. * [ICD Manifest File Usage](#icd-manifest-file-usage) * [ICD Discovery on Windows](#icd-discovery-on-windows) * [ICD Discovery on Linux](#icd-discovery-on-linux) - * [Using Pre-Production ICDs on Windows and Linux](#using-pre-production-icds-on-windows-and-linux) + * [ICD Discovery on MacOS](#icd-discovery-on-macos) + * [Using Pre-Production ICDs on Windows, Linux and MacOS](#using-pre-production-icds-on-windows-and-linux) * [ICD Discovery on Android](#icd-discovery-on-android) * [ICD Manifest File Format](#icd-manifest-file-format) * [ICD Manifest File Versions](#icd-manifest-file-versions) @@ -1949,7 +1982,7 @@ ICD to properly hand-shake. * [ICD Dispatchable Object Creation](#icd-dispatchable-object-creation) * [Handling KHR Surface Objects in WSI Extensions](#handling-khr-surface-objects-in-wsi-extensions) * [Loader and ICD Interface Negotiation](#loader-and-icd-interface-negotiation) - * [Windows and Linux ICD Negotiation](#windows-and-linux-icd-negotiation) + * [Windows, Linux, and MacOS ICD Negotiation](#windows-and-linux-icd-negotiation) * [Version Negotiation Between Loader and ICDs](#version-negotiation-between-loader-and-icds) * [Interfacing With Legacy ICDs or Loader](#interfacing-with-legacy-icds-or-loader) * [Loader Version 5 Interface Requirements](#loader-version-5-interface-requirements) @@ -1968,7 +2001,7 @@ responsible for discovering available Vulkan ICDs on the system. Given a list of available ICDs, the loader can enumerate all the physical devices available for an application and return this information to the application. The process in which the loader discovers the available Installable Client Drivers (ICDs) -on a system is platform dependent. Windows, Linux and Android ICD discovery +on a system is platform dependent. Windows, Linux, Android, and MacOS ICD discovery details are listed below. #### Overriding the Default ICD Usage @@ -2001,10 +2034,18 @@ export VK_ICD_FILENAMES=/home/user/dev/mesa/share/vulkan/icd.d/intel_icd.x86_64. This is an example which is using the `VK_ICD_FILENAMES` override on Linux to point to the Intel Mesa driver's ICD Manifest file. +##### On MacOS + +``` +export VK_ICD_FILENAMES=/home/user/MoltenVK/Package/Latest/MoltenVK/macOS/MoltenVK_icd.json +``` + +This is an example which is using the `VK_ICD_FILENAMES` override on MacOS to point +to an installation and build of the MoltenVK GitHub repository that contains the MoltenVK ICD. #### ICD Manifest File Usage -As with layers, on Windows and Linux systems, JSON formatted manifest files are +As with layers, on Windows, Linux and MacOS systems, JSON formatted manifest files are used to store ICD information. In order to find system-installed drivers, the Vulkan loader will read the JSON files to identify the names and attributes of each driver. One thing you will notice is that ICD Manifest files are much @@ -2122,6 +2163,38 @@ pathname of an ICD shared library (".so") file. See the [ICD Manifest File Format](#icd-manifest-file-format) section for more details. +#### ICD Discovery on MacOS + +In order to find installed ICDs, the Vulkan loader will scan the files +in the following directories: + +``` + /Contents/Resources/vulkan/icd.d + /etc/vulkan/icd.d + /usr/local/share/vulkan/icd.d + /usr/share/vulkan/icd.d + $HOME/.local/share/vulkan/icd.d +``` + +The "/usr/local/*" directories can be configured to be other directories at +build time. + +The typical usage of the directories is indicated in the table below. + +| Location | Details | +|-------------------|------------------------| +| <bundle>/Contents/Resources/vulkan/icd.d | Directory for ICDs that are bundled with the application (searched first) | +| "/etc/vulkan/icd.d" | Location of ICDs installed manually | +| "/usr/local/share/vulkan/icd.d" | Directory for locally built ICDs | +| "/usr/share/vulkan/icd.d" | Location of ICDs installed from packages | +| $HOME/.local/share/vulkan/icd.d | $HOME is the current home directory of the application's user id; this path will be ignored for suid programs | + +The Vulkan loader will open each manifest file found to obtain the name or +pathname of an ICD shared library (".dylib") file. + +See the [ICD Manifest File Format](#icd-manifest-file-format) section for more +details. + ##### Additional Settings For ICD Debugging If you are seeing issues which may be related to the ICD. A possible option to debug is to enable the @@ -2130,7 +2203,7 @@ there is a problem with an ICD missing symbols on your system, this will expose to fail on loading the ICD. It is recommended that you enable `LD_BIND_NOW` along with `VK_LOADER_DEBUG=warn` to expose any issues. -#### Using Pre-Production ICDs on Windows and Linux +#### Using Pre-Production ICDs on Windows, Linux and MacOS Independent Hardware Vendor (IHV) pre-production ICDs. In some cases, a pre-production ICD may be in an installable package. In other cases, a @@ -2144,13 +2217,13 @@ other words, only the ICDs listed in "VK\_ICD\_FILENAMES" will be used. The "VK\_ICD\_FILENAMES" environment variable is a list of ICD manifest files, containing the full path to the ICD JSON Manifest file. This -list is colon-separated on Linux, and semi-colon separated on Windows. +list is colon-separated on Linux and MacOS, and semi-colon separated on Windows. Typically, "VK\_ICD\_FILENAMES" will only contain a full pathname to one info file for a developer-built ICD. A separator (colon or semi-colon) is only used if more than one ICD is listed. -**NOTE:** On Linux, this environment variable will be ignored for suid programs. +**NOTE:** On Linux and MacOS, this environment variable will be ignored for suid programs. #### ICD Discovery on Android @@ -2183,7 +2256,7 @@ Here is an example ICD JSON Manifest file: |----------------|--------------------| | "file\_format\_version" | The JSON format major.minor.patch version number of this file. Currently supported version is 1.0.0. | | "ICD" | The identifier used to group all ICD information together. | -| "library_path" | The "library\_path" specifies either a filename, a relative pathname, or a full pathname to a layer shared library file. If "library\_path" specifies a relative pathname, it is relative to the path of the JSON manifest file. If "library\_path" specifies a filename, the library must live in the system's shared object search path. There are no rules about the name of the ICD shared library files other than it should end with the appropriate suffix (".DLL" on Windows, and ".so" on Linux). | N/A | +| "library_path" | The "library\_path" specifies either a filename, a relative pathname, or a full pathname to a layer shared library file. If "library\_path" specifies a relative pathname, it is relative to the path of the JSON manifest file. If "library\_path" specifies a filename, the library must live in the system's shared object search path. There are no rules about the name of the ICD shared library files other than it should end with the appropriate suffix (".DLL" on Windows, ".so" on Linux and "*.dylib" on MacOS). | N/A | | "api_version" | The major.minor.patch version number of the Vulkan API that the shared library files for the ICD was built against. For example: 1.0.33. | **NOTE:** If the same ICD shared library supports multiple, incompatible @@ -2373,9 +2446,10 @@ vkObj alloc_icd_obj() ### Handling KHR Surface Objects in WSI Extensions Normally, ICDs handle object creation and destruction for various Vulkan -objects. The WSI surface extensions for Linux and Windows +objects. The WSI surface extensions for Linux, Windows, and MacOS ("VK\_KHR\_win32\_surface", "VK\_KHR\_xcb\_surface", "VK\_KHR\_xlib\_surface", -"VK\_KHR\_mir\_surface", "VK\_KHR\_wayland\_surface", and "VK\_KHR\_surface") +"VK\_KHR\_mir\_surface", "VK\_KHR\_wayland\_surface", "VK\_MVK\_macos\_surface" +and "VK\_KHR\_surface") are handled differently. For these extensions, the `VkSurfaceKHR` object creation and destruction may be handled by either the loader, or an ICD. @@ -2390,6 +2464,7 @@ If the loader handles the management of the `VkSurfaceKHR` objects: * Xlib * Windows * Android + * MacOS (`vkCreateMacOSSurfaceMVK`) 2. The loader creates a `VkIcdSurfaceXXX` object for the corresponding `vkCreateXXXSurfaceKHR` call. * The `VkIcdSurfaceXXX` structures are defined in `include/vulkan/vk_icd.h`. @@ -2418,7 +2493,7 @@ associated with multiple ICDs. Therefore, when the loader receives the object. This object acts as a container for each ICD's version of the `VkSurfaceKHR` object. If an ICD does not support the creation of its own `VkSurfaceKHR` object, the loader's container stores a NULL for that ICD. On -the otherhand, if the ICD does support `VkSurfaceKHR` creation, the loader will +the other hand, if the ICD does support `VkSurfaceKHR` creation, the loader will make the appropriate `vkCreateXXXSurfaceKHR` call to the ICD, and store the returned pointer in it's container object. The loader then returns the `VkSurfaceIcdXXX` as a `VkSurfaceKHR` object back up the call chain. Finally, @@ -2434,10 +2509,10 @@ viewed as a pass through. That is, the loader generally doesn't modify the functions or their parameters, but simply calls the ICDs entry-point for that function. There are specific additional interface requirements an ICD needs to comply with that are not part of any requirements from the Vulkan specification. -These addtional requirements are versioned to allow flexibility in the future. +These additional requirements are versioned to allow flexibility in the future. -#### Windows and Linux ICD Negotiation +#### Windows, Linux and MacOS ICD Negotiation ##### Version Negotiation Between Loader and ICDs @@ -2604,7 +2679,7 @@ The Android loader uses the same protocol for initializing the dispatch table as described above. The only difference is that the Android loader queries layer and extension information directly from the respective libraries and does not use the json manifest files used -by the Windows and Linux loaders. +by the Windows, Linux and MacOS loaders. ## Table of Debug Environment Variables @@ -2617,7 +2692,7 @@ of discovery. | VK_ICD_FILENAMES | Force the loader to use the specific ICD JSON files. The value should contain a list of delimited full path listings to ICD JSON Manifest files. **NOTE:** If you fail to use the global path to a JSON file, you may encounter issues. | `export VK_ICD_FILENAMES=\intel.json:\amd.json`

`set VK_ICD_FILENAMES=\nvidia.json;\mesa.json` | | VK_INSTANCE_LAYERS | Force the loader to add the given layers to the list of Enabled layers normally passed into `vkCreateInstance`. These layers are added first, and the loader will remove any duplicate layers that appear in both this list as well as that passed into `ppEnabledLayerNames`. | `export VK_INSTANCE_LAYERS=:`

`set VK_INSTANCE_LAYERS=;` | | VK_LAYER_PATH | Override the loader's standard Layer library search folders and use the provided delimited folders to search for layer Manifest files. | `export VK_LAYER_PATH=:`

`set VK_LAYER_PATH=;` | -| VK_LOADER_DISABLE_INST_EXT_FILTER | Disable the filtering out of instance extensions that the loader doesn't know about. This will allow applications to enable instance extensions exposed by ICDs but that the loader has no support for. **NOTE:** This may cause the loader or applciation to crash. | `export VK_LOADER_DISABLE_INST_EXT_FILTER=1`

`set VK_LOADER_DISABLE_INST_EXT_FILTER=1` | +| VK_LOADER_DISABLE_INST_EXT_FILTER | Disable the filtering out of instance extensions that the loader doesn't know about. This will allow applications to enable instance extensions exposed by ICDs but that the loader has no support for. **NOTE:** This may cause the loader or application to crash. | `export VK_LOADER_DISABLE_INST_EXT_FILTER=1`

`set VK_LOADER_DISABLE_INST_EXT_FILTER=1` | | VK_LOADER_DEBUG | Enable loader debug messages. Options are:
- error (only errors)
- warn (warnings and errors)
- info (info, warning, and errors)
- debug (debug + all before)
-all (report out all messages) | `export VK_LOADER_DEBUG=all`

`set VK_LOADER_DEBUG=warn` | ## Glossary of Terms @@ -2625,11 +2700,11 @@ of discovery. | Field Name | Field Value | |:---:|--------------------| | Android Loader | The loader designed to work primarily for the Android OS. This is generated from a different code-base than the desktop loader. But, in all important aspects, should be functionally equivalent. | -| Desktop Loader | The loader designed to work on both Windows and Linux. This is generated from a different [code-base](#https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers) than the Android loader. But in all important aspects, should be functionally equivalent. | +| Desktop Loader | The loader designed to work on Windows, Linux and MacOS. This is generated from a different [code-base](#https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers) than the Android loader. But in all important aspects, should be functionally equivalent. | | Core Function | A function that is already part of the Vulkan core specification and not an extension. For example, vkCreateDevice(). | | Device Call Chain | The call chain of functions followed for device functions. This call chain for a device function is usually as follows: first the application calls into a loader trampoline, then the loader trampoline calls enabled layers, the final layer calls into the ICD specific to the device. See the [Dispatch Tables and Call Chains](#dispatch-tables-and-call-chains) section for more information | | Device Function | A Device function is any Vulkan function which takes a `VkDevice`, `VkQueue`, `VkCommandBuffer`, or any child of these, as its first parameter. Some Vulkan Device functions are: `vkQueueSubmit`, `vkBeginCommandBuffer`, `vkCreateEvent`. See the [Instance Versus Device](#instance-versus-device) section for more information. | -| Discovery | The process of the loader searching for ICD and Layer files to setup the internal list of Vulkan objects available. On Windows/Linux, the discovery process typically focuses on searching for Manifest files. While on Android, the process focuses on searching for library files. | +| Discovery | The process of the loader searching for ICD and Layer files to setup the internal list of Vulkan objects available. On Windows/Linux/MacOS, the discovery process typically focuses on searching for Manifest files. While on Android, the process focuses on searching for library files. | | Dispatch Table | An array of function pointers (including core and possibly extension functions) used to step to the next entity in a call chain. The entity could be the loader, a layer or an ICD. See [Dispatch Tables and Call Chains](#dispatch-tables-and-call-chains) for more information. | | Extension | A concept of Vulkan used to expand the core Vulkan functionality. Extensions may be IHV-specific, platform-specific, or more broadly available. You should always query if an extension exists, and enable it during `vkCreateInstance` (if it is an instance extension) or during `vkCreateDevice` (if it is a device extension). | | ICD | Acronym for Installable Client Driver. These are drivers that are provided by IHVs to interact with the hardware they provide. See [Installable Client Drivers](#installable-client-drivers) section for more information. diff --git a/loader/loader.c b/loader/loader.c index 9fc764d2..766711ca 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -32,7 +32,10 @@ #include #include #include - +#if defined(__APPLE__) +#include +#include +#endif #include #if defined(_WIN32) #include "dirent_on_windows.h" @@ -205,7 +208,7 @@ void *loader_device_heap_realloc(const struct loader_device *device, void *pMemo } // Environment variables -#if defined(__linux__) +#if defined(__linux__) || defined(__APPLE__) static inline char *loader_getenv(const char *name, const struct loader_instance *inst) { // No allocation of memory necessary for Linux, but we should at least touch @@ -215,13 +218,22 @@ static inline char *loader_getenv(const char *name, const struct loader_instance } static inline char *loader_secure_getenv(const char *name, const struct loader_instance *inst) { - // No allocation of memory necessary for Linux, but we should at least touch - // the inst pointer to get rid of compiler warnings. - (void)inst; - +#if defined(__APPLE__) + // Apple does not appear to have a secure getenv implementation. + // The main difference between secure getenv and getenv is that secure getenv + // returns NULL if the process is being run with elevated privileges by a normal user. + // The idea is to prevent the reading of malicious environment variables by a process + // that can do damage. + // This algorithm is derived from glibc code that sets an internal + // variable (__libc_enable_secure) if the process is running under setuid or setgid. + return geteuid() != getuid() || getegid() != getgid() ? NULL : loader_getenv(name, inst); +#else +// Linux #ifdef HAVE_SECURE_GETENV + (void)inst; return secure_getenv(name); #elif defined(HAVE___SECURE_GETENV) + (void)inst; return __secure_getenv(name); #else #pragma message( \ @@ -229,6 +241,7 @@ static inline char *loader_secure_getenv(const char *name, const struct loader_i " updating to a different libc.") return loader_getenv(name, inst); #endif +#endif } static inline void loader_free_getenv(char *val, const struct loader_instance *inst) { @@ -2976,7 +2989,6 @@ static VkResult loader_get_manifest_files(const struct loader_instance *inst, co override = override_getenv = loader_secure_getenv(env_override, inst); } } - #if !defined(_WIN32) if (relative_location == NULL) { #else @@ -3016,6 +3028,10 @@ static VkResult loader_get_manifest_files(const struct loader_instance *inst, co #if defined(EXTRASYSCONFDIR) loc_size += strlen(EXTRASYSCONFDIR) + rel_size + 1; #endif +#if defined(__APPLE__) + // For bundle path + loc_size += MAXPATHLEN; +#endif #else loc_size += strlen(location) + 1; #endif @@ -3033,6 +3049,23 @@ static VkResult loader_get_manifest_files(const struct loader_instance *inst, co const char *loc_read; size_t start, stop; +#if defined(__APPLE__) + // Add the bundle's Resources dir to the beginning of the search path. + // Looks for manifests in the bundle first, before any system directories. + CFBundleRef main_bundle = CFBundleGetMainBundle(); + if (NULL != main_bundle) { + CFURLRef ref = CFBundleCopyResourcesDirectoryURL(main_bundle); + if (NULL != ref) { + if (CFURLGetFileSystemRepresentation(ref, TRUE, (UInt8 *)loc_write, loc_size)) { + loc_write += strlen(loc_write); + memcpy(loc_write, relative_location, rel_size); + loc_write += rel_size; + *loc_write++ = PATH_SEPARATOR; + } + CFRelease(ref); + } + } +#endif loc_read = &xdgconfdirs[0]; start = 0; while (loc_read[start] != '\0') { diff --git a/loader/loader.h b/loader/loader.h index 58dfefed..852417d1 100644 --- a/loader/loader.h +++ b/loader/loader.h @@ -296,6 +296,12 @@ struct loader_instance { #endif #ifdef VK_USE_PLATFORM_ANDROID_KHR bool wsi_android_surface_enabled; +#endif +#ifdef VK_USE_PLATFORM_MACOS_MVK + bool wsi_macos_surface_enabled; +#endif +#ifdef VK_USE_PLATFORM_IOS_MVK + bool wsi_ios_surface_enabled; #endif bool wsi_display_enabled; }; diff --git a/loader/vk_loader_platform.h b/loader/vk_loader_platform.h index 2b30c719..41625602 100644 --- a/loader/vk_loader_platform.h +++ b/loader/vk_loader_platform.h @@ -31,7 +31,7 @@ #include "vulkan/vk_platform.h" #include "vulkan/vk_sdk_platform.h" -#if defined(__linux__) +#if defined(__linux__) || defined(__APPLE__) /* Linux-specific common code: */ // Headers: diff --git a/loader/wsi.c b/loader/wsi.c index 131ca518..5de33451 100644 --- a/loader/wsi.c +++ b/loader/wsi.c @@ -55,6 +55,12 @@ void wsi_create_instance(struct loader_instance *ptr_instance, const VkInstanceC #ifdef VK_USE_PLATFORM_ANDROID_KHR ptr_instance->wsi_android_surface_enabled = false; #endif // VK_USE_PLATFORM_ANDROID_KHR +#ifdef VK_USE_PLATFORM_MACOS_MVK + ptr_instance->wsi_macos_surface_enabled = false; +#endif // VK_USE_PLATFORM_MACOS_MVK +#ifdef VK_USE_PLATFORM_IOS_MVK + ptr_instance->wsi_ios_surface_enabled = false; +#endif // VK_USE_PLATFORM_IOS_MVK ptr_instance->wsi_display_enabled = false; @@ -99,6 +105,18 @@ void wsi_create_instance(struct loader_instance *ptr_instance, const VkInstanceC continue; } #endif // VK_USE_PLATFORM_ANDROID_KHR +#ifdef VK_USE_PLATFORM_MACOS_MVK + if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_MVK_MACOS_SURFACE_EXTENSION_NAME) == 0) { + ptr_instance->wsi_macos_surface_enabled = true; + continue; + } +#endif // VK_USE_PLATFORM_MACOS_MVK +#ifdef VK_USE_PLATFORM_IOS_MVK + if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_MVK_IOS_SURFACE_EXTENSION_NAME) == 0) { + ptr_instance->wsi_ios_surface_enabled = true; + continue; + } +#endif // VK_USE_PLATFORM_IOS_MVK if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_DISPLAY_EXTENSION_NAME) == 0) { ptr_instance->wsi_display_enabled = true; continue; @@ -378,8 +396,7 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR(VkDevice devic } VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkSwapchainKHR *pSwapchain) { + const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) { uint32_t icd_index = 0; struct loader_device *dev; struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index); @@ -1066,7 +1083,6 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateAndroidSurfaceKHR(VkInstance ins } pIcdSurface->base.platform = VK_ICD_WSI_PLATFORM_ANDROID; - pIcdSurface->dpy = dpy; pIcdSurface->window = window; *pSurface = (VkSurfaceKHR)pIcdSurface; @@ -1076,6 +1092,129 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateAndroidSurfaceKHR(VkInstance ins #endif // VK_USE_PLATFORM_ANDROID_KHR +#ifdef VK_USE_PLATFORM_MACOS_MVK + +// Functions for the VK_MVK_macos_surface extension: + +// This is the trampoline entrypoint for CreateMacOSSurfaceMVK +LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateMacOSSurfaceMVK(VkInstance instance, + const VkMacOSSurfaceCreateInfoMVK *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkSurfaceKHR *pSurface) { + const VkLayerInstanceDispatchTable *disp; + disp = loader_get_instance_layer_dispatch(instance); + VkResult res; + + res = disp->CreateMacOSSurfaceMVK(instance, pCreateInfo, pAllocator, pSurface); + return res; +} + +// This is the instance chain terminator function for CreateMacOSSurfaceKHR +VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateMacOSSurfaceMVK(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) { + VkResult vkRes = VK_SUCCESS; + VkIcdSurface *pIcdSurface = NULL; + uint32_t i = 0; + + // First, check to ensure the appropriate extension was enabled: + struct loader_instance *ptr_instance = loader_get_instance(instance); + if (!ptr_instance->wsi_macos_surface_enabled) { + loader_log(ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, + "VK_MVK_macos_surface extension not enabled. vkCreateMacOSSurfaceMVK not executed!\n"); + vkRes = VK_ERROR_EXTENSION_NOT_PRESENT; + goto out; + } + + // Next, if so, proceed with the implementation of this function: + pIcdSurface = AllocateIcdSurfaceStruct(ptr_instance, sizeof(pIcdSurface->macos_surf.base), sizeof(pIcdSurface->macos_surf)); + if (pIcdSurface == NULL) { + vkRes = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + + pIcdSurface->macos_surf.base.platform = VK_ICD_WSI_PLATFORM_MACOS; + pIcdSurface->macos_surf.pView = pCreateInfo->pView; + + // Loop through each ICD and determine if they need to create a surface + for (struct loader_icd_term *icd_term = ptr_instance->icd_terms; icd_term != NULL; icd_term = icd_term->next, i++) { + if (icd_term->scanned_icd->interface_version >= ICD_VER_SUPPORTS_ICD_SURFACE_KHR) { + if (NULL != icd_term->dispatch.CreateMacOSSurfaceMVK) { + vkRes = icd_term->dispatch.CreateMacOSSurfaceMVK(icd_term->instance, pCreateInfo, pAllocator, + &pIcdSurface->real_icd_surfaces[i]); + if (VK_SUCCESS != vkRes) { + goto out; + } + } + } + } + + *pSurface = (VkSurfaceKHR)pIcdSurface; + +out: + + if (VK_SUCCESS != vkRes && NULL != pIcdSurface) { + if (NULL != pIcdSurface->real_icd_surfaces) { + i = 0; + for (struct loader_icd_term *icd_term = ptr_instance->icd_terms; icd_term != NULL; icd_term = icd_term->next, i++) { + if ((VkSurfaceKHR)NULL != pIcdSurface->real_icd_surfaces[i] && NULL != icd_term->dispatch.DestroySurfaceKHR) { + icd_term->dispatch.DestroySurfaceKHR(icd_term->instance, pIcdSurface->real_icd_surfaces[i], pAllocator); + } + } + loader_instance_heap_free(ptr_instance, pIcdSurface->real_icd_surfaces); + } + loader_instance_heap_free(ptr_instance, pIcdSurface); + } + + return vkRes; +} + +#endif // VK_USE_PLATFORM_MACOS_MVK + +#ifdef VK_USE_PLATFORM_IOS_MVK + +// Functions for the VK_MVK_ios_surface extension: + +// This is the trampoline entrypoint for CreateIOSSurfaceMVK +LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateIOSSurfaceMVK(VkInstance instance, + const VkIOSSurfaceCreateInfoMVK *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkSurfaceKHR *pSurface) { + const VkLayerInstanceDispatchTable *disp; + disp = loader_get_instance_layer_dispatch(instance); + VkResult res; + + res = disp->CreateIOSSurfaceMVK(instance, pCreateInfo, pAllocator, pSurface); + return res; +} + +// This is the instance chain terminator function for CreateIOSSurfaceKHR +VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateIOSSurfaceMVK(VkInstance instance, const VkIOSSurfaceCreateInfoMVK *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) { + // First, check to ensure the appropriate extension was enabled: + struct loader_instance *ptr_instance = loader_get_instance(instance); + if (!ptr_instance->wsi_ios_surface_enabled) { + loader_log(ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, + "VK_MVK_ios_surface extension not enabled. vkCreateIOSSurfaceMVK not executed!\n"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + // Next, if so, proceed with the implementation of this function: + VkIcdSurfaceIOS *pIcdSurface = + loader_instance_heap_alloc(ptr_instance, sizeof(VkIcdSurfaceIOS), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (pIcdSurface == NULL) { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + pIcdSurface->base.platform = VK_ICD_WSI_PLATFORM_IOS; + pIcdSurface->pView = pCreateInfo->pView; + + *pSurface = (VkSurfaceKHR)pIcdSurface; + + return VK_SUCCESS; +} + +#endif // VK_USE_PLATFORM_IOS_MVK + // Functions for the VK_KHR_display instance extension: LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, @@ -1502,10 +1641,26 @@ bool wsi_swapchain_instance_gpa(struct loader_instance *ptr_instance, const char // Functions for the VK_KHR_android_surface extension: if (!strcmp("vkCreateAndroidSurfaceKHR", name)) { - *addr = ptr_instance->wsi_xlib_surface_enabled ? (void *)vkCreateAndroidSurfaceKHR : NULL; + *addr = ptr_instance->wsi_android_surface_enabled ? (void *)vkCreateAndroidSurfaceKHR : NULL; return true; } #endif // VK_USE_PLATFORM_ANDROID_KHR +#ifdef VK_USE_PLATFORM_MACOS_MVK + + // Functions for the VK_MVK_macos_surface extension: + if (!strcmp("vkCreateMacOSSurfaceMVK", name)) { + *addr = ptr_instance->wsi_macos_surface_enabled ? (void *)vkCreateMacOSSurfaceMVK : NULL; + return true; + } +#endif // VK_USE_PLATFORM_MACOS_MVK +#ifdef VK_USE_PLATFORM_IOS_MVK + + // Functions for the VK_MVK_ios_surface extension: + if (!strcmp("vkCreateIOSSurfaceMVK", name)) { + *addr = ptr_instance->wsi_ios_surface_enabled ? (void *)vkCreateIOSSurfaceMVK : NULL; + return true; + } +#endif // VK_USE_PLATFORM_IOS_MVK // Functions for VK_KHR_display extension: if (!strcmp("vkGetPhysicalDeviceDisplayPropertiesKHR", name)) { diff --git a/loader/wsi.h b/loader/wsi.h index 519a7aac..03479636 100644 --- a/loader/wsi.h +++ b/loader/wsi.h @@ -42,6 +42,9 @@ typedef struct { #ifdef VK_USE_PLATFORM_XLIB_KHR VkIcdSurfaceXlib xlib_surf; #endif // VK_USE_PLATFORM_XLIB_KHR +#ifdef VK_USE_PLATFORM_MACOS_MVK + VkIcdSurfaceMacOS macos_surf; +#endif // VK_USE_PLATFORM_MACOS_MVK VkIcdSurfaceDisplay display_surf; }; uint32_t base_size; // Size of VkIcdSurfaceBase @@ -115,6 +118,14 @@ VKAPI_ATTR VkBool32 VKAPI_CALL terminator_GetPhysicalDeviceXlibPresentationSuppo uint32_t queueFamilyIndex, Display *dpy, VisualID visualID); #endif +#ifdef VK_USE_PLATFORM_MACOS_MVK +VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateMacOSSurfaceMVK(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface); +#endif +#ifdef VK_USE_PLATFORM_IOS_MVK +VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateIOSSurfaceMVK(VkInstance instance, const VkIOSSurfaceCreateInfoMVK *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface); +#endif VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkDisplayPropertiesKHR *pProperties); @@ -142,4 +153,4 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateSharedSwapchainsKHR(VkDevice dev const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchains); -#endif // WSI_H +#endif // WSI_H -- cgit v1.2.3