Skip to content

Commit

Permalink
Add visionOS and tvOS support to Apple runtime
Browse files Browse the repository at this point in the history
This pull request adds support for both visionOS and tvOS to the Apple (colloquially referred to as iOS) runtime.

It should _not_ be a breaking change, since the only major API change is an internal one (see `RenderContext` below). I believe we should be able to make this a minor release. Developers who have subclassed `RiveView` or `RiveRendererView` should not see any changes, unless they were explicitly expecting this view to be `MTKView`, which is fully unavailable on visionOS (hence our recreation - see `RiveMTKView` below.

## Premake Scripts

The premake scripts were updated to add a few new variants for iOS:
- xros (visionOS devices; named after the internal sdk)
- xrsimulator (visionOS simulator; named after the internal sdk)
- appletvos (tvOS devices; named after the internal sdk)
- appletvsimulator (tvOS simulators; named after the internal sdk)

The majority of the work here is copy/pasting existing code, and just adding additional filters when these new options are used, primarily used to target the new SDKs / minimums for those SDKs.

## Shaders

Shaders are pre-compiled for visionOS and tvOS separately, and the correct shaders are then used later-on at compile time.

## Build scripts

Build scripts were updated to support building the new libraries, targeting the new devices, using the new options above. Additionally, they have to point to new output files.

The `build_framework` script has been updated to build the new libraries to add to the final output `xcframework`.

## Project

Example targets for both visionOS and tvOS, since these truly are the "native" apps, rather than just iPad-on-your-device. These use a new `streaming` riv by the creative team.

The tvOS example app adds additional support for remote control, since that behavior can be utilized in multiple ways during development; that is, we don't add any "default" behavior for remote controls. The visionOS app, on the other hand, works out-of-the-box with no additional changes.

## RenderContext

`RenderContext` is an internal type; it's forward-declared, so it's unusable outside of the scope of internal development. There have been some "breaking" changes here - the API has been updated to, instead of passing in `MTKView` around, using `id<RiveMetalDrawableView>`. This had to be changed, regardless, since visionOS does not have `MTKView`. The choice to use a protocol was because it forces a little more explicit initialization across platforms, rather than having a parent class that acts as an abstract class, but isn't abstract because it still needs some default values, but those values are different based on device and API availability, etc. We could've passed around `RiveMTKView` as the type, but with a protocol, there's a possibility of being able to use a type that isn't exactly a view, but might want to still act against the drawing process. Personal choice, really.

## RiveRendererView

`RiveRendererView` is now a subclass of `RiveMTKView`. `RiveMTKView`'s superclass depends on the device:
- On visionOS, this is a `UIView` with an underlying `CAMetalLayer`
- On all other platforms, `MTKView`

This new class conforms to `RiveMetalDrawableView`, which allows it to be passed to `RenderContext` types.

### RiveMTKView (visionOS)

`RiveMTKView` on visionOS is a subclass of `UIView` that is backed by a `CAMetalLayer`, providing the necessary properties of `RiveMetalDrawableView` (compile-time safety here, baby). This is quite a simple recreation of the default `MTKView`, since that type is not available on visionOS (thanks, Apple).

## Other things

Additional compile-time checks for platform OS have been added to make sure each new platform compiles with the correct APIs that can be shared, or otherwise newly implemented.

Diffs=
6f70a0e803 Add visionOS and tvOS support to Apple runtime (#8107)

Co-authored-by: David Skuza <david@rive.app>
  • Loading branch information
dskuza and dskuza committed Dec 11, 2024
1 parent e27fe66 commit f8c6fc4
Show file tree
Hide file tree
Showing 13 changed files with 423 additions and 67 deletions.
2 changes: 1 addition & 1 deletion .rive_head
Original file line number Diff line number Diff line change
@@ -1 +1 @@
f69757c8dd221c54942fee2e47bae55df8f6dc12
6f70a0e803b1eaf43374b98cc4fda6e79163667d
33 changes: 33 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,45 @@ else
fi
;;
ios_sim)
echo "Building for iOS Simulator"
export IOS_SYSROOT=$(xcrun --sdk iphonesimulator --show-sdk-path)
build "--os=ios --variant=emulator"
if [ "$OPTION" = "clean" ]; then
exit
fi
;;
xros)
echo "Building for visionOS"
export XROS_SYSROOT=$(xcrun --sdk xros --show-sdk-path)
build "--os=ios --variant=xros"
if [ "$OPTION" = "clean" ]; then
exit
fi
;;
xrsimulator)
echo "Building for visionOS Simulator"
export XROS_SYSROOT=$(xcrun --sdk xrsimulator --show-sdk-path)
build "--os=ios --variant=xrsimulator"
if [ "$OPTION" = "clean" ]; then
exit
fi
;;
appletvos)
echo "Building for tvOS"
export APPLETVOS_SYSROOT=$(xcrun --sdk appletvos --show-sdk-path)
build "--os=ios --variant=appletvos"
if [ "$OPTION" = "clean" ]; then
exit
fi
;;
appletvsimulator)
echo "Building for tvOS Simulator"
export APPLETVOS_SYSROOT=$(xcrun --sdk appletvsimulator --show-sdk-path)
build "--os=ios --variant=appletvsimulator"
if [ "$OPTION" = "clean" ]; then
exit
fi
;;
# Android supports ABIs via a custom platform format:
# e.g. 'android.x86', 'android.x64', etc.
android*)
Expand Down
50 changes: 50 additions & 0 deletions build/premake5.lua
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,52 @@ do
objdir('%{cfg.system}_sim/obj/%{cfg.buildcfg}')
end

filter({ 'system:ios', 'options:variant=xros' })
do
buildoptions({
'--target=arm64-apple-xros1.0',
'-fembed-bitcode -arch arm64 -isysroot '
.. (os.getenv('XROS_SYSROOT') or ''),
})
targetdir('xros/bin/%{cfg.buildcfg}')
objdir('xros/obj/%{cfg.buildcfg}')
end

filter({ 'system:ios', 'options:variant=xrsimulator' })
do
buildoptions({
'--target=arm64-apple-xros1.0-simulator',
'-arch arm64 -arch x86_64 -isysroot '
.. (os.getenv('XROS_SYSROOT') or ''),
})
targetdir('xrsimulator/bin/%{cfg.buildcfg}')
objdir('xrsimulator/obj/%{cfg.buildcfg}')
end

filter({ 'system:ios', 'options:variant=appletvos' })
do
buildoptions({
'--target=arm64-apple-tvos',
'-mappletvos-version-min=16.0',
'-fembed-bitcode -arch arm64 -isysroot '
.. (os.getenv('APPLETVOS_SYSROOT') or ''),
})
targetdir('appletvos/bin/%{cfg.buildcfg}')
objdir('appletvos/obj/%{cfg.buildcfg}')
end

filter({ 'system:ios', 'options:variant=appletvsimulator' })
do
buildoptions({
'--target=arm64-apple-tvos-simulator',
'-mappletvsimulator-version-min=16.0',
'-arch arm64 -arch x86_64 -isysroot '
.. (os.getenv('APPLETVOS_SYSROOT') or ''),
})
targetdir('appletvsimulator/bin/%{cfg.buildcfg}')
objdir('appletvsimulator/obj/%{cfg.buildcfg}')
end

filter('system:macosx or system:ios')
do
files({ '../src/text/font_hb_apple.mm' })
Expand Down Expand Up @@ -208,6 +254,10 @@ newoption({
'runtime',
'Build the static library specifically targeting our runtimes',
},
{ 'xros', 'Builds for Apple Vision Pro' },
{ 'xrsimulator', 'Builds for Apple Vision Pro simulator' },
{ 'appletvos', 'Builds for Apple TV' },
{ 'appletvsimulator', 'Builds for Apple TV simulator' },
},
default = 'system',
})
Expand Down
109 changes: 88 additions & 21 deletions build/rive_build_config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ newoption({
allowed = {
{ 'system', 'Builds the static library for the provided system' },
{ 'emulator', 'Builds for a simulator for the provided system' },
{ 'xros', 'Builds for Apple Vision Pro' },
{ 'xrsimulator', 'Builds for Apple Vision Pro simulator' },
{ 'appletvos', 'Builds for Apple TV' },
{ 'appletvsimulator', 'Builds for Apple TV simulator' },
{
'runtime',
'Build the static library specifically targeting our runtimes',
}
},
default = 'system',
})
Expand Down Expand Up @@ -472,37 +480,96 @@ end

filter({})

if _OPTIONS['os'] == 'ios' then
iphoneos_sysroot = os.outputof('xcrun --sdk iphoneos --show-sdk-path')
if iphoneos_sysroot == nil then
error(
'Unable to locate iPhoneOS SDK. Please ensure Xcode and its iOS component are installed. Additionally, ensure Xcode Command Line Tools are pointing to that Xcode location with `xcode-select -p`.'
)
end
filter('system:macosx')
do
defines({ 'RIVE_MACOSX' })
end

iphonesimulator_sysroot = os.outputof('xcrun --sdk iphonesimulator --show-sdk-path')
if iphonesimulator_sysroot == nil then
error(
'Unable to locate iPhone simulator SDK. Please ensure Xcode and its iOS component are installed. Additionally, ensure Xcode Command Line Tools are pointing to that Xcode location with `xcode-select -p`.'
)
end
filter({})

filter('options:variant=system')
do
if _OPTIONS['os'] == 'ios' then
if _OPTIONS['variant'] == 'system' then
iphoneos_sysroot = os.outputof('xcrun --sdk iphoneos --show-sdk-path')
if iphoneos_sysroot == nil then
error(
'Unable to locate iPhoneOS SDK. Please ensure Xcode and its iOS component are installed. Additionally, ensure Xcode Command Line Tools are pointing to that Xcode location with `xcode-select -p`.'
)
end

defines({ 'RIVE_IOS' })
buildoptions({
'--target=arm64-apple-ios13.0.0',
'-mios-version-min=13.0.0',
'-isysroot ' .. iphoneos_sysroot,
})
end

filter('options:variant=emulator')
do
elseif _OPTIONS['variant'] == 'emulator' then
iphonesimulator_sysroot = os.outputof('xcrun --sdk iphonesimulator --show-sdk-path')
if iphonesimulator_sysroot == nil then
error(
'Unable to locate iPhone simulator SDK. Please ensure Xcode and its iOS component are installed. Additionally, ensure Xcode Command Line Tools are pointing to that Xcode location with `xcode-select -p`.'
)
end

defines({ 'RIVE_IOS_SIMULATOR' })
buildoptions({
'--target=arm64-apple-ios13.0.0-simulator',
'-mios-version-min=13.0.0',
'-isysroot ' .. iphonesimulator_sysroot,
})
elseif _OPTIONS['variant'] == 'xros' then
xros_sysroot = os.outputof('xcrun --sdk xros --show-sdk-path')
if xros_sysroot == nil then
error(
'Unable to locate xros sdk. Please ensure Xcode Command Line Tools are installed, as well as the visionOS SDK.'
)
end

defines({ 'RIVE_XROS' })
buildoptions({
'--target=arm64-apple-xros1.0',
'-isysroot ' .. xros_sysroot,
})
elseif _OPTIONS['variant'] == 'xrsimulator' then
xrsimulator_sysroot = os.outputof('xcrun --sdk xrsimulator --show-sdk-path')
if xrsimulator_sysroot == nil then
error(
'Unable to locate xrsimulator sdk. Please ensure Xcode Command Line Tools are installed, as well as the visionOS SDK.'
)
end

defines({ 'RIVE_XROS_SIMULATOR' })
buildoptions({
'--target=arm64-apple-xros1.0-simulator',
'-isysroot ' .. xrsimulator_sysroot,
})
elseif _OPTIONS['variant'] == 'appletvos' then
appletvos_sysroot = os.outputof('xcrun --sdk appletvos --show-sdk-path')
if appletvos_sysroot == nil then
error(
'Unable to locate appletvos sdk. Please ensure Xcode Command Line Tools are installed, as well as the tvOS SDK.'
)
end

defines({ 'RIVE_APPLETVOS' })
buildoptions({
'--target=arm64-apple-tvos',
'-mappletvos-version-min=16.0',
'-isysroot ' .. appletvos_sysroot,
})
elseif _OPTIONS['variant'] == 'appletvsimulator' then
appletvsimulator_sysroot = os.outputof('xcrun --sdk appletvsimulator --show-sdk-path')
if appletvsimulator_sysroot == nil then
error(
'Unable to locate appletvsimulator sdk. Please ensure Xcode Command Line Tools are installed, as well as the tvOS SDK.'
)
end

defines({ 'RIVE_APPLETVOS_SIMULATOR' })
buildoptions({
'--target=arm64-apple-tvos-simulator',
'-mappletvsimulator-version-min=16.0',
'-isysroot ' .. appletvsimulator_sysroot,
})
end

filter({})
Expand Down Expand Up @@ -557,7 +624,7 @@ if os.host() == 'macosx' then

filter({
'system:ios',
'options:variant=emulator',
'options:variant=emulator or variant=xrsimulator or variant=appletvsimulator',
'options:arch=x64 or arch=universal',
})
do
Expand All @@ -566,7 +633,7 @@ if os.host() == 'macosx' then

filter({
'system:ios',
'options:variant=emulator',
'options:variant=emulator or variant=xrsimulator or variant=appletvsimulator',
'options:arch=arm64 or arch=universal',
})
do
Expand Down
12 changes: 11 additions & 1 deletion decoders/premake5_v2.lua
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,21 @@ do
forceincludes({ 'rive_libjpeg_renames.h' })
end

filter({ 'system:macosx or system:ios' })
filter({ 'system:macosx or system:ios', 'not options:variant=appletvos', 'not options:variant=appletvsimulator' })
do
files({ 'src/**.mm' })
end

filter({ 'system:ios' , 'options:variant=appletvos or options:variant=appletvsimulator' })
do
files({
'src/bitmap_decoder_thirdparty.cpp',
'src/decode_webp.cpp',
'src/decode_jpeg.cpp',
'src/decode_png.cpp',
})
end

filter({ 'system:not macosx', 'system:not ios' })
do
files({
Expand Down
50 changes: 49 additions & 1 deletion dependencies/premake5_harfbuzz.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require('setup_compiler')
local dependency = require('dependency')
harfbuzz = dependency.github('rive-app/harfbuzz', 'rive_10.0.1_coretext')
harfbuzz = dependency.github('rive-app/harfbuzz', 'rive_10.1.0')

workspace('rive')
configurations({ 'debug', 'release' })
Expand Down Expand Up @@ -321,6 +321,54 @@ do
objdir('%{cfg.system}_sim/cache/obj/%{cfg.buildcfg}')
end

filter({ 'system:ios', 'options:variant=xros' })
do
buildoptions({
'--target=arm64-apple-xros1.0',
'-fembed-bitcode -arch arm64 -isysroot '
.. (os.getenv('XROS_SYSROOT') or ''),
})
targetdir('xros/cache/bin/%{cfg.buildcfg}')
objdir('xros/cache/obj/%{cfg.buildcfg}')
end

filter({ 'system:ios', 'options:variant=xrsimulator' })
do
buildoptions({
'--target=arm64-apple-xros1.0-simulator',
'-arch arm64 -arch x86_64 -isysroot '
.. (os.getenv('XROS_SYSROOT') or ''),
})
targetdir('xrsimulator/cache/bin/%{cfg.buildcfg}')
objdir('xrsimulator/cache/obj/%{cfg.buildcfg}')
end

filter({ 'system:ios', 'options:variant=appletvos' })
do
buildoptions({
'--target=arm64-apple-tvos',
'-mappletvos-version-min=16.0',
'-fembed-bitcode -arch arm64 -isysroot '
.. (os.getenv('APPLETVOS_SYSROOT') or ''),
})
targetdir('appletvos/cache/bin/%{cfg.buildcfg}')
objdir('appletvos/cache/obj/%{cfg.buildcfg}')
defines({ 'RIVE_APPLETVOS' })
end

filter({ 'system:ios', 'options:variant=appletvsimulator' })
do
buildoptions({
'--target=arm64-apple-tvos-simulator',
'-mappletvsimulator-version-min=16.0',
'-arch arm64 -arch x86_64 -isysroot '
.. (os.getenv('APPLETVOS_SYSROOT') or ''),
})
targetdir('appletvsimulator/cache/bin/%{cfg.buildcfg}')
objdir('appletvsimulator/cache/obj/%{cfg.buildcfg}')
defines({ 'RIVE_APPLETVOS_SIMULATOR' })
end

filter({ 'system:android', 'configurations:release' })
do
buildoptions({ '-flto=full' })
Expand Down
2 changes: 1 addition & 1 deletion dependencies/premake5_harfbuzz_v2.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
dofile('rive_build_config.lua')

local dependency = require('dependency')
harfbuzz = dependency.github('rive-app/harfbuzz', 'rive_10.0.1_coretext')
harfbuzz = dependency.github('rive-app/harfbuzz', 'rive_10.1.0')

newoption({
trigger = 'no-harfbuzz-renames',
Expand Down
Loading

0 comments on commit f8c6fc4

Please sign in to comment.