From f8eab65c7de1fb2867c6e735ba4c1fbedd96daeb Mon Sep 17 00:00:00 2001 From: izzy2lost Date: Thu, 12 Mar 2026 21:01:10 -0400 Subject: [PATCH] switched to linux env --- android/app/src/main/cpp/CMakeLists.txt | 31 ++++++++++-- .../src/main/cpp/xemu_notifications_stub.c | 50 +++++++++++++++++++ android/gradle.properties | 1 - android/gradlew | 2 +- hw/xbox/nv2a/pgraph/vk/renderer.c | 27 +++++++--- ui/xemu.c | 33 ++++++++++-- 6 files changed, 127 insertions(+), 17 deletions(-) diff --git a/android/app/src/main/cpp/CMakeLists.txt b/android/app/src/main/cpp/CMakeLists.txt index f3d39cf0b5..e2943ab2dd 100644 --- a/android/app/src/main/cpp/CMakeLists.txt +++ b/android/app/src/main/cpp/CMakeLists.txt @@ -9,9 +9,9 @@ include(FetchContent) include(ExternalProject) get_filename_component(REPO_ROOT "${CMAKE_CURRENT_LIST_DIR}/../../../../.." ABSOLUTE) -find_program(PYTHON_EXECUTABLE python) +find_program(PYTHON_EXECUTABLE NAMES python3 python) if(NOT PYTHON_EXECUTABLE) - message(FATAL_ERROR "python not found in PATH; required for QAPI/trace generation") + message(FATAL_ERROR "python3/python not found in PATH; required for QAPI/trace generation") endif() option(XEMU_ENABLE_VULKAN "Enable Vulkan renderer" ON) @@ -24,6 +24,11 @@ if(CARGO_EXECUTABLE MATCHES "-NOTFOUND$" OR NOT CARGO_EXECUTABLE) if(EXISTS "${CARGO_USERPROFILE_BIN}") set(CARGO_EXECUTABLE "${CARGO_USERPROFILE_BIN}" CACHE FILEPATH "Path to cargo executable" FORCE) endif() + elseif(DEFINED ENV{HOME}) + file(TO_CMAKE_PATH "$ENV{HOME}/.cargo/bin/cargo" CARGO_HOME_BIN) + if(EXISTS "${CARGO_HOME_BIN}") + set(CARGO_EXECUTABLE "${CARGO_HOME_BIN}" CACHE FILEPATH "Path to cargo executable" FORCE) + endif() endif() endif() set(XEMU_XISO_CONVERTER_BUILD_ENABLED ${XEMU_ENABLE_XISO_CONVERTER}) @@ -165,7 +170,25 @@ if(NOT ANDROID_API) endif() set(ANDROID_TRIPLE "aarch64-none-linux-android${ANDROID_API}") -set(NDK_TOOLCHAIN "${NDK_PATH}/toolchains/llvm/prebuilt/windows-x86_64/bin") +if(CMAKE_HOST_WIN32) + set(NDK_HOST_TAG "windows-x86_64") +elseif(CMAKE_HOST_APPLE) + if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)$") + set(NDK_HOST_TAG "darwin-arm64") + else() + set(NDK_HOST_TAG "darwin-x86_64") + endif() +elseif(CMAKE_HOST_UNIX) + set(NDK_HOST_TAG "linux-x86_64") +else() + message(FATAL_ERROR "Unsupported host platform for Android NDK: ${CMAKE_HOST_SYSTEM_NAME}") +endif() + +set(NDK_PREBUILT_DIR "${NDK_PATH}/toolchains/llvm/prebuilt/${NDK_HOST_TAG}") +if(NOT EXISTS "${NDK_PREBUILT_DIR}") + message(FATAL_ERROR "Android NDK host toolchain not found at ${NDK_PREBUILT_DIR}") +endif() +set(NDK_TOOLCHAIN "${NDK_PREBUILT_DIR}/bin") if(XEMU_XISO_CONVERTER_BUILD_ENABLED) if(CMAKE_HOST_WIN32) @@ -276,7 +299,7 @@ file(WRITE "${GLIB_CROSS_FILE}" "\n" "[properties]\n" "needs_exe_wrapper = true\n" -"sys_root = '${NDK_PATH}/toolchains/llvm/prebuilt/windows-x86_64/sysroot'\n" +"sys_root = '${NDK_PREBUILT_DIR}/sysroot'\n" "c_args = ['--target=${ANDROID_TRIPLE}', '-I${CMAKE_CURRENT_LIST_DIR}/iconv_stub']\n" "cpp_args = ['--target=${ANDROID_TRIPLE}', '-I${CMAKE_CURRENT_LIST_DIR}/iconv_stub']\n" "c_link_args = ['--target=${ANDROID_TRIPLE}', '-L${ICONV_STUB_DIR}', '-liconv']\n" diff --git a/android/app/src/main/cpp/xemu_notifications_stub.c b/android/app/src/main/cpp/xemu_notifications_stub.c index 4756ee4709..01a7e651c7 100644 --- a/android/app/src/main/cpp/xemu_notifications_stub.c +++ b/android/app/src/main/cpp/xemu_notifications_stub.c @@ -1,9 +1,59 @@ #include +#include +#include + +static void xemu_android_show_toast(const char *msg, int duration) +{ + if (!msg || !msg[0]) { + return; + } + + JNIEnv *env = (JNIEnv *)SDL_AndroidGetJNIEnv(); + jobject activity = (jobject)SDL_AndroidGetActivity(); + if (!env || !activity) { + return; + } + + jclass activity_class = (*env)->GetObjectClass(env, activity); + if (!activity_class) { + return; + } + + jmethodID show_toast = (*env)->GetStaticMethodID( + env, activity_class, "showToast", "(Ljava/lang/String;IIII)I"); + if (!show_toast) { + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionClear(env); + } + (*env)->DeleteLocalRef(env, activity_class); + return; + } + + jstring message = (*env)->NewStringUTF(env, msg); + if (!message) { + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionClear(env); + } + (*env)->DeleteLocalRef(env, activity_class); + return; + } + + (*env)->CallStaticIntMethod(env, activity_class, show_toast, + message, duration, -1, 0, 0); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionClear(env); + } + + (*env)->DeleteLocalRef(env, message); + (*env)->DeleteLocalRef(env, activity_class); +} + void xemu_queue_notification(const char *msg) { if (msg) { fprintf(stderr, "[xemu] %s\n", msg); + xemu_android_show_toast(msg, 0); } } diff --git a/android/gradle.properties b/android/gradle.properties index adab58750b..b77f9c6803 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,4 @@ org.gradle.jvmargs=-Xmx512m -Dfile.encoding=UTF-8 -org.gradle.java.home=C:\\Program Files\\Zulu\\zulu-21 org.gradle.workers.max=1 org.gradle.parallel=false android.useAndroidX=true diff --git a/android/gradlew b/android/gradlew index d80251b4ef..c230992edf 100644 --- a/android/gradlew +++ b/android/gradlew @@ -1,6 +1,6 @@ #!/usr/bin/env sh -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +DEFAULT_JVM_OPTS="-Xmx64m -Xms64m" APP_HOME="$(cd "${0%/*}" && pwd -P)" CLASSPATH="$APP_HOME/gradle/wrapper/gradle-wrapper.jar" diff --git a/hw/xbox/nv2a/pgraph/vk/renderer.c b/hw/xbox/nv2a/pgraph/vk/renderer.c index ba0d079677..7da47e6485 100644 --- a/hw/xbox/nv2a/pgraph/vk/renderer.c +++ b/hw/xbox/nv2a/pgraph/vk/renderer.c @@ -19,6 +19,7 @@ #include "hw/xbox/nv2a/nv2a_int.h" #include "renderer.h" +#include "qapi/error.h" #include "gloffscreen.h" @@ -49,8 +50,6 @@ static void pgraph_vk_init(NV2AState *d, Error **errp) { PGRAPHState *pg = &d->pgraph; - pg->vk_renderer_state = (PGRAPHVkState *)g_malloc0(sizeof(PGRAPHVkState)); - #if HAVE_EXTERNAL_MEMORY bool use_external_memory = false; #ifdef __ANDROID__ @@ -70,17 +69,33 @@ static void pgraph_vk_init(NV2AState *d, Error **errp) glo_set_current(g_gl_context); use_external_memory = pgraph_vk_gl_external_memory_available(); } +#ifdef __ANDROID__ if (!use_external_memory) { -#ifdef __ANDROID__ __android_log_print(ANDROID_LOG_WARN, "xemu-android", - "pgraph_vk_init: external memory interop unavailable, using download fallback"); -#endif + "pgraph_vk_init: external memory interop unavailable, falling back to OpenGL"); + if (g_gl_context) { + glo_context_destroy(g_gl_context); + g_gl_context = NULL; + } + error_setg(errp, + "Vulkan display interop unavailable on this device"); + return; } -#ifdef __ANDROID__ __android_log_print(ANDROID_LOG_INFO, "xemu-android", "pgraph_vk_init: external memory interop=%s", use_external_memory ? "enabled" : "disabled"); #endif +#elif defined(__ANDROID__) + __android_log_print(ANDROID_LOG_WARN, "xemu-android", + "pgraph_vk_init: Vulkan external-memory interop not built, falling back to OpenGL"); + error_setg(errp, + "Vulkan display interop unavailable in this build"); + return; +#endif + + pg->vk_renderer_state = (PGRAPHVkState *)g_malloc0(sizeof(PGRAPHVkState)); + +#if HAVE_EXTERNAL_MEMORY pg->vk_renderer_state->display.use_external_memory = use_external_memory; #endif diff --git a/ui/xemu.c b/ui/xemu.c index 769fb0416a..c9681519a1 100644 --- a/ui/xemu.c +++ b/ui/xemu.c @@ -135,12 +135,34 @@ static uint64_t g_android_frame_counter = 0; static int g_android_target_fps = 60; static int64_t g_android_frame_interval_ns = 16666666; static int g_android_display_mode = 0; /* 0=stretch, 1=4:3, 2=16:9 */ +static int g_android_render_logs_enabled = -1; static bool sdl2_is_render_thread(void) { return sdl_render_thread_id != 0 && SDL_ThreadID() == sdl_render_thread_id; } +static bool android_render_logs_enabled(void) +{ + if (g_android_render_logs_enabled < 0) { + const char *value = SDL_getenv("XEMU_ANDROID_RENDER_LOGS"); + g_android_render_logs_enabled = + (value && value[0] != '\0' && value[0] != '0') ? 1 : 0; + if (g_android_render_logs_enabled) { + __android_log_print(ANDROID_LOG_INFO, "xemu-android", + "android: verbose render logging enabled"); + } + } + return g_android_render_logs_enabled != 0; +} + +static bool android_should_log_render_periodic(uint64_t period) +{ + return android_render_logs_enabled() && + period != 0 && + (g_android_frame_counter % period) == 0; +} + static bool sdl2_gl_has_extension(const char *ext_list, const char *ext) { if (!ext_list || !ext || !ext[0]) { @@ -260,7 +282,7 @@ static void sdl2_gl_render_texture(struct sdl2_console *scon, } #ifdef __ANDROID__ - if ((g_android_frame_counter % 60) == 0) { + if (android_should_log_render_periodic(60)) { __android_log_print(ANDROID_LOG_INFO, "xemu-android", "present drawable=%dx%d window=%dx%d viewport=%d,%d %dx%d tex=%u flip=%d mode=%d", w, h, ww, wh, vx, vy, vw, vh, @@ -1553,13 +1575,14 @@ void sdl2_gl_refresh(DisplayChangeListener *dcl) return; } if (g_android_paused || scon->hidden) { - if ((g_android_frame_counter++ % 120) == 0) { + if (android_should_log_render_periodic(120)) { __android_log_print(ANDROID_LOG_INFO, "xemu-android", "refresh paused: hidden=%d paused=%d runstate=%d", scon->hidden ? 1 : 0, g_android_paused ? 1 : 0, (int)runstate_get()); } + g_android_frame_counter++; qemu_mutex_lock_main_loop(); bql_lock(); sdl2_poll_events(scon); @@ -1604,7 +1627,7 @@ void sdl2_gl_refresh(DisplayChangeListener *dcl) GLuint tex = nv2a_get_framebuffer_surface(); #ifdef __ANDROID__ if (tex != 0 && glIsTexture(tex) == GL_FALSE) { - if ((g_android_frame_counter % 120) == 0) { + if (android_should_log_render_periodic(120)) { __android_log_print(ANDROID_LOG_WARN, "xemu-android", "refresh: nv2a tex %u not valid in display context", (unsigned)tex); @@ -1614,7 +1637,7 @@ void sdl2_gl_refresh(DisplayChangeListener *dcl) #endif #ifdef __ANDROID__ android_log_gl_error("refresh-get-fb"); - if ((g_android_frame_counter % 120) == 0) { + if (android_should_log_render_periodic(120)) { __android_log_print(ANDROID_LOG_INFO, "xemu-android", "refresh frame=%llu tex=%u flip=%d surface=%p size=%dx%d runstate=%d", (unsigned long long)g_android_frame_counter, @@ -1641,7 +1664,7 @@ void sdl2_gl_refresh(DisplayChangeListener *dcl) tex = scon->surface->texture; flip_required = true; #ifdef __ANDROID__ - if ((g_android_frame_counter % 120) == 0) { + if (android_should_log_render_periodic(120)) { __android_log_print(ANDROID_LOG_INFO, "xemu-android", "refresh no nv2a fb, using surface texture=%u", (unsigned)tex);