chore(unreal): Unreal target IOS (#14291) 10821b0399 Co-authored-by: Jonathon Copeland <jcopela4@gmail.com>
diff --git a/.rive_head b/.rive_head index e67461e..53ab4fe 100644 --- a/.rive_head +++ b/.rive_head
@@ -1 +1 @@ -603235d26914a14ab897e696c446f4354782b6fa +10821b03994f98cf1fc3d67f663db0d41431998f
diff --git a/tests/check_golds.sh b/tests/check_golds.sh index 37e8064..e1c3bd9 100755 --- a/tests/check_golds.sh +++ b/tests/check_golds.sh
@@ -53,6 +53,14 @@ fi shift ;; + -ui) + TARGET="unreal_ios" + # msaa is what we target on android. atomics needs pixel shader + # UAVs, which mobile handles badly, and it hangs on adreno. + DEFAULT_BACKEND=metalatomic + ARGS="$ARGS --no-rebuild" + shift + ;; -ua) TARGET="unreal_android" # msaa is what we target on android. atomics needs pixel shader
diff --git a/tests/deploy_tests.py b/tests/deploy_tests.py index d9d2ed5..91413cf 100644 --- a/tests/deploy_tests.py +++ b/tests/deploy_tests.py
@@ -112,7 +112,7 @@ parser.add_argument("-t", "--target", default="host", choices=["host", "android", "ios", "iossim", "unreal", - "unreal_android", "webbrowser", "webserver", + "unreal_android", "unreal_ios", "webbrowser", "webserver", "webbrowserandroid", "webserverandroid", 'console'], help="which platform to run on") parser.add_argument("-a", "--android-arch", @@ -548,9 +548,18 @@ unreal_exe_path = os.path.join(dirname, *UNREAL_HOST_PACKAGE) return [unreal_exe_path] + unreal_tool_args(toolname) + \ unreal_engine_args(args.target, args.backend) + \ - ["-ResX=1280", "-ResY=720"] + unreal_offscreen_args(toolname) + \ + unreal_resolution_args(toolname) + unreal_offscreen_args(toolname) + \ cmd[1:] + if args.target == "unreal_ios": + print("\nDeploying %s on unreal ios (udid=%s, ios_version=%i)..." % + (toolname, args.ios_udid, target_info["ios_version"])) + return ["xcrun", "devicectl", "device", "process", "launch", "--console", + "--device", args.ios_udid, unreal_ios_bundle_id(), "--"] + \ + unreal_tool_args(toolname) + \ + unreal_engine_args(args.target, args.backend) + \ + unreal_offscreen_args(toolname) + cmd[1:] + if args.target == "unreal_android": tool_args = ' '.join(unreal_tool_args(toolname) + unreal_engine_args(args.target, args.backend) + cmd[1:]) @@ -724,6 +733,7 @@ UNREAL_TARGET_PLATFORMS = { "unreal": UNREAL_HOST_PLATFORM, "unreal_android": "Android", + "unreal_ios": "iOS", } # One map serves every tool: which tool runs is chosen by "-rivetool=<name>", @@ -739,6 +749,9 @@ # something you watch, so it keeps its window. return [] if toolname == "player" else ["-RenderOffScreen"] +def unreal_resolution_args(toolname): + return [] if toolname == "player" else ["-ResX=1280", "-ResY=720"] + UNREAL_RHI_SWITCHES = { "d3d": "-dx11", "d3d12": "-dx12", @@ -757,12 +770,14 @@ ["vk"] if platform.system() == "Linux" else ["d3d", "d3d12", "vk"], "unreal_android": ["vk"], + "unreal_ios": ["metal"], } DEFAULT_UNREAL_BACKENDS = { "unreal": "metal" if platform.system() == "Darwin" else "vk" if platform.system() == "Linux" else "d3d12", "unreal_android": "vk", + "unreal_ios": "metal", } def split_unreal_backend(name): @@ -845,10 +860,43 @@ table package_project.py keeps is public and has no entry for one.""" return ["--platform", UNREAL_TARGET_PLATFORMS[args.target]] +def ios_device_version(udid): + listing = subprocess.check_output(["xcrun", "xctrace", "list", "devices"]).decode() + for line in listing.splitlines(): + if udid not in line: + continue + version = re.search(r"\(([0-9]+)\.[0-9.]+\)", line) + if version: + return int(version.group(1)) + return None + +def unreal_ios_bundle(): + stage_dir = os.path.join(args.builddir, "IOS") + bundles = sorted(glob.glob(os.path.join(stage_dir, "*.app"))) + if not bundles: + ipas = sorted(glob.glob(os.path.join(stage_dir, "*.ipa"))) + raise RuntimeError( + "no .app in %s; devicectl and the bundle id both need the .app " + "directory that package_project.py archives%s" + % (stage_dir, + ", but only these .ipa archives are there: %s" % + ", ".join(os.path.basename(i) for i in ipas) if ipas else "")) + return bundles[0] + +def unreal_ios_bundle_id(): + bundle = unreal_ios_bundle() + plist = os.path.join(bundle, "Info.plist") + return subprocess.check_output( + ["plutil", "-extract", "CFBundleIdentifier", "raw", "-o", "-", plist] + ).decode().strip() + def install_unreal_package(): """Put the packaged build on the device. Nothing to do where the launch command reaches it from the host.""" - pass + if args.target != "unreal_ios": + return + subprocess.check_call(["xcrun", "devicectl", "device", "install", "app", + "--device", args.ios_udid, unreal_ios_bundle()]) def package_unreal_project(): # No engine path -> assume the project is already packaged (legacy behavior). @@ -863,7 +911,6 @@ "--output", os.path.abspath(args.builddir), "--config", unreal_client_config(), "--no-rive-build"] + unreal_package_platform_args()) - install_unreal_package() def main(): # Parse skipped tests. These only apply to a whole-corpus sweep: gms or @@ -921,7 +968,7 @@ args.remote = True # Since we can't do port forwarding in iOS, it always has to be remote. if not args.ios_udid: args.ios_udid = "booted" - elif args.target == 'unreal' or args.target == 'unreal_android': + elif args.target in ('unreal', 'unreal_android', 'unreal_ios'): # currently, unreal needs to run only one job at a time for goldens and gms to work args.jobs_per_tool = 1 if args.builddir == None: @@ -929,6 +976,25 @@ if args.backend == None: args.backend = DEFAULT_UNREAL_BACKENDS[args.target] unreal_engine_args(args.target, args.backend) + if args.target == 'unreal_ios': + args.remote = True + if not args.ios_udid: + udids = subprocess.check_output(["idevice_id", "-l"]).decode().split() + if len(udids) != 1: + print("expected exactly one attached iOS device, found %d; " + "pass --ios_udid" % len(udids)) + return -1 + args.ios_udid = udids[0] + ios_version = ios_device_version(args.ios_udid) + if ios_version is None: + print("no device matching --ios_udid=%s in 'xcrun xctrace list devices'" + % args.ios_udid) + return -1 + if ios_version < 17: + print("--target=unreal_ios launches through devicectl, which needs " + "iOS 17 or newer; this device reports iOS %d" % ios_version) + return -1 + target_info["ios_version"] = ios_version elif args.target.startswith("web"): args.jobs_per_tool = 1 if args.builddir == None: @@ -1082,6 +1148,8 @@ subprocess.check_call(["ios-deploy", "--bundle", "ios_tests/build/Debug-iphoneos/rive_ios_tests.app"]) print() + elif "unreal" in args.target or args.target == "console": + install_unreal_package() elif args.target == "iossim": # Install the ios_tests wrapper app on the simulator. subprocess.check_call(["xcrun", "simctl", "install", args.ios_udid,