From fcfecd9ad2706fdce1a71c11ac4b524c4c11e701 Mon Sep 17 00:00:00 2001 From: izzy2lost Date: Sat, 4 Apr 2026 03:00:20 -0400 Subject: [PATCH] Better part 2? --- android/app/build.gradle.kts | 1 + android/app/src/main/cpp/CMakeLists.txt | 27 ++- .../src/main/cpp/android_crash_handler.cpp | 2 +- android/app/src/main/cpp/config-host.h | 16 +- android/app/src/main/cpp/samplerate_stub.c | 9 + android/app/src/main/cpp/xemu_android.cpp | 183 ++++++++++++------ .../app/src/main/cpp/xemu_settings_android.cc | 8 +- .../app/src/main/cpp/xiso_converter_jni.cpp | 106 +++++++++- hw/xbox/nv2a/pgraph/vk/instance.c | 25 ++- 9 files changed, 299 insertions(+), 78 deletions(-) diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 864f1669f7..b0978408e0 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -101,6 +101,7 @@ android { "META-INF/LICENSE*", "META-INF/NOTICE*" ) + /* Extract .so to disk (nativeLibraryDir); required for adrenotools hooks / custom GPU drivers. */ jniLibs.useLegacyPackaging = true jniLibs.keepDebugSymbols += setOf("**/*.so") } diff --git a/android/app/src/main/cpp/CMakeLists.txt b/android/app/src/main/cpp/CMakeLists.txt index c2944b6890..38ff746131 100644 --- a/android/app/src/main/cpp/CMakeLists.txt +++ b/android/app/src/main/cpp/CMakeLists.txt @@ -497,7 +497,6 @@ list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "ui[\\\\/]gtk.*\\.c$") list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "ui[\\\\/]sdl2.*\\.c$") list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "ui[\\\\/]console-gl\\.c$") list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "ui[\\\\/]console-vc\\.c$") -list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "ui[\\\\/]shader\\.c$") list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "ui[\\\\/]vnc.*\\.c$") list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "ui[\\\\/]xemu-snapshots\\.c$") list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "ui[\\\\/]xemu-thumbnail\\.cc$") @@ -671,6 +670,30 @@ endif() file(GLOB_RECURSE QAPI_GEN_SOURCES "${QAPI_GEN_DIR}/*.c") list(APPEND XEMU_CORE_SOURCES ${QAPI_GEN_SOURCES}) +# Generate GL shader headers used by ui/shader.c. +set(XEMU_SHADER_GEN_DIR "${CMAKE_BINARY_DIR}/ui/shader") +set(XEMU_SHADER_INPUTS + "${REPO_ROOT}/ui/shader/texture-blit.frag" + "${REPO_ROOT}/ui/shader/texture-blit.vert" + "${REPO_ROOT}/ui/shader/texture-blit-flip.vert" +) +file(MAKE_DIRECTORY "${XEMU_SHADER_GEN_DIR}") +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${XEMU_SHADER_INPUTS}) +foreach(SHADER_INPUT ${XEMU_SHADER_INPUTS}) + get_filename_component(SHADER_NAME "${SHADER_INPUT}" NAME) + string(REPLACE "." "-" SHADER_OUTPUT_BASENAME "${SHADER_NAME}") + set(SHADER_OUTPUT "${XEMU_SHADER_GEN_DIR}/${SHADER_OUTPUT_BASENAME}.h") + execute_process( + COMMAND "${PYTHON_EXECUTABLE}" "${REPO_ROOT}/scripts/shaderinclude.py" "${SHADER_INPUT}" + OUTPUT_FILE "${SHADER_OUTPUT}" + WORKING_DIRECTORY "${REPO_ROOT}" + RESULT_VARIABLE SHADER_GEN_RESULT + ) + if(NOT SHADER_GEN_RESULT EQUAL 0) + message(FATAL_ERROR "Shader header generation failed for ${SHADER_INPUT}") + endif() +endforeach() + # Generate block coroutine wrapper sources (block-gen.c). set(BLOCK_GEN_C "${CMAKE_BINARY_DIR}/block-gen.c") execute_process( @@ -922,6 +945,8 @@ add_library(xemu SHARED xemu_android.cpp android_crash_handler.cpp vmstate_if_android.c + xemu_fatx_import.c + xemu_hdd_tools_jni.c ) target_compile_definitions(xemu PRIVATE ANDROID __ANDROID__ XBOX CONFIG_SDL CONFIG_OPENGL diff --git a/android/app/src/main/cpp/android_crash_handler.cpp b/android/app/src/main/cpp/android_crash_handler.cpp index 61d551458e..3c4191923f 100644 --- a/android/app/src/main/cpp/android_crash_handler.cpp +++ b/android/app/src/main/cpp/android_crash_handler.cpp @@ -9,7 +9,7 @@ #include namespace { -constexpr const char* kCrashTag = "hakuX"; +constexpr const char* kCrashTag = "xemu-android"; constexpr size_t kPathMax = 512; static char g_inline_aio_flag_path[kPathMax]; diff --git a/android/app/src/main/cpp/config-host.h b/android/app/src/main/cpp/config-host.h index b437b3a566..c55d377f2f 100644 --- a/android/app/src/main/cpp/config-host.h +++ b/android/app/src/main/cpp/config-host.h @@ -11,14 +11,14 @@ #define CONFIG_AUDIO_DRIVERS "sdl", #define CONFIG_DEVICES "config-devices.h" -#define CONFIG_QEMU_DATADIR "/sdcard/Android/data/com.rfandango.haku_x/files" -#define CONFIG_QEMU_FIRMWAREPATH "/sdcard/Android/data/com.rfandango.haku_x/files/firmware", -#define CONFIG_SYSCONFDIR "/sdcard/Android/data/com.rfandango.haku_x/files/etc" -#define CONFIG_QEMU_CONFDIR "/sdcard/Android/data/com.rfandango.haku_x/files/etc/xemu" -#define CONFIG_QEMU_HELPERDIR "/sdcard/Android/data/com.rfandango.haku_x/files/bin" -#define CONFIG_PREFIX "/sdcard/Android/data/com.rfandango.haku_x/files" -#define CONFIG_BINDIR "/sdcard/Android/data/com.rfandango.haku_x/files/bin" -#define CONFIG_QEMU_LOCALSTATEDIR "/sdcard/Android/data/com.rfandango.haku_x/files/state" +#define CONFIG_QEMU_DATADIR "/sdcard/Android/data/com.izzy2lost.x1box/files" +#define CONFIG_QEMU_FIRMWAREPATH "/sdcard/Android/data/com.izzy2lost.x1box/files/firmware", +#define CONFIG_SYSCONFDIR "/sdcard/Android/data/com.izzy2lost.x1box/files/etc" +#define CONFIG_QEMU_CONFDIR "/sdcard/Android/data/com.izzy2lost.x1box/files/etc/xemu" +#define CONFIG_QEMU_HELPERDIR "/sdcard/Android/data/com.izzy2lost.x1box/files/bin" +#define CONFIG_PREFIX "/sdcard/Android/data/com.izzy2lost.x1box/files" +#define CONFIG_BINDIR "/sdcard/Android/data/com.izzy2lost.x1box/files/bin" +#define CONFIG_QEMU_LOCALSTATEDIR "/sdcard/Android/data/com.izzy2lost.x1box/files/state" #define CONFIG_BDRV_RW_WHITELIST #define CONFIG_BDRV_RO_WHITELIST diff --git a/android/app/src/main/cpp/samplerate_stub.c b/android/app/src/main/cpp/samplerate_stub.c index 7a5eb0754b..676cbee368 100644 --- a/android/app/src/main/cpp/samplerate_stub.c +++ b/android/app/src/main/cpp/samplerate_stub.c @@ -152,6 +152,15 @@ int src_reset(SRC_STATE *state) return 0; } +SRC_STATE *src_delete(SRC_STATE *state) +{ + if (state) { + free(state->input_buf); + free(state); + } + return NULL; +} + const char *src_strerror(int error) { (void)error; diff --git a/android/app/src/main/cpp/xemu_android.cpp b/android/app/src/main/cpp/xemu_android.cpp index 7856da462d..74ea2ca050 100644 --- a/android/app/src/main/cpp/xemu_android.cpp +++ b/android/app/src/main/cpp/xemu_android.cpp @@ -73,6 +73,8 @@ extern "C" bool nv2a_android_copy_readback(uint8_t **buffer, size_t *buffer_size #include static void* g_custom_vulkan_library = nullptr; +/* True only when a user-installed GPU driver ZIP was loaded (e.g. Turnip). */ +static bool g_vulkan_custom_driver_zip_loaded = false; extern "C" PFN_vkGetInstanceProcAddr xemu_android_get_vk_proc_addr(void) { @@ -82,12 +84,22 @@ extern "C" PFN_vkGetInstanceProcAddr xemu_android_get_vk_proc_addr(void) return reinterpret_cast( dlsym(g_custom_vulkan_library, "vkGetInstanceProcAddr")); } + +extern "C" bool xemu_android_vulkan_custom_driver_zip_loaded(void) +{ + return g_vulkan_custom_driver_zip_loaded; +} +#else +extern "C" bool xemu_android_vulkan_custom_driver_zip_loaded(void) +{ + return false; +} #endif static int g_dvd_fd = -1; namespace { -constexpr const char* kLogTag = "hakuX"; +constexpr const char* kLogTag = "xemu-android"; constexpr const char* kPrefsName = "x1box_prefs"; static JNIEnv* GetEnv(); @@ -533,8 +545,9 @@ struct DisplaySettings { bool vsync = false; bool unlock_framerate = true; bool validation_layers = false; + std::string renderer = "vulkan"; std::string filtering = "nearest"; - std::string aspect_ratio = "auto"; + std::string aspect_ratio = "fit"; }; static bool WriteConfigToml(const std::string& config_path, @@ -581,7 +594,7 @@ static bool WriteConfigToml(const std::string& config_path, } general->insert_or_assign("show_welcome", false); - display->insert_or_assign("renderer", "vulkan"); + display->insert_or_assign("renderer", ds.renderer); display->insert_or_assign("filtering", ds.filtering); display_window->insert_or_assign("vsync", ds.vsync); @@ -780,67 +793,93 @@ static SetupFiles SyncSetupFiles() { int tbSize = GetPrefInt(env, activity, "tcg_tb_size", 128); DisplaySettings ds; - ds.surface_scale = GetPrefInt(env, activity, "surface_scale", 1); + ds.surface_scale = GetPrefInt( + env, activity, "setting_surface_scale", + GetPrefInt(env, activity, "surface_scale", 1)); if (ds.surface_scale < 1) ds.surface_scale = 1; if (ds.surface_scale > 4) ds.surface_scale = 4; - ds.vsync = GetPrefBool(env, activity, "vsync", false); + ds.vsync = GetPrefBool( + env, activity, "setting_vsync", + GetPrefBool(env, activity, "vsync", false)); ds.unlock_framerate = GetPrefBool(env, activity, "unlock_framerate", true); ds.validation_layers = GetPrefBool(env, activity, "validation_layers", false); bool fp_safe = GetPrefBool(env, activity, "fp_safe", true); xemu_set_fp_safe(fp_safe); - __android_log_print(ANDROID_LOG_INFO, "hakuX", + __android_log_print(ANDROID_LOG_INFO, "xemu-android", "FP safe (native arithmetic): %s", fp_safe ? "ON" : "OFF"); bool fp_jit = GetPrefBool(env, activity, "fp_jit", true); xemu_set_fp_jit(fp_jit); - __android_log_print(ANDROID_LOG_INFO, "hakuX", + __android_log_print(ANDROID_LOG_INFO, "xemu-android", "FP JIT (native storage + inline ops): %s", fp_jit ? "ON" : "OFF"); bool fast_fences = GetPrefBool(env, activity, "fast_fences", false); xemu_set_fast_fences(fast_fences); - __android_log_print(ANDROID_LOG_INFO, "hakuX", + __android_log_print(ANDROID_LOG_INFO, "xemu-android", "fast fences: %s", fast_fences ? "ON" : "OFF"); bool draw_reorder = GetPrefBool(env, activity, "draw_reorder", false); xemu_set_draw_reorder(draw_reorder); - __android_log_print(ANDROID_LOG_INFO, "hakuX", + __android_log_print(ANDROID_LOG_INFO, "xemu-android", "draw reorder: %s", draw_reorder ? "ON" : "OFF"); bool draw_merge = GetPrefBool(env, activity, "draw_merge", false); xemu_set_draw_merge(draw_merge); - __android_log_print(ANDROID_LOG_INFO, "hakuX", + __android_log_print(ANDROID_LOG_INFO, "xemu-android", "draw merge: %s", draw_merge ? "ON" : "OFF"); bool bindless_tex = GetPrefBool(env, activity, "bindless_textures", false); xemu_set_bindless_textures(bindless_tex); - __android_log_print(ANDROID_LOG_INFO, "hakuX", + __android_log_print(ANDROID_LOG_INFO, "xemu-android", "bindless textures: %s", bindless_tex ? "ON" : "OFF"); bool async_compile = GetPrefBool(env, activity, "async_compile", false); xemu_set_async_compile(async_compile); - __android_log_print(ANDROID_LOG_INFO, "hakuX", + __android_log_print(ANDROID_LOG_INFO, "xemu-android", "async compile: %s", async_compile ? "ON" : "OFF"); bool frame_skip = GetPrefBool(env, activity, "frame_skip", false); xemu_set_frame_skip(frame_skip); - __android_log_print(ANDROID_LOG_INFO, "hakuX", + __android_log_print(ANDROID_LOG_INFO, "xemu-android", "frame skip: %s", frame_skip ? "ON" : "OFF"); int submit_frames = GetPrefInt(env, activity, "submit_frames", 2); xemu_set_submit_frames(submit_frames); - __android_log_print(ANDROID_LOG_INFO, "hakuX", + __android_log_print(ANDROID_LOG_INFO, "xemu-android", "submit frames: %d", submit_frames); int tier1_threshold = GetPrefInt(env, activity, "tier1_threshold", 64); xemu_set_tier1_threshold(tier1_threshold); - __android_log_print(ANDROID_LOG_INFO, "hakuX", + __android_log_print(ANDROID_LOG_INFO, "xemu-android", "tier1 threshold: %d", tier1_threshold); - std::string filterPref = GetPrefString(env, activity, "filtering"); + std::string rendererPref = GetPrefString(env, activity, "setting_renderer"); + if (rendererPref.empty()) { + rendererPref = GetPrefString(env, activity, "renderer"); + } + if (rendererPref == "opengl") { + ds.renderer = "opengl"; + } else if (rendererPref == "vulkan") { + ds.renderer = "vulkan"; + } + + std::string filterPref = GetPrefString(env, activity, "setting_filtering"); + if (filterPref.empty()) { + filterPref = GetPrefString(env, activity, "filtering"); + } if (!filterPref.empty()) ds.filtering = filterPref; - std::string arPref = GetPrefString(env, activity, "aspect_ratio"); - if (!arPref.empty()) ds.aspect_ratio = arPref; + int displayMode = GetPrefInt(env, activity, "setting_display_mode", -1); + if (displayMode == 1) { + ds.aspect_ratio = "4:3"; + } else if (displayMode == 2) { + ds.aspect_ratio = "16:9"; + } else if (displayMode == 0) { + ds.aspect_ratio = "fit"; + } else { + std::string arPref = GetPrefString(env, activity, "aspect_ratio"); + if (!arPref.empty()) ds.aspect_ratio = arPref; + } WriteConfigToml(out.config_path, out.mcpx, out.flash, out.hdd, out.dvd, out.eeprom, tbSize, ds); LogInfoFmt("SyncSetupFiles: config %s", out.config_path.c_str()); @@ -857,7 +896,7 @@ static SetupFiles SyncSetupFiles() { size_t n = fread(buf, 1, sizeof(buf) - 1, f); buf[n] = '\0'; fclose(f); - __android_log_print(ANDROID_LOG_INFO, "hakuX-config", + __android_log_print(ANDROID_LOG_INFO, "xemu-config", "--- xemu.toml ---\n%s\n--- end ---", buf); } } @@ -913,7 +952,7 @@ static void xemu_pin_to_big_cores_cpp(const char *label) { } if (big_count > 0 && big_count < ncpus) { if (syscall(__NR_sched_setaffinity, 0, sizeof(mask), &mask) == 0) { - __android_log_print(ANDROID_LOG_INFO, "hakuX", + __android_log_print(ANDROID_LOG_INFO, "xemu-android", "%s: pinned to %d big cores (max_freq=%lu)", label, big_count, max_freq); } @@ -959,7 +998,7 @@ extern "C" int xemu_android_main(int argc, char** argv) { auto t_init_start = SDL_GetTicks(); qemu_init(argc, argv); auto t_init_end = SDL_GetTicks(); - __android_log_print(ANDROID_LOG_INFO, "hakuX", + __android_log_print(ANDROID_LOG_INFO, "xemu-android", "qemu_init took %u ms", t_init_end - t_init_start); /* qemu_init's cleanup_add_fd already closed the original fd */ @@ -992,7 +1031,7 @@ extern "C" int xemu_android_main(int argc, char** argv) { * cache saved with different FP modes is automatically rejected. */ game_hash ^= (xemu_get_fp_safe() ? 0x1u : 0) | (xemu_get_fp_jit() ? 0x2u : 0); int nhints = tb_cache_load(cache_path, game_hash); - __android_log_print(ANDROID_LOG_INFO, "hakuX", + __android_log_print(ANDROID_LOG_INFO, "xemu-android", "TB cache: loaded %d hints from %s", nhints, cache_path); } #endif @@ -1047,7 +1086,7 @@ extern "C" int SDL_main(int argc, char* argv[]) { auto t_sync_start = SDL_GetTicks(); SetupFiles setup = SyncSetupFiles(); auto t_sync_end = SDL_GetTicks(); - __android_log_print(ANDROID_LOG_INFO, "hakuX", + __android_log_print(ANDROID_LOG_INFO, "xemu-android", "SyncSetupFiles took %u ms", t_sync_end - t_sync_start); xemu_android_set_inline_aio_crash_flag_path(setup.inline_aio_flag_path.empty() @@ -1260,13 +1299,13 @@ extern "C" int SDL_main(int argc, char* argv[]) { } extern "C" JNIEXPORT jint JNICALL -Java_com_rfandango_haku_1x_MainActivity_nativeGetFps(JNIEnv *, jobject) +Java_com_izzy2lost_x1box_MainActivity_nativeGetFps(JNIEnv *, jobject) { return static_cast(g_nv2a_stats.increment_fps); } extern "C" JNIEXPORT jstring JNICALL -Java_com_rfandango_haku_1x_MainActivity_nativeGetFramePacing(JNIEnv *env, jobject) +Java_com_izzy2lost_x1box_MainActivity_nativeGetFramePacing(JNIEnv *env, jobject) { char buf[256]; nv2a_profile_get_pacing_str(buf, sizeof(buf)); @@ -1274,7 +1313,7 @@ Java_com_rfandango_haku_1x_MainActivity_nativeGetFramePacing(JNIEnv *env, jobjec } extern "C" JNIEXPORT jstring JNICALL -Java_com_rfandango_haku_1x_MainActivity_nativeGetShaderStats(JNIEnv *env, jobject) +Java_com_izzy2lost_x1box_MainActivity_nativeGetShaderStats(JNIEnv *env, jobject) { char buf[256]; nv2a_profile_get_shader_stats_str(buf, sizeof(buf)); @@ -1282,7 +1321,7 @@ Java_com_rfandango_haku_1x_MainActivity_nativeGetShaderStats(JNIEnv *env, jobjec } extern "C" JNIEXPORT jboolean JNICALL -Java_com_rfandango_haku_1x_MainActivity_nativeCaptureFrame(JNIEnv *, jobject) +Java_com_izzy2lost_x1box_MainActivity_nativeCaptureFrame(JNIEnv *, jobject) { #ifdef CONFIG_RENDERDOC if (nv2a_dbg_renderdoc_available()) { @@ -1294,7 +1333,7 @@ Java_com_rfandango_haku_1x_MainActivity_nativeCaptureFrame(JNIEnv *, jobject) } extern "C" JNIEXPORT void JNICALL -Java_com_rfandango_haku_1x_MainActivity_nativeDumpDiagFrames(JNIEnv *, jobject, jint numFrames) +Java_com_izzy2lost_x1box_MainActivity_nativeDumpDiagFrames(JNIEnv *, jobject, jint numFrames) { nv2a_dbg_trigger_diag_frames((int)numFrames); } @@ -1302,19 +1341,19 @@ Java_com_rfandango_haku_1x_MainActivity_nativeDumpDiagFrames(JNIEnv *, jobject, extern "C" char g_vulkan_driver_info[256]; extern "C" JNIEXPORT jstring JNICALL -Java_com_rfandango_haku_1x_MainActivity_nativeGetDriverInfo(JNIEnv *env, jobject) +Java_com_izzy2lost_x1box_MainActivity_nativeGetDriverInfo(JNIEnv *env, jobject) { return env->NewStringUTF(g_vulkan_driver_info); } extern "C" JNIEXPORT jboolean JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeGetFpSafe(JNIEnv *, jobject) +Java_com_izzy2lost_x1box_SettingsActivity_nativeGetFpSafe(JNIEnv *, jobject) { return xemu_get_fp_safe() ? JNI_TRUE : JNI_FALSE; } extern "C" JNIEXPORT void JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeSetFpSafe(JNIEnv *, jobject, jboolean enable) +Java_com_izzy2lost_x1box_SettingsActivity_nativeSetFpSafe(JNIEnv *, jobject, jboolean enable) { xemu_set_fp_safe(enable == JNI_TRUE); const char *storage = SDL_AndroidGetInternalStoragePath(); @@ -1326,109 +1365,109 @@ Java_com_rfandango_haku_1x_SettingsActivity_nativeSetFpSafe(JNIEnv *, jobject, j } extern "C" JNIEXPORT jboolean JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeGetFastFences(JNIEnv *, jobject) +Java_com_izzy2lost_x1box_SettingsActivity_nativeGetFastFences(JNIEnv *, jobject) { return xemu_get_fast_fences() ? JNI_TRUE : JNI_FALSE; } extern "C" JNIEXPORT void JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeSetFastFences(JNIEnv *, jobject, jboolean enable) +Java_com_izzy2lost_x1box_SettingsActivity_nativeSetFastFences(JNIEnv *, jobject, jboolean enable) { xemu_set_fast_fences(enable == JNI_TRUE); } extern "C" JNIEXPORT jboolean JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeGetDrawReorder(JNIEnv *, jobject) +Java_com_izzy2lost_x1box_SettingsActivity_nativeGetDrawReorder(JNIEnv *, jobject) { return xemu_get_draw_reorder() ? JNI_TRUE : JNI_FALSE; } extern "C" JNIEXPORT void JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeSetDrawReorder(JNIEnv *, jobject, jboolean enable) +Java_com_izzy2lost_x1box_SettingsActivity_nativeSetDrawReorder(JNIEnv *, jobject, jboolean enable) { xemu_set_draw_reorder(enable == JNI_TRUE); } extern "C" JNIEXPORT jboolean JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeGetDrawMerge(JNIEnv *, jobject) +Java_com_izzy2lost_x1box_SettingsActivity_nativeGetDrawMerge(JNIEnv *, jobject) { return xemu_get_draw_merge() ? JNI_TRUE : JNI_FALSE; } extern "C" JNIEXPORT void JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeSetDrawMerge(JNIEnv *, jobject, jboolean enable) +Java_com_izzy2lost_x1box_SettingsActivity_nativeSetDrawMerge(JNIEnv *, jobject, jboolean enable) { xemu_set_draw_merge(enable == JNI_TRUE); } extern "C" JNIEXPORT jboolean JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeGetBindlessTextures(JNIEnv *, jobject) +Java_com_izzy2lost_x1box_SettingsActivity_nativeGetBindlessTextures(JNIEnv *, jobject) { return xemu_get_bindless_textures() ? JNI_TRUE : JNI_FALSE; } extern "C" JNIEXPORT void JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeSetBindlessTextures(JNIEnv *, jobject, jboolean enable) +Java_com_izzy2lost_x1box_SettingsActivity_nativeSetBindlessTextures(JNIEnv *, jobject, jboolean enable) { xemu_set_bindless_textures(enable == JNI_TRUE); } extern "C" JNIEXPORT jboolean JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeGetAsyncCompile(JNIEnv *, jobject) +Java_com_izzy2lost_x1box_SettingsActivity_nativeGetAsyncCompile(JNIEnv *, jobject) { return xemu_get_async_compile() ? JNI_TRUE : JNI_FALSE; } extern "C" JNIEXPORT void JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeSetAsyncCompile(JNIEnv *, jobject, jboolean enable) +Java_com_izzy2lost_x1box_SettingsActivity_nativeSetAsyncCompile(JNIEnv *, jobject, jboolean enable) { xemu_set_async_compile(enable == JNI_TRUE); } extern "C" JNIEXPORT jboolean JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeGetFrameSkip(JNIEnv *, jobject) +Java_com_izzy2lost_x1box_SettingsActivity_nativeGetFrameSkip(JNIEnv *, jobject) { return xemu_get_frame_skip() ? JNI_TRUE : JNI_FALSE; } extern "C" JNIEXPORT void JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeSetFrameSkip(JNIEnv *, jobject, jboolean enable) +Java_com_izzy2lost_x1box_SettingsActivity_nativeSetFrameSkip(JNIEnv *, jobject, jboolean enable) { xemu_set_frame_skip(enable == JNI_TRUE); } extern "C" JNIEXPORT jint JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeGetSubmitFrames(JNIEnv *, jobject) +Java_com_izzy2lost_x1box_SettingsActivity_nativeGetSubmitFrames(JNIEnv *, jobject) { return static_cast(xemu_get_submit_frames()); } extern "C" JNIEXPORT void JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeSetSubmitFrames(JNIEnv *, jobject, jint count) +Java_com_izzy2lost_x1box_SettingsActivity_nativeSetSubmitFrames(JNIEnv *, jobject, jint count) { xemu_set_submit_frames(static_cast(count)); } extern "C" JNIEXPORT jint JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeGetTier1Threshold(JNIEnv *, jobject) +Java_com_izzy2lost_x1box_SettingsActivity_nativeGetTier1Threshold(JNIEnv *, jobject) { return static_cast(xemu_get_tier1_threshold()); } extern "C" JNIEXPORT void JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeSetTier1Threshold(JNIEnv *, jobject, jint value) +Java_com_izzy2lost_x1box_SettingsActivity_nativeSetTier1Threshold(JNIEnv *, jobject, jint value) { xemu_set_tier1_threshold(static_cast(value)); } extern "C" JNIEXPORT jboolean JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeGetFpJit(JNIEnv *, jobject) +Java_com_izzy2lost_x1box_SettingsActivity_nativeGetFpJit(JNIEnv *, jobject) { return xemu_get_fp_jit() ? JNI_TRUE : JNI_FALSE; } extern "C" JNIEXPORT void JNICALL -Java_com_rfandango_haku_1x_SettingsActivity_nativeSetFpJit(JNIEnv *, jobject, jboolean enable) +Java_com_izzy2lost_x1box_SettingsActivity_nativeSetFpJit(JNIEnv *, jobject, jboolean enable) { xemu_set_fp_jit(enable == JNI_TRUE); const char *storage = SDL_AndroidGetInternalStoragePath(); @@ -1440,32 +1479,32 @@ Java_com_rfandango_haku_1x_SettingsActivity_nativeSetFpJit(JNIEnv *, jobject, jb } extern "C" JNIEXPORT void JNICALL -Java_com_rfandango_haku_1x_MainActivity_nativePauseEmulation(JNIEnv *, jobject) +Java_com_izzy2lost_x1box_MainActivity_nativePauseEmulation(JNIEnv *, jobject) { xemu_android_pause_emulation(); } extern "C" JNIEXPORT void JNICALL -Java_com_rfandango_haku_1x_MainActivity_nativeResumeEmulation(JNIEnv *, jobject) +Java_com_izzy2lost_x1box_MainActivity_nativeResumeEmulation(JNIEnv *, jobject) { xemu_android_resume_emulation(); } extern "C" JNIEXPORT void JNICALL -Java_com_rfandango_haku_1x_MainActivity_nativeExitEmulation(JNIEnv *, jobject) +Java_com_izzy2lost_x1box_MainActivity_nativeExitEmulation(JNIEnv *, jobject) { xemu_android_request_exit(); } #ifdef CONFIG_VULKAN extern "C" JNIEXPORT jboolean JNICALL -Java_com_rfandango_haku_1x_GpuDriverHelper_nativeSupportsCustomDriverLoading(JNIEnv *, jclass) +Java_com_izzy2lost_x1box_GpuDriverHelper_nativeSupportsCustomDriverLoading(JNIEnv *, jclass) { return access("/dev/kgsl-3d0", F_OK) == 0 ? JNI_TRUE : JNI_FALSE; } extern "C" JNIEXPORT void JNICALL -Java_com_rfandango_haku_1x_GpuDriverHelper_nativeInitializeDriver( +Java_com_izzy2lost_x1box_GpuDriverHelper_nativeInitializeDriver( JNIEnv *env, jclass, jstring hookLibDir, jstring customDriverDir, jstring customDriverName) @@ -1475,9 +1514,10 @@ Java_com_rfandango_haku_1x_GpuDriverHelper_nativeInitializeDriver( const char *driver_name = customDriverName ? env->GetStringUTFChars(customDriverName, nullptr) : nullptr; void *handle = nullptr; + g_vulkan_custom_driver_zip_loaded = false; if (driver_name && driver_name[0] != '\0') { - __android_log_print(ANDROID_LOG_INFO, "hakuX", + __android_log_print(ANDROID_LOG_INFO, "xemu-android", "Loading custom Vulkan driver: %s from %s", driver_name, driver_dir ? driver_dir : "(null)"); handle = adrenotools_open_libvulkan( @@ -1492,15 +1532,40 @@ Java_com_rfandango_haku_1x_GpuDriverHelper_nativeInitializeDriver( if (handle) { g_custom_vulkan_library = handle; - __android_log_print(ANDROID_LOG_INFO, "hakuX", + g_vulkan_custom_driver_zip_loaded = true; + __android_log_print(ANDROID_LOG_INFO, "xemu-android", "Custom Vulkan driver loaded successfully via adrenotools"); } else { - __android_log_print(ANDROID_LOG_WARN, "hakuX", + __android_log_print(ANDROID_LOG_WARN, "xemu-android", "adrenotools failed to load custom driver, will fall back to system default"); } } else { - __android_log_print(ANDROID_LOG_INFO, "hakuX", - "No custom driver specified, using system Vulkan driver"); + /* + * No Turnip/custom ZIP: still dlopen libvulkan through adrenotools with + * featureFlags=0 (stock driver). That matches the volk dispatch path used + * when a custom .so is loaded and applies adrenotools hooks from + * nativeLibraryDir — avoiding OEM-specific quirks from mixing linker- + * resolved Vulkan symbols with this code path. + */ + if (hook_dir && hook_dir[0] != '\0') { + handle = adrenotools_open_libvulkan( + RTLD_NOW, + 0, + (driver_dir && driver_dir[0] != '\0') ? driver_dir : nullptr, + hook_dir, + nullptr, + nullptr, + nullptr, + nullptr); + } + if (handle) { + g_custom_vulkan_library = handle; + __android_log_print(ANDROID_LOG_INFO, "xemu-android", + "System Vulkan driver opened via adrenotools (hooked dispatch)"); + } else { + __android_log_print(ANDROID_LOG_INFO, "xemu-android", + "Vulkan: default linkage (adrenotools system open not used)"); + } } if (driver_name) env->ReleaseStringUTFChars(customDriverName, driver_name); diff --git a/android/app/src/main/cpp/xemu_settings_android.cc b/android/app/src/main/cpp/xemu_settings_android.cc index fa4d16b3b8..a2a06ded39 100644 --- a/android/app/src/main/cpp/xemu_settings_android.cc +++ b/android/app/src/main/cpp/xemu_settings_android.cc @@ -169,7 +169,7 @@ const char *xemu_settings_get_base_path(void) } base_path = base ? strdup(base) : strdup(""); SDL_free(base); - __android_log_print(ANDROID_LOG_INFO, "hakuX-config", + __android_log_print(ANDROID_LOG_INFO, "xemu-config", "xemu_settings_get_base_path: %s", base_path); return base_path; } @@ -245,7 +245,7 @@ bool xemu_settings_load(void) parsed == CONFIG_DISPLAY_RENDERER_OPENGL) { g_config.display.renderer = parsed; } - __android_log_print(ANDROID_LOG_INFO, "hakuX", + __android_log_print(ANDROID_LOG_INFO, "xemu-android", "Config display.renderer=%s (using %s)", renderer->c_str(), g_config.display.renderer == CONFIG_DISPLAY_RENDERER_VULKAN @@ -346,7 +346,7 @@ bool xemu_settings_load(void) if (*tcg_thread == "single" || *tcg_thread == "multi") { setenv("XEMU_ANDROID_TCG_THREAD", tcg_thread->c_str(), 1); } else { - __android_log_print(ANDROID_LOG_WARN, "hakuX", + __android_log_print(ANDROID_LOG_WARN, "xemu-android", "Ignoring android.tcg_thread=%s (expected single|multi)", tcg_thread->c_str()); } @@ -508,7 +508,7 @@ bool xemu_settings_load_gamepad_mapping(const char *guid, GamepadMappings *new_mappings = static_cast(realloc( g_config.input.gamepad_mappings, sizeof(GamepadMappings) * new_count)); if (!new_mappings) { - __android_log_print(ANDROID_LOG_ERROR, "hakuX", + __android_log_print(ANDROID_LOG_ERROR, "xemu-android", "Failed to allocate gamepad mapping for %s", guid); return false; } diff --git a/android/app/src/main/cpp/xiso_converter_jni.cpp b/android/app/src/main/cpp/xiso_converter_jni.cpp index c0f804289d..f7d4013251 100644 --- a/android/app/src/main/cpp/xiso_converter_jni.cpp +++ b/android/app/src/main/cpp/xiso_converter_jni.cpp @@ -1,15 +1,50 @@ #include +#include #include #include +#define XISO_LOG_TAG "XisoConverter" + extern "C" int xiso_convert_iso_to_xiso(const char *input_path, const char *output_path, char *err_buf, size_t err_buf_len); +extern "C" int xiso_convert_iso_to_xiso_with_progress( + const char *input_path, + const char *output_path, + char *err_buf, + size_t err_buf_len, + void (*progress_callback)(int current, int total, void *user_data), + void *user_data); + +struct JniProgressContext { + JNIEnv *env; + jobject callback; + jmethodID method_id; + bool failed; +}; + +static void xiso_progress_bridge(int current, int total, void *user_data) { + auto *ctx = static_cast(user_data); + if (ctx->failed) return; + if (ctx->env->ExceptionCheck()) { + ctx->failed = true; + ctx->env->ExceptionClear(); + return; + } + ctx->env->CallVoidMethod(ctx->callback, ctx->method_id, + static_cast(current), + static_cast(total)); + if (ctx->env->ExceptionCheck()) { + ctx->failed = true; + ctx->env->ExceptionClear(); + } +} + extern "C" JNIEXPORT jstring JNICALL -Java_com_rfandango_haku_1x_XisoConverterNative_nativeConvertIsoToXiso( +Java_com_izzy2lost_x1box_XisoConverterNative_nativeConvertIsoToXiso( JNIEnv *env, jclass, jstring input_path, @@ -45,5 +80,72 @@ Java_com_rfandango_haku_1x_XisoConverterNative_nativeConvertIsoToXiso( const char *msg = error_buffer[0] != '\0' ? error_buffer.data() : "ISO conversion failed"; + __android_log_print(ANDROID_LOG_ERROR, XISO_LOG_TAG, + "nativeConvertIsoToXiso rc=%d: %s", rc, msg); return env->NewStringUTF(msg); -} \ No newline at end of file +} + +extern "C" JNIEXPORT jstring JNICALL +Java_com_izzy2lost_x1box_XisoConverterNative_nativeConvertIsoToXisoWithProgress( + JNIEnv *env, + jclass, + jstring input_path, + jstring output_path, + jobject progress_callback) { + if (input_path == nullptr || output_path == nullptr) { + return env->NewStringUTF("Input/output path is missing"); + } + + const char *input_chars = env->GetStringUTFChars(input_path, nullptr); + if (input_chars == nullptr) { + return env->NewStringUTF("Failed to read input path"); + } + const char *output_chars = env->GetStringUTFChars(output_path, nullptr); + if (output_chars == nullptr) { + env->ReleaseStringUTFChars(input_path, input_chars); + return env->NewStringUTF("Failed to read output path"); + } + + std::array error_buffer{}; + int rc; + + if (progress_callback != nullptr) { + jclass cb_class = env->GetObjectClass(progress_callback); + jmethodID on_progress = env->GetMethodID(cb_class, "onProgress", "(II)V"); + + if (on_progress == nullptr) { + env->ReleaseStringUTFChars(input_path, input_chars); + env->ReleaseStringUTFChars(output_path, output_chars); + return env->NewStringUTF("Failed to find onProgress method on callback"); + } + + JniProgressContext ctx{env, progress_callback, on_progress, false}; + rc = xiso_convert_iso_to_xiso_with_progress( + input_chars, + output_chars, + error_buffer.data(), + error_buffer.size(), + xiso_progress_bridge, + &ctx); + } else { + rc = xiso_convert_iso_to_xiso( + input_chars, + output_chars, + error_buffer.data(), + error_buffer.size()); + } + + env->ReleaseStringUTFChars(input_path, input_chars); + env->ReleaseStringUTFChars(output_path, output_chars); + + if (rc == 0) { + return nullptr; + } + + const char *msg = error_buffer[0] != '\0' + ? error_buffer.data() + : "ISO conversion failed"; + __android_log_print(ANDROID_LOG_ERROR, XISO_LOG_TAG, + "nativeConvertIsoToXisoWithProgress rc=%d: %s", rc, msg); + return env->NewStringUTF(msg); +} diff --git a/hw/xbox/nv2a/pgraph/vk/instance.c b/hw/xbox/nv2a/pgraph/vk/instance.c index c1b81bb5fd..3017d451cc 100644 --- a/hw/xbox/nv2a/pgraph/vk/instance.c +++ b/hw/xbox/nv2a/pgraph/vk/instance.c @@ -482,9 +482,28 @@ static void add_optional_device_extension_names( } #if OPT_DYNAMIC_BLEND - r->eds3_blend_supported = add_extension_if_available( - available_extensions, enabled_extension_names, - VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); + /* + * Stock Qualcomm drivers often advertise EXT_extended_dynamic_state3 but + * crash or fault inside vkCmdSetColorBlend* / related dynamic state during + * real draws. Turnip and other updaters are fine; skip EDS3 on Adreno-only + * Android so we use static pipeline blend state instead. + */ +# ifdef __ANDROID__ + extern bool xemu_android_vulkan_custom_driver_zip_loaded(void); + if (r->device_props.vendorID == 0x5143u && + !xemu_android_vulkan_custom_driver_zip_loaded()) { + r->eds3_blend_supported = false; + fprintf(stderr, "Qualcomm GPU: omitting %s (use static blend for stock-driver compatibility)\n", + VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); + __android_log_print(ANDROID_LOG_INFO, "hakuX", + "Qualcomm stock driver: dynamic blend (EDS3) disabled"); + } else +# endif + { + r->eds3_blend_supported = add_extension_if_available( + available_extensions, enabled_extension_names, + VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); + } #endif #if OPT_BINDLESS_TEXTURES