master
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
725ffbd8ed |
arm64: flat guest mapping, audio, crash reporting, self-extracting data
The run of work that took the translated build from "boots" to "playable". Engine: - Flat guest mapping replaces the software MMU on aarch64 hosts. A 4 GiB PROT_NONE reservation lets a 32-bit guest address zero-extend safely, so tcg_out_qemu_ld/st short-circuit before tcg_out_tlb_read and the prologue materialises the base into X28. Measured 1.24x (51 vs 41 fps, interleaved A/B). Note the base must be set BEFORE UC_INIT - Unicorn inits lazily, and setting it after uc_open silently falls back to softmmu. - num_get<char> facet implemented, which was the real cause of the crash after the prologue race; a full race is now playable end to end. - Thread-stack free list + ReleaseThreadEngine, fixing the arena leak that showed up as a black screen when entering a race. kMaxGuestThreads 16 -> 64. - Real ARM32 FMOD now runs in-engine via the Java FMODAudioDevice bridge, with a per-thread JNIEnv. Two of the three blockers were our own single-image-era guards. Host/app: - Native crash handler: async-signal-safe, decodes the host fault back to a guest address, writes a report file and nothing else. CrashReportActivity picks it up on the NEXT launch, zips it, and offers to share. No backend, no automatic upload. - Game data ships inside the APK and self-extracts on first launch, so a tester installs one file and plays. Copy-to-.part-then-rename, with a free-space check up front. - EGL context preserved across pause, fixing black textures on resume. - Navigation bar hidden and re-hidden on focus gain; volume keys reported as system keys, checked before the loading-state gate. - x86_64 added to abiFilters: the ARM32 guest runs under tcg/i386 with no houdini in the path. The flat mapping is aarch64-only, so that host falls back to the software MMU - commented at the abiFilters line. Ignore rules added for app/translated/ (611 MB of signed release APK, which also carries the bundled OBB) and ostream_repro/build/. Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
7af48860eb |
Survey dynamic_cast call shapes + native rate counter: 84% need no hierarchy walk
Task #58 asked whether the engine induces the __dynamic_cast flood or the game does. A native LD_PRELOAD interposer added to trace_agent answers it: native ARM32 on the A9 calls it up to 824,200/sec, against this engine's 284,986/sec. The game is simply that RTTI-heavy, and native absorbs it because a real call costs tens of nanoseconds. Our rate is not demand, it is supply - the shim boundary is throttling the guest. (Interposing __dynamic_cast collides with libc++abi.a, which the NDK links statically into the agent; resolved with --allow-multiple-definition scoped to that target, since our object precedes the archive and wins.) That makes a guest-side implementation interesting: Shim_dynamic_cast is already a pure guest-memory walk - it reads the object's vtable, vtable[-1] (dynamic type) and vtable[-2] (offset-to-top), then compares type_info records. Nothing comes from the host, so the same algorithm could run as emulated ARM32 with NO boundary crossing at all. Whether that is worth doing depends on how big it would have to be, so this adds a temporary shape survey. Measured over a prologue load, 2.7M calls: exact (depth 0) 84.2% one base 0.4% deeper 0.0% (max depth reached all run: 3) not found 15.4% 84% of calls need NO hierarchy walk - the object's dynamic type already IS the target. A guest fast path of roughly six instructions (load vtable, compare vtable[-1] to the target, return ptr + vtable[-2]) with a fallback to this shim would eliminate 84% of dynamic_cast crossings, which is ~41% of ALL shim crossings given dynamic_cast is 49% of them. Also confirms there is no implementation to reuse inside libapp.so: not only __dynamic_cast but the type_info vtables themselves (__class_type_info, __si_class_type_info, __vmi_class_type_info, __pointer_type_info) are all UND - this engine supplies them from rtti_shims.cpp. Survey left in the tree behind kSurveyDynamicCast, default off. Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
d5e6037fc7 |
Stable checkpoint: game reaches playable 3D gameplay on ARM64
Verified live on a Pixel 6a: the game passes its EULA, loads the prologue and renders real 3D gameplay, with zero heap exhaustion, zero faults and zero rejected frees over a full session. Root causes fixed in this state, each backed by a measurement (details and the list of refuted theories live in ARM64_TRANSLATION_LAYER.md): * JNI varargs float->double promotion. C promotes float to double in any varargs call and every Call*Method form is varargs, so reading one 4-byte slot yielded the double's always-zero low half. EVERY float argument passed to Java was silently becoming 0; text was just where it showed. * GuestHeap ~4x memory overhead. Power-of-two size classes carving the full class, plus segregated free lists that could never share memory between sizes. Reworked to exact sizing with O(log n) best-fit reuse and splitting (deliberately not a linear scan - this allocator already had an O(n) perf cliff in its history). Peak live now 207MB against the real A9's 199MB, fragmentation ~2.5MB. Also fixed: realloc reading past the old block on shrink, a 32-bit overflow in calloc, and drifting payload alignment. * Unbounded FMOD fake-handle leak into the never-freeing permanent arena, which is why enlarging that arena had not helped. * Frame presentation, corrected against A9 ground truth: the real frame has three default-framebuffer colour clears and ONE present at the end; this engine had been presenting on each of them. Load-time acceleration (zlib_accel.cpp): host zlib now serves inflate and crc32, the latter measured by the block profiler as the single hottest guest routine at 17.7%. Streams are only taken over when this layer saw their own inflateInit2_, so unknown streams (libpng's, among others) still run the original emulated path. name_lookup_accel.cpp is present but its hook is NOT registered - it crashed on bad assumptions about guest table lifetime and is kept as a starting point, with both mistakes recorded in its comments. Co-Authored-By: Claude <noreply@anthropic.com> |