mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[MG_Remote, android-plugin] (P6): a real phone retraces a real trace across two processes
OpenRA.DirectGLES, transport=spawn, on a Redmi: ssim=1.000000,
mismatchPixels=0, zero Fatal{ lines, three runs for three. The server is a
process the client launched out of the APK's lib/arm64/, and the client's own
log names its pid.
Four things stood between the desktop green and the device green, and every
one of them was invisible on desktop for the same reason: a build tree is not
a deployment, and Linux is not Android.
1. THE SERVER COULD NOT LINK. It links libMobileGL.so and is EXEC'd, not
dlopen'd, so it gets a fresh linker namespace with the DEFAULT search path
- and an APK's lib/<abi>/ is not on it. `CANNOT LINK EXECUTABLE ...:
library "libMobileGL.so" not found: needed by main executable`, before a
single line of MobileGL ran. On desktop CMake had been giving the target an
absolute build-tree RPATH, so the WSL server resolved its dependency
through a path no phone has. $ORIGIN is asked for via BUILD_RPATH (a raw
-Wl,-rpath,$ORIGIN reaches the generator unquoted and the SHELL eats it -
the device linker said `normalize_path - invalid input: "$"`), and because
the NDK drops RPATH from the link anyway, the LAUNCHER states
LD_LIBRARY_PATH: it is the one component that has already resolved where
the image lives, and a pair that is not co-located is not a pair.
2. THE RENDEZVOUS NEEDED A WRITABLE DIRECTORY. An Android app has no /tmp, so
bind() in the child had nowhere to put the node and the client refused by
name 20 s later. AF_UNIX endpoints now accept the ABSTRACT namespace with a
leading '@' - the systemd/D-Bus convention - which has no filesystem
presence at all: no directory, no mode bits, and no stale node to unlink
after a crash, which is the bind() failure Listen() has been working
around. Its reach is the network namespace, which for an app is the app.
StartSpawned mints '@' names; an explicit path still works everywhere, and
that is what P12's "connect to something somebody else is listening on"
will use.
3. PBUFFER WAS A DirectGLES-ONLY KNOB. Twice over: trace-replay-ci.sh gated
`--ez use_pbuffer true` on the backend name, and the JNI demanded a native
window for DirectVulkan unconditionally. A surface SHAPE is not a backend
property, and the coupling mattered because the Android GLWS makes a window
surface whenever gNativeWindow is non-null - so handing Magma a window was
the same as asking for one. Until P12 a spawned server cannot be given a
window at all: an ANativeWindow* is a pointer into the CLIENT's process and
SetWindowHandle is refused on the way across with Fatal{UnmigratedSurface,
"AndroidNativeWindow@P12"} (Rule H). Which is exactly what happened, one op
after the server had come up green.
4. THE RUNNER LOOKED IN ONE OF THE TWO OUTPUT DIRECTORIES. assembleTraceRelease
writes apk/trace/release; CI has staged the same artifact under
apk/trace/debug. A tree that has built locally has both, and picking the
wrong one retraces last month's APK and says nothing about it. Newest of
either, now.
MEASURED AND NOT FIXED: DirectVulkan on this device diverges under BOTH split
transports and does so nondeterministically - inproc scored ssim=0.988998 /
9836 px, spawn scored 0.976494 / 14658 px and then 0.988998 / 9836 px on a
repeat, while monolith with the same pbuffer surface scores 1.000000 / 0 px.
The two transports draw from the same set of outcomes, so this is the split
path on Magma against a real GPU, not the process boundary: P6 neither caused
it nor can fix it. DirectVulkan spawn IS green on desktop (lavapipe, 1.000000).
G14: one test name added, AnAbstractEndpointNeedsNoWritableDirectoryAndLeaves-
NoFile, which pins both halves - the handshake crosses an abstract name, and
nothing is left on the filesystem. A '@' mistaken for a path would have bound
a file of that literal name, passed here, and failed on the one platform this
exists for.
This commit is contained in:
@@ -170,9 +170,21 @@ Java_top_mobilegl_plugin_trace_TraceReplayActivity_nativeRunTraceReplay(JNIEnv*
|
||||
request.benchmarkResultPath = ToString(env, benchmarkResultPath);
|
||||
request.envOverrides = SplitSemicolonList(ToString(env, envOverrides));
|
||||
|
||||
const bool needsNativeWindow =
|
||||
request.backend == "DirectVulkan" ||
|
||||
(request.backend == "DirectGLES" && !request.usePbuffer);
|
||||
// THE SURFACE SHAPE DECIDES THIS, NOT THE BACKEND. DirectVulkan used to demand a native
|
||||
// window unconditionally, which made `use_pbuffer` a DirectGLES-only knob in practice: the
|
||||
// Android GLWS creates a window surface whenever gNativeWindow is non-null
|
||||
// (apitrace_glws_android.cpp's createSurface), so handing Magma a window was the same as
|
||||
// asking for one.
|
||||
//
|
||||
// P6 needs the pbuffer path on BOTH backends. Until P12 a spawned server cannot be given a
|
||||
// window at all - an ANativeWindow* is a pointer into the CLIENT's process, and
|
||||
// SetWindowHandle is refused on the way across with Fatal{UnmigratedSurface,
|
||||
// "AndroidNativeWindow@P12"} (Rule H). Measured: the DirectVulkan spawn arm died on exactly
|
||||
// that, one op after the server had come up green, while DirectGLES with the same flag passed.
|
||||
//
|
||||
// Every existing caller is unaffected: nobody asks for a Vulkan pbuffer today, and
|
||||
// !usePbuffer reproduces the old answer for both backends in every other combination.
|
||||
const bool needsNativeWindow = !request.usePbuffer;
|
||||
ANativeWindow *window = needsNativeWindow && surface != nullptr ? ANativeWindow_fromSurface(env, surface) : nullptr;
|
||||
if (needsNativeWindow && window == nullptr) {
|
||||
auto result = MakeFailureResult(request, mobilegl_trace::STATUS_RETRACE_FAILED,
|
||||
|
||||
@@ -44,7 +44,7 @@ Set MOBILEGL_ESPRYT_USE_ANGLE=1 to run DirectGLES replay with packaged ANGLE
|
||||
instead of the device system GLES driver.
|
||||
Set MOBILEGL_TRACE_ANGLE_VARIANT to the packaged ANGLE short hash used by
|
||||
DirectGLES replay.
|
||||
Set MOBILEGL_RETRACE_USE_PBUFFER=1 or pass --use-pbuffer to run DirectGLES
|
||||
Set MOBILEGL_RETRACE_USE_PBUFFER=1 or pass --use-pbuffer to run
|
||||
against an offscreen EGL pbuffer instead of the Activity surface.
|
||||
Set MOBILEGL_MAGMA_FIX_ITERATIONRP_SUBGROUP_SCRATCH=1,
|
||||
MOBILEGL_MAGMA_DERIVE_NUM_SUBGROUPS=1, and MOBILEGL_MAGMA_ITERATIONRP_FIX_BARRIER=1 to
|
||||
@@ -366,7 +366,7 @@ run_retrace() {
|
||||
use_angle=1
|
||||
test -n "${MOBILEGL_TRACE_ANGLE_VARIANT:-}" || die "MOBILEGL_TRACE_ANGLE_VARIANT is required for DirectGLES ANGLE replay"
|
||||
fi
|
||||
if [ "${MOBILEGL_RETRACE_USE_PBUFFER:-}" = "1" ] && [ "${backend}" = "DirectGLES" ]; then
|
||||
if [ "${MOBILEGL_RETRACE_USE_PBUFFER:-}" = "1" ]; then
|
||||
use_pbuffer=1
|
||||
fi
|
||||
|
||||
@@ -392,7 +392,13 @@ run_retrace() {
|
||||
set -- "$@" --ez use_angle true
|
||||
set -- "$@" --es angle_variant "${MOBILEGL_TRACE_ANGLE_VARIANT}"
|
||||
fi
|
||||
if [ "${use_pbuffer}" -eq 1 ] && [ "${backend}" = "DirectGLES" ]; then
|
||||
# PBUFFER IS A SURFACE SHAPE, NOT A BACKEND PROPERTY, and the DirectGLES condition that used to
|
||||
# guard this line made it one. It was harmless while the only caller was the ANGLE lane; P6 needs
|
||||
# it on BOTH backends, because until P12 the spawn arm can only use pbuffer/surfaceless - an
|
||||
# ANativeWindow* is a pointer into the CLIENT's process and SetWindowHandle is refused by name
|
||||
# with Fatal{UnmigratedSurface, "AndroidNativeWindow@P12"} on the way across. Magma creates an
|
||||
# EGL pbuffer exactly as Espryt does.
|
||||
if [ "${use_pbuffer}" -eq 1 ]; then
|
||||
set -- "$@" --ez use_pbuffer true
|
||||
fi
|
||||
if [ "${avoid_angle_llvmpipe_sampler_mipmap_min_filter}" -eq 1 ] && [ "${backend}" = "DirectGLES" ]; then
|
||||
|
||||
Reference in New Issue
Block a user