a-simple-triangle / Part 16 - Vulkan setup iOS

In this article we will get Vulkan running on iOS. This is a pivot point for our iOS platform target - in order to compile an iOS application to use Vulkan it will need to be capable of running Apple’s Metal framework.

If you check the following table: https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/DeviceCompatibilityMatrix/DeviceCompatibilityMatrix.html you can see that only iPhone 5s or later - or effectively 64 bit devices - can run Metal. So by introducing Vulkan to our iOS platform, we will have to say goodbye to older iOS devices prior to the 5s (my poor iPad mini!) It should be noted also that the MoltenVK framework needed for Vulkan support cannot compile for the iOS simulator either - so pretty much you have to deploy code to a real iOS device during development.


Setup script

The iOS platform target is very similar to the MacOS app so once again we’ll get a good amount of reuse from our existing setup scripts.

Open up the ios/setup.sh script and add the following command directly beneath the existing fetch_third_party_lib_tiny_obj_loader command:

fetch_third_party_lib_vulkan_macos

This will download the Vulkan SDK for MacOS if necessary, which also contains the iOS MoltenVK libraries.

Next we need to copy the iOS MoltenVK framework and dynamic library into our ios/Frameworks folder so they can be linked and included in our build. This differs from the MacOS and console application which only used dynamic libraries.

Add the following script to ios/setup.sh just before the xcodegen command:

# Check to see if we have the MoltenVK framework and dynamic library
verify_frameworks_folder_exists
pushd "Frameworks"
  if [ ! -d "MoltenVK.framework" ]; then
    cp -R ../../../third-party/vulkan-mac/MoltenVK/iOS/framework/MoltenVK.framework .
  fi

  if [ ! -e "libMoltenVK.dylib" ]; then
    cp ../../../third-party/vulkan-mac/MoltenVK/iOS/dynamic/libMoltenVK.dylib .
  fi
popd

Run the setup script in Terminal in the ios folder then observe the new files and folders that were generated:

: root
  + ios
    + Frameworks
      libMoltenVK.dylib
      MoltenVK.framework

We now need to update the project.yml file to stitch the libraries into our Xcode project. Open the ios/project.yml file for editing.

Target SDK

To use MoltenVK we’ll need to include the Metal framework and due to the way we are statically linking the MoltenVK libraries we will need to drop support for non 64 bit iOS devices - anything prior to the iPhone 5s. So we may as well also lift our minimum iOS version to 10 to filter devices to that level. Update the deploymentTarget to do this:

deploymentTarget:
    iOS: "10.0"

Vulkan SDK headers

To include the Vulkan headers we will update the HEADER_SEARCH_PATHS section - observe the additional Vulkan include path:

HEADER_SEARCH_PATHS:
    - $(PROJECT_DIR)/../../third-party/SDL/include
    - $(PROJECT_DIR)/../../third-party/glm
    - $(PROJECT_DIR)/../../third-party/tiny-obj-loader
    - $(PROJECT_DIR)/../../third-party/SDL2_image
    - $(PROJECT_DIR)/../../third-party/vulkan-mac/macOS/include

Link MoltenVK framework and dynamic library files

Next we need to link the MoltenVK files into our Xcode project - edit the LIBRARY_SEARCH_PATHS to include the new Frameworks folder we created:

LIBRARY_SEARCH_PATHS:
    - $(inherited)
    - $(PROJECT_DIR)
    - $(PROJECT_DIR)/Libs
    - $(PROJECT_DIR)/Frameworks

Then edit the dependencies section and add the two MoltenVK entries and the Metal SDK framework like this:

Important: The order of these dependencies matters - make sure you get them in the same order as shown below.

dependencies:
    - framework: Frameworks/libMoltenVK.dylib
        embed: true
    - framework: Frameworks/MoltenVK.framework
        embed: false
    - sdk: Metal.framework        
    - framework: Libs/libSDL2.a
        embed: false
    - framework: Libs/libSDL2_image.a
        embed: false
    - sdk: MobileCoreServices.framework
    - sdk: CoreMotion.framework
    - sdk: CoreGraphics.framework
    - sdk: AudioToolbox.framework
    - sdk: CoreAudio.framework
    - sdk: QuartzCore.framework
    - sdk: GameController.framework
    - sdk: Foundation.framework
    - sdk: OpenGLES.framework
    - sdk: UIKit.framework
    - sdk: AVFoundation.framework
    - sdk: ImageIO.framework

Save and close your project.yml file, then run the setup.sh script in your ios folder to regenerate the Xcode project. When its done, open the project in Xcode run the application on a physical iOS device.

Note: You will need to update the application signing configuration using whatever Apple developer account you normally use. If you are not a registered Apple developer then I don’t think you can actually run iOS apps on a physical device. To avoid configuring the signing every time you regenerate the Xcode project you could include the signing information in the project.yml file.

The following screenshot shows the expected output when you run the app - note that I’m running it on a physical device which is why you can’t see a device in the picture.


Summary

The setup for MacOS/console and iOS ended up being pretty straight forward but it took me ages to figure out the correct incantations to apply to get it working.

Next up we’ll wrangle Vulkan on Android which is anything but straight forward!

The code for this article can be found here.

Continue to Part 17: Vulkan setup Android.

End of part 16