Skip to content

Fix tvOS simulator support (Jolt sim archive, libc++, CAMetalLayer present, wgpu limits, file I/O) - #58

Merged
proggeramlug merged 3 commits into
mainfrom
fix/tvos-simulator-support
Jun 8, 2026
Merged

Fix tvOS simulator support (Jolt sim archive, libc++, CAMetalLayer present, wgpu limits, file I/O)#58
proggeramlug merged 3 commits into
mainfrom
fix/tvos-simulator-support

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Summary

A game compiled for --target tvos-simulator failed to run on the tvOS simulator at five separate points. This PR fixes all of them; the result is the full game (title screen and gameplay — tiles, sprites, enemies, HUD) rendering correctly on the Apple TV simulator.

Each failure was found by fixing the prior one and re-running, so they're layered:

#SymptomRoot causeFix
1Link error: building for 'tvOS-simulator', but linking in object file built for 'tvOS'find_prebuilt_dir keyed jolt-prebuilt only on {os}-{arch}, so every Apple *-sim target linked the device Jolt archiveAppend -sim when CARGO_CFG_TARGET_ABI == "sim" to select the shipped <os>-<arch>-sim archive
2Link error: unresolved ___cxa_guard_acquire/releasetvos target declared frameworks but no libs; Jolt's C++ needs libc++Add "libs": ["c++"] (matches macos)
3Runtime panic: request_deviceLimitsExceeded { max_inter_stage_shader_variables: requested 16, allowed 15 }Requested wgpu::Limits::default(); the simulator's Metal caps it at 15Clamp that field to adapter.limits()
4App runs, render loop healthy, but screen is black (only UIKit subviews show)CAMetalLayer.presentsWithTransaction = YES — incompatible with wgpu's async -presentDrawable:; CoreAnimation waits for a CATransaction commit that never happensSet it to NO (both scene_will_connect and deferred_init)
5SIGSEGV at 0xfffffffffffffff8 entering a levelbloom_read_file returned null on a missing file; Perry's inline .length dereferences (ptr-8). Also used the obsolete 8-byte string header (data@8 vs 0.5.x's 20-byte StringHeader data@20), corrupting even valid readsRoute both branches through alloc_perry_string; return an empty string, never null

Also removes two leftover debug UILabels that were drawn over the game to verify window visibility.

Scope note

Fix#1 (build.rs) also repairs the iOS and watchOS simulator link paths, which had the same device-archive bug.

Validation

  • Built bloom-tvos for aarch64-apple-tvos-sim — compiles clean.
  • The equivalent changes against the published 0.4.12 build run the full game on the Apple TV 4K (3rd gen) tvOS 26 simulator: title screen, then a playable level (player, grass/dirt tiles, coins, walker enemies, spikes, gem, HUD hearts/lives).

Note: a companion fix is needed in the Perry compiler so the tvOS bundle includes the project assets/ dir (it currently skips the resource copy that iOS/watchOS/visionOS do) — submitted separately to PerryTS/perry. Without it the engine runs but level/sprite files aren't in the bundle.

find_prebuilt_dir keyed the jolt-prebuilt lookup only on
{target_os}-{target_arch}, so every Apple *-sim target (tvos/ios/watchos)
resolved to the device archive (e.g. tvos-arm64) and linked a device-built
Jolt object into a simulator build. ld then rejects it:
building for 'tvOS-simulator', but linking in object file built for 'tvOS'
jolt-prebuilt already ships the correct <os>-<arch>-sim archives; select
them by appending -sim when CARGO_CFG_TARGET_ABI == "sim". Device builds
are unaffected. Fixes the link step for the tvOS/iOS/watchOS simulators.
The tvos target in perry.nativeLibrary.targets declared frameworks but no
libs, unlike macos which lists ["c++"]. The Jolt C++ objects pull in
libc++ symbols (___cxa_guard_acquire/release, etc.), so a tvOS link failed
with unresolved symbols. Add "libs": ["c++"] to match macos.
… I/O
Three runtime bugs that prevented the tvOS native layer from running a game,
plus debug-scaffold cleanup:
- CAMetalLayer.presentsWithTransaction was YES in both scene_will_connect and
deferred_init. wgpu presents its drawable asynchronously via
-presentDrawable:, which is incompatible: CoreAnimation waits for a
synchronous CATransaction commit that never comes, so the layer never
displays rendered frames (screen stays black behind UIKit subviews). Set NO.
- request_device asked for wgpu::Limits::default()
(max_inter_stage_shader_variables = 16), but the tvOS/iOS simulators' Metal
only allows 15, so device creation panicked with LimitsExceeded. Clamp that
limit to adapter.limits(); real hardware meets/exceeds default() so it is
unchanged.
- bloom_read_file returned std::ptr::null() on a missing/unreadable file and
hand-rolled the obsolete Perry-0.4 8-byte string header. Perry 0.5.x reads
.length by dereferencing (ptr - 8), so a null string segfaults the caller,
and the 8-byte header (data@8 vs the 0.5.x 20-byte StringHeader's data@20)
returned garbage even for existing files. Route both branches through
alloc_perry_string; return an empty string, never null.
- Remove two debug UILabels ("BLOOM JUMP TVOS" / "...DEBUG") that were
drawn over the game to verify window visibility.
@proggeramlug
proggeramlug merged commit 38eaf0e into mainJun 8, 2026
8 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cascaded shadow maps (CSM)

1 participant

@proggeramlug