// issue-0026: Chess game on iOS-sim with `plat.gpu_mode = .metal` crashes // inside `[MTLTexture replaceRegion:mipmapLevel:withBytes:bytesPerRow:]` // when uploading the 1024×1024 R8 font atlas. The 1×1 RGBA8 white tex // through the SAME code path (metal_update_texture_region_ios in // library/modules/gpu/metal.sx) works. // // Blocked on issue-0024 (NSLog inside if/else not firing — or unified-log // buffer loss on crash; investigation pending) — without a trustworthy // tracer we can't reliably bisect which arg arrives wrong. Most likely // cause: this is downstream of issue-0025's ABI gaps (MTLRegion is 48 // bytes and goes through `xx objc_msgSend` cast, which is the // call_indirect path that issue-0025 part B covers). // // ── Reproduction recipe ─────────────────────────────────────────────────── // // cd /Users/agra/projects/game // /Users/agra/projects/sx/zig-out/bin/sx build --target ios-sim main.sx \ // --bundle sx-out/ios/SxChess.app --bundle-id co.swipelab.sxchess \ // -F ~/Library/Frameworks // cp -R assets sx-out/ios/SxChess.app/ // codesign --force --sign - --timestamp=none sx-out/ios/SxChess.app // xcrun simctl install booted sx-out/ios/SxChess.app // xcrun simctl launch --terminate-running-process booted co.swipelab.sxchess // sleep 4 && xcrun simctl io booted screenshot /tmp/sx-chess.png // // Expected (after fix): chess board renders via Metal. // Observed: app launches, returns immediately to home screen, no screen // touched. The simpler examples/63-metal-clear.sx demo still renders the // colored triangle on the same sim, so the Metal pipeline itself works // for small uploads. // // ── Candidate root causes (in priority order) ───────────────────────────── // // 1. issue-0025 fallout (most likely): MTLRegion (48 B by value) passed // via the *MTLRegion workaround. The call_indirect path (issue-0025 // part B) doesn't ABI-coerce, so the pointer-shaped declaration may // not actually pass the address in the right register slot for that // call site shape (6 args, including the indirect aggregate). // // 2. iOS-sim Metal-driver limitation: `setStorageMode:.shared` may not be // honored for r8 textures of this size; default may be `.private` // which precludes CPU-side replaceRegion. Workaround would be to // upload via `MTLBuffer` + `MTLBlitCommandEncoder` (newBufferWithBytes // + copyFromBuffer:sourceOffset:sourceBytesPerRow:...:toTexture:...). // // 3. sx-side `xx` cast bug: bytes_per_row : u64 = xx (u32_expr) may // truncate or sign-extend incorrectly. Less likely (the math comes // out to 1024, which fits in any width). // // ── How to resolve ──────────────────────────────────────────────────────── // // After issues 0024 + 0025 are landed: // 1. Re-add the trace NSLog markers ("[metal] U1..U5" in // metal_update_texture_region_ios) — now they should actually print. // 2. Re-build + relaunch chess on iOS-sim. // 3. If U5 fires after U4 (no crash inside msg_replace), the bug was // ABI-related; declare success and rename this file to // examples/NN-metal-large-region-upload.sx (next free NN). // 4. If U4 → crash persists, fall back to the MTLBuffer + blit // encoder path in metal.sx's create_texture (when pixels != null, // allocate a temporary MTLBuffer with newBufferWithBytes:length:options: // then run a one-shot command buffer with a MTLBlitCommandEncoder // copying the buffer into the texture). This is the Apple-recommended // approach for large texture initial-uploads. #import "modules/std.sx"; main :: () -> s32 { 0; }