From 3e6a837266ab6a1796d15964ae147bccd6a46430 Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Sat, 14 Mar 2026 18:50:20 -0400 Subject: [PATCH 1/5] Migrate iOS application framework to required UIKit scene-based lifecycle --- app/CMakeLists.txt | 4 ++- app/ios/AppDelegate.h | 3 +- app/ios/AppDelegate.m | 24 ++------------- app/ios/Info.plist | 19 ++++++++++++ app/ios/SceneDelegate.h | 25 +++++++++++++++ app/ios/SceneDelegate.m | 65 +++++++++++++++++++++++++++++++++++++++ app/ios/ViewController.mm | 6 +++- 7 files changed, 121 insertions(+), 25 deletions(-) create mode 100644 app/ios/SceneDelegate.h create mode 100644 app/ios/SceneDelegate.m diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 22c817f0ce..ed4dedf1eb 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2019-2025, Arm Limited and Contributors +# Copyright (c) 2019-2026, Arm Limited and Contributors # # SPDX-License-Identifier: Apache-2.0 # @@ -49,6 +49,8 @@ elseif(IOS) ${CMAKE_CURRENT_SOURCE_DIR}/ios/main.mm ${CMAKE_CURRENT_SOURCE_DIR}/ios/AppDelegate.h ${CMAKE_CURRENT_SOURCE_DIR}/ios/AppDelegate.m + ${CMAKE_CURRENT_SOURCE_DIR}/ios/SceneDelegate.h + ${CMAKE_CURRENT_SOURCE_DIR}/ios/SceneDelegate.m ${CMAKE_CURRENT_SOURCE_DIR}/ios/ViewController.h ${CMAKE_CURRENT_SOURCE_DIR}/ios/ViewController.mm ) diff --git a/app/ios/AppDelegate.h b/app/ios/AppDelegate.h index a4724124a9..04d83a61b6 100644 --- a/app/ios/AppDelegate.h +++ b/app/ios/AppDelegate.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2024, Holochip Inc. +/* Copyright (c) 2024-2026, Holochip Inc. * * SPDX-License-Identifier: Apache-2.0 * @@ -25,7 +25,6 @@ #if TARGET_OS_IOS @interface AppDelegate : UIResponder -@property (strong, nonatomic) UIWindow *window; #else @interface AppDelegate : NSResponder diff --git a/app/ios/AppDelegate.m b/app/ios/AppDelegate.m index 5e4c4f81e6..a63fa0fb79 100644 --- a/app/ios/AppDelegate.m +++ b/app/ios/AppDelegate.m @@ -1,4 +1,4 @@ -/* Copyright (c) 2024, Holochip Inc. +/* Copyright (c) 2024-2026, Holochip Inc. * * SPDX-License-Identifier: Apache-2.0 * @@ -29,27 +29,9 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( return YES; } - -- (void)applicationWillResignActive:(UIApplication *)application { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. -} - - -- (void)applicationDidEnterBackground:(UIApplication *)application { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. +- (void)applicationWillTerminate:(UIApplication *)application { + // Called when the application is about to terminate. Save data if appropriate. } - -- (void)applicationWillEnterForeground:(UIApplication *)application { - // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. -} - - -- (void)applicationDidBecomeActive:(UIApplication *)application { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. -} - - @end #endif diff --git a/app/ios/Info.plist b/app/ios/Info.plist index 542bd4d5b9..762283b2d8 100644 --- a/app/ios/Info.plist +++ b/app/ios/Info.plist @@ -47,6 +47,25 @@ limitations under the License. Storyboard UILaunchStoryboardName launch + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + SceneDelegate + UISceneStoryboardFile + Storyboard + + + + CSResourcesFileMapped NSHumanReadableCopyright diff --git a/app/ios/SceneDelegate.h b/app/ios/SceneDelegate.h new file mode 100644 index 0000000000..dc15b3c638 --- /dev/null +++ b/app/ios/SceneDelegate.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2026, Holochip Inc. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 the "License"; +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#import + +@interface SceneDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end + diff --git a/app/ios/SceneDelegate.m b/app/ios/SceneDelegate.m new file mode 100644 index 0000000000..9825bd7157 --- /dev/null +++ b/app/ios/SceneDelegate.m @@ -0,0 +1,65 @@ +/* Copyright (c) 2026, Holochip Inc. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 the "License"; +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#import "SceneDelegate.h" +#import "ViewController.h" + +@interface SceneDelegate () + +@end + +@implementation SceneDelegate + + +- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { + UIWindowScene *windowScene = (UIWindowScene *)scene; + + self.window = [[UIWindow alloc] initWithWindowScene:windowScene]; + self.window.rootViewController = [[ViewController alloc] init]; + + [self.window makeKeyAndVisible]; +} + +- (void)sceneWillEnterForeground:(UIScene *)scene { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. +} + +- (void)sceneDidBecomeActive:(UIScene *)scene { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. +} + +- (void)sceneWillResignActive:(UIScene *)scene { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). +} + +- (void)sceneDidEnterBackground:(UIScene *)scene { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. +} + +- (void)sceneDidDisconnect:(UIScene *)scene { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). +} + +@end diff --git a/app/ios/ViewController.mm b/app/ios/ViewController.mm index 5f1f8bd413..f82e5f4f91 100644 --- a/app/ios/ViewController.mm +++ b/app/ios/ViewController.mm @@ -1,4 +1,4 @@ -/* Copyright (c) 2024, Holochip Inc. +/* Copyright (c) 2024-2026, Holochip Inc. * * SPDX-License-Identifier: Apache-2.0 * @@ -46,6 +46,10 @@ - (void)viewDidLoad { argv[i] = s.UTF8String; } + // Allocate and add a Metal-compatible sub-view for Vulkan to use + self.vulkan_view = [[VulkanView alloc] initWithFrame:self.view.bounds]; + [self.view addSubview:self.vulkan_view]; + self.vulkan_view.contentScaleFactor = UIScreen.mainScreen.nativeScale; context = create_platform_context((int)args.count, const_cast(argv)); From 7d8b8e64d3561b674a27afcdb8d90506d8094e87 Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Sun, 15 Mar 2026 09:02:16 -0400 Subject: [PATCH 2/5] Update the Vulkan sub-view to match parent view dimensions on rotation --- app/ios/ViewController.mm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/ios/ViewController.mm b/app/ios/ViewController.mm index f82e5f4f91..611d919394 100644 --- a/app/ios/ViewController.mm +++ b/app/ios/ViewController.mm @@ -62,6 +62,13 @@ - (void)viewDidLoad { [_displayLink addToRunLoop: NSRunLoop.currentRunLoop forMode: NSDefaultRunLoopMode]; } +- (void)viewDidLayoutSubviews { + [super viewDidLayoutSubviews]; + + // Update the Vulkan sub-view to match parent view dimensions following rotation events + self.vulkan_view.layer.frame = self.view.bounds; +} + -(void) renderLoop { if(!_displayLink.isPaused && [UIApplication sharedApplication].applicationState == UIApplicationStateActive) { if(_code == vkb::ExitCode::Success) { From a2e70da9e530d4a25219a1bddc3fe52f5f79e9de Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Sun, 15 Mar 2026 22:03:44 -0400 Subject: [PATCH 3/5] Add touchscreen input handling to iOS application framework --- app/ios/ViewController.mm | 66 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/app/ios/ViewController.mm b/app/ios/ViewController.mm index 611d919394..3c3362e9dc 100644 --- a/app/ios/ViewController.mm +++ b/app/ios/ViewController.mm @@ -20,6 +20,7 @@ #include "core/platform/entrypoint.hpp" #include "platform/ios/ios_platform.h" #include "platform/ios/ios_window.h" +#include "platform/input_events.h" int platform_main(const vkb::PlatformContext &); @@ -28,16 +29,16 @@ @interface ViewController(){ std::unique_ptr context; vkb::IosPlatformContext* _context; vkb::ExitCode _code; + UITouch* _activeTouch; } @property (retain, nonatomic) IBOutlet VulkanView *vulkan_view; @end @implementation ViewController -- (void)viewDidLoad { +- (void) viewDidLoad { [super viewDidLoad]; - // Convert incoming args to "C" argc/argv strings NSArray *args = [[NSProcessInfo processInfo] arguments]; const char** argv = (const char**) alloca(sizeof(char*) * args.count); @@ -62,7 +63,7 @@ - (void)viewDidLoad { [_displayLink addToRunLoop: NSRunLoop.currentRunLoop forMode: NSDefaultRunLoopMode]; } -- (void)viewDidLayoutSubviews { +- (void) viewDidLayoutSubviews { [super viewDidLayoutSubviews]; // Update the Vulkan sub-view to match parent view dimensions following rotation events @@ -84,4 +85,63 @@ -(void) renderLoop { } } } + +-(CGPoint) getTouchLocalPoint:(UITouch*) touch { + CGPoint point = [touch locationInView:self.vulkan_view]; + point.x *= self.vulkan_view.contentScaleFactor; + point.y *= self.vulkan_view.contentScaleFactor; + return point; +} + +// Handle touch events for selection and dragging within the display and GUI overlay +-(void) touchesBegan:(NSSet*) touches withEvent:(UIEvent*) theEvent { + if (_activeTouch == nil) { + _activeTouch = [touches anyObject]; + + auto point = [self getTouchLocalPoint:_activeTouch]; + ((vkb::IosPlatform*)_context->userPlatform)->input_event(vkb::TouchInputEvent{ + 0, 1, + vkb::TouchAction::Down, + static_cast(point.x), + static_cast(point.y)}); + } +} + +-(void) touchesMoved:(NSSet*) touches withEvent:(UIEvent*) theEvent { + if (_activeTouch && [touches containsObject:_activeTouch]) { + auto point = [self getTouchLocalPoint:_activeTouch]; + ((vkb::IosPlatform*)_context->userPlatform)->input_event(vkb::TouchInputEvent{ + 0, 1, + vkb::TouchAction::Move, + static_cast(point.x), + static_cast(point.y)}); + } +} + +-(void) touchesEnded:(NSSet*) touches withEvent:(UIEvent*) theEvent { + if (_activeTouch && [touches containsObject:_activeTouch]) { + auto point = [self getTouchLocalPoint:_activeTouch]; + ((vkb::IosPlatform*)_context->userPlatform)->input_event(vkb::TouchInputEvent{ + 0, 1, + vkb::TouchAction::Up, + static_cast(point.x), + static_cast(point.y)}); + + _activeTouch = nil; + } +} + +-(void) touchesCancelled:(NSSet*) touches withEvent:(UIEvent*) theEvent { + if (_activeTouch && [touches containsObject:_activeTouch]) { + auto point = [self getTouchLocalPoint:_activeTouch]; + ((vkb::IosPlatform*)_context->userPlatform)->input_event(vkb::TouchInputEvent{ + 0, 1, + vkb::TouchAction::Cancel, + static_cast(point.x), + static_cast(point.y)}); + + _activeTouch = nil; + } +} + @end From 39e073d10680c7251d5dca69940b920b2b3d567b Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Sun, 15 Mar 2026 22:44:15 -0400 Subject: [PATCH 4/5] Update copyright date in iOS info.plist file --- app/ios/Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/ios/Info.plist b/app/ios/Info.plist index 762283b2d8..d64d93c489 100644 --- a/app/ios/Info.plist +++ b/app/ios/Info.plist @@ -1,6 +1,6 @@