mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Feat] (Trace): the replay runner builds as an adb-shell executable for Android, and unix endpoints carry a headless window
MOBILEGL_BUILD_TRACE_REPLAY now also produces mobilegl_trace_replay on ANDROID: the same CLI as desktop, linked against the APK runner's glws/glproc glue. On the device it dials a render server with no Activity at all - MOBILEGL_IPC_CONTROL=unix:@name with shm data to the offscreen supervisor (a cross-uid abstract connect needs root or an SELinux waiver; loopback TCP works from plain adb shell), or tcp:// with MOBILEGL_IPC_SURFACE=server to the on-screen display server. glws_android grows the desktop glws_egl's server-owned null-window createWindowSurface, gated on MOBILEGL_TRACE_SURFACE=window so the APK's pbuffer mode keeps its old answer, and the config carries EGL_WINDOW_BIT for it. The control screen refuses unix endpoints in on-screen mode: the in-process display server serves tcp:// only. Verified on-device with an OpenRA retrace, ssim=1.0 both ways: offscreen service on @mgl-cli with the CLI as root, and the display Activity on tcp://127.0.0.1:40613 with the replay's frames on the phone's screen.
This commit is contained in:
@@ -982,6 +982,12 @@ if (ANDROID AND MOBILEGL_BUILD_INTEGRATION_TEST)
|
||||
add_subdirectory(MobileGL/MG_IntegrationTest)
|
||||
endif()
|
||||
|
||||
# The replay runner also builds for Android: an adb-shell executable that can
|
||||
# dial a render server on the device (unix or TCP) without any Activity.
|
||||
if (ANDROID AND MOBILEGL_BUILD_TRACE_REPLAY)
|
||||
add_subdirectory(tools/trace_replay)
|
||||
endif()
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# P0 spike A: the Android delivery chain for a second native executable.
|
||||
#
|
||||
|
||||
@@ -75,6 +75,14 @@ int ResolveHeight(int height) {
|
||||
return height > 0 ? height : 1;
|
||||
}
|
||||
|
||||
// A HEADLESS command-line replay (no ANativeWindow) that still wants a window surface: the
|
||||
// window will be the MobileGL server's (MOBILEGL_IPC_SURFACE=server), so the config must
|
||||
// carry EGL_WINDOW_BIT for the null-window eglCreateWindowSurface in createSurface.
|
||||
bool WantsServerOwnedWindow() {
|
||||
const char *mode = std::getenv("MOBILEGL_TRACE_SURFACE");
|
||||
return gNativeWindow == nullptr && mode != nullptr && std::strcmp(mode, "window") == 0;
|
||||
}
|
||||
|
||||
void *Lookup(const char *name) {
|
||||
if (gMobileGl == nullptr) {
|
||||
gMobileGl = dlopen("libMobileGL.so", RTLD_NOW | RTLD_GLOBAL | RTLD_NOLOAD);
|
||||
@@ -206,6 +214,22 @@ private:
|
||||
static_cast<const AndroidVisual *>(visual)->config,
|
||||
gNativeWindow,
|
||||
nullptr);
|
||||
} else if (!pbuffer && WantsServerOwnedWindow()) {
|
||||
// HEADLESS COMMAND-LINE REPLAY (P12 D9, same shape as the desktop glws_egl path):
|
||||
// the window is the MobileGL SERVER's (MOBILEGL_IPC_SURFACE=server,
|
||||
// WindowKind::ServerOwned), so the native window is none and the size the trace
|
||||
// wants rides EGL_WIDTH/EGL_HEIGHT. Gated on MOBILEGL_TRACE_SURFACE=window so the
|
||||
// APK's pbuffer mode (no ANativeWindow either) keeps its pbuffer.
|
||||
const EGLint windowAttribs[] = {
|
||||
EGL_WIDTH, surfaceWidth,
|
||||
EGL_HEIGHT, surfaceHeight,
|
||||
EGL_NONE,
|
||||
};
|
||||
surface = gEgl.createWindowSurface(
|
||||
gDisplay,
|
||||
static_cast<const AndroidVisual *>(visual)->config,
|
||||
EGLNativeWindowType{},
|
||||
windowAttribs);
|
||||
} else {
|
||||
const EGLint attribs[] = {
|
||||
EGL_WIDTH, surfaceWidth,
|
||||
@@ -334,7 +358,8 @@ Visual *createVisual(bool doubleBuffer, unsigned samples, Profile profile) {
|
||||
}
|
||||
|
||||
const EGLint attribs[] = {
|
||||
EGL_SURFACE_TYPE, gNativeWindow == nullptr ? EGL_PBUFFER_BIT : EGL_WINDOW_BIT,
|
||||
EGL_SURFACE_TYPE,
|
||||
gNativeWindow == nullptr && !WantsServerOwnedWindow() ? EGL_PBUFFER_BIT : EGL_WINDOW_BIT,
|
||||
EGL_RENDERABLE_TYPE,
|
||||
visual->api == EGL_OPENGL_ES_API ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_BIT,
|
||||
EGL_RED_SIZE, 8,
|
||||
|
||||
@@ -98,7 +98,7 @@ public final class ServerControlActivity extends Activity {
|
||||
envField = addField(contentLayout, "Extra env (optional)", "", dp(8));
|
||||
|
||||
onScreenBox = new CheckBox(this);
|
||||
onScreenBox.setText("On-screen window (render client frames onto this screen)");
|
||||
onScreenBox.setText("On-screen window (render client frames onto this screen; tcp:// only)");
|
||||
onScreenBox.setTextColor(COLOR_TEXT);
|
||||
onScreenBox.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13);
|
||||
LinearLayout.LayoutParams boxParams = new LinearLayout.LayoutParams(
|
||||
@@ -155,6 +155,14 @@ public final class ServerControlActivity extends Activity {
|
||||
String token = tokenField.getText().toString();
|
||||
String env = envField.getText().toString().trim();
|
||||
|
||||
// The in-process display server only accepts tcp:// (ServerMain's in-process arm);
|
||||
// the unix forms belong to the offscreen supervisor.
|
||||
if (onScreenBox.isChecked() && !endpoint.startsWith("tcp://")) {
|
||||
setStatus("The on-screen display server serves tcp:// only; use a tcp:// endpoint "
|
||||
+ "or uncheck On-screen window.", COLOR_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
String probeDisplay;
|
||||
Probe probe;
|
||||
if (endpoint.startsWith("tcp://")) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.22.1)
|
||||
|
||||
if(NOT UNIX OR ANDROID)
|
||||
message(STATUS "MobileGL trace replay runner is only enabled on desktop Unix")
|
||||
if(NOT UNIX)
|
||||
message(STATUS "MobileGL trace replay runner is only enabled on Unix (Android included)")
|
||||
return()
|
||||
endif()
|
||||
|
||||
@@ -139,7 +139,9 @@ target_link_libraries(mobilegl_trace_common PUBLIC
|
||||
|
||||
add_library(mobilegl_trace_glproc STATIC
|
||||
"${APITRACE_GENERATED_DIR}/glproc.cpp"
|
||||
"${MOBILEGL_TRACE_ROOT}/apitrace_glproc_mobilegl.cpp")
|
||||
# Android resolves GL through the same loader glue as the APK runner; desktop
|
||||
# keeps its own.
|
||||
"$<IF:$<BOOL:${ANDROID}>,${MOBILEGL_TRACE_SHARED_CPP_DIR}/apitrace_glproc_android.cpp,${MOBILEGL_TRACE_ROOT}/apitrace_glproc_mobilegl.cpp>")
|
||||
if(APPLE)
|
||||
target_compile_definitions(mobilegl_trace_glproc PRIVATE GL_SILENCE_DEPRECATION)
|
||||
endif()
|
||||
@@ -225,7 +227,9 @@ add_library(mobilegl_trace_glretrace_common STATIC
|
||||
"${APITRACE_ROOT}/retrace/metric_helper.cpp"
|
||||
"${APITRACE_ROOT}/retrace/metric_writer.cpp"
|
||||
"${MOBILEGL_TRACE_ROOT}/apitrace_fbo_dump.cpp"
|
||||
"${MOBILEGL_TRACE_ROOT}/apitrace_glws_egl.cpp"
|
||||
# Android uses the APK runner's glws/glproc glue (pbuffer, or the server-owned
|
||||
# null-window surface for a headless replay); desktop uses the EGL one.
|
||||
"$<IF:$<BOOL:${ANDROID}>,${MOBILEGL_TRACE_SHARED_CPP_DIR}/apitrace_glws_android.cpp,${MOBILEGL_TRACE_ROOT}/apitrace_glws_egl.cpp>"
|
||||
"${MOBILEGL_TRACE_SHARED_CPP_DIR}/trace_benchmark.cpp")
|
||||
if(APPLE)
|
||||
set(MOBILEGL_TRACE_APPLE_FRAMEWORKS
|
||||
@@ -241,6 +245,7 @@ target_include_directories(mobilegl_trace_glretrace_common PUBLIC
|
||||
"${APITRACE_ROOT}/dispatch"
|
||||
"${APITRACE_ROOT}/helpers"
|
||||
"${APITRACE_ROOT}/retrace"
|
||||
"${MOBILEGL_TRACE_ROOT}"
|
||||
"${MOBILEGL_TRACE_SHARED_CPP_DIR}")
|
||||
target_compile_definitions(mobilegl_trace_glretrace_common PRIVATE
|
||||
exit=mobilegl_apitrace_exit
|
||||
@@ -280,6 +285,9 @@ else()
|
||||
${MOBILEGL_TRACE_REPLAY_LINK_LIBRARIES}
|
||||
"-Wl,--end-group")
|
||||
endif()
|
||||
if(ANDROID)
|
||||
target_link_libraries(mobilegl_trace_replay PRIVATE android log)
|
||||
endif()
|
||||
|
||||
# The `K=V;K=V` environment passthrough is the only hand-rolled parse between a CI flag
|
||||
# and setenv(), and the lane that exercises it end to end is an on-device retrace, which
|
||||
|
||||
Reference in New Issue
Block a user