diff options
| -rw-r--r-- | src/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/CMakeLists.txt | 15 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/emu_window/emu_window.cpp | 58 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/emu_window/emu_window.h | 51 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/id_cache.cpp | 36 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/id_cache.h | 11 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/native.cpp | 342 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/native.h | 127 | 
8 files changed, 645 insertions, 0 deletions
| diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5e3a74c0f..55b113297 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -195,3 +195,8 @@ endif()  if (ENABLE_WEB_SERVICE)      add_subdirectory(web_service)  endif() + +if (ANDROID) +    add_subdirectory(android/app/src/main/jni) +    target_include_directories(yuzu-android PRIVATE android/app/src/main) +endif() diff --git a/src/android/app/src/main/jni/CMakeLists.txt b/src/android/app/src/main/jni/CMakeLists.txt new file mode 100644 index 000000000..373c0e8bd --- /dev/null +++ b/src/android/app/src/main/jni/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(yuzu-android SHARED +    emu_window/emu_window.cpp +    emu_window/emu_window.h +    id_cache.cpp +    id_cache.h +    native.cpp +    native.h +) + +set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR}) + +target_link_libraries(yuzu-android PRIVATE audio_core common core input_common) +target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad inih jnigraphics log) + +set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} yuzu-android) diff --git a/src/android/app/src/main/jni/emu_window/emu_window.cpp b/src/android/app/src/main/jni/emu_window/emu_window.cpp new file mode 100644 index 000000000..9062c0ae3 --- /dev/null +++ b/src/android/app/src/main/jni/emu_window/emu_window.cpp @@ -0,0 +1,58 @@ +#include <android/native_window_jni.h> + +#include "common/logging/log.h" +#include "input_common/drivers/touch_screen.h" +#include "input_common/drivers/virtual_gamepad.h" +#include "input_common/main.h" +#include "jni/emu_window/emu_window.h" + +void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { +    render_window = surface; +} + +bool EmuWindow_Android::OnTouchEvent(float x, float y, bool pressed) { +    if (pressed) { +        input_subsystem->GetTouchScreen()->TouchPressed(NormalizeX(x), NormalizeY(y), 0); +        return true; +    } + +    input_subsystem->GetTouchScreen()->ReleaseAllTouch(); +    return true; +} + +void EmuWindow_Android::OnTouchMoved(float x, float y) { +    input_subsystem->GetTouchScreen()->TouchMoved(NormalizeX(x), NormalizeY(y), 0); +} + +void EmuWindow_Android::OnGamepadEvent(int button_id, bool pressed) { +    input_subsystem->GetVirtualGamepad()->SetButtonState(0, button_id, pressed); +} + +void EmuWindow_Android::OnGamepadMoveEvent(float x, float y) { +    input_subsystem->GetVirtualGamepad()->SetStickPosition( +        0, InputCommon::VirtualGamepad::VirtualStick::Left, x, y); +} + +EmuWindow_Android::EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem_, +                                     ANativeWindow* surface_) +    : input_subsystem{input_subsystem_} { +    LOG_INFO(Frontend, "initializing"); + +    if (!surface_) { +        LOG_CRITICAL(Frontend, "surface is nullptr"); +        return; +    } + +    window_width = ANativeWindow_getWidth(surface_); +    window_height = ANativeWindow_getHeight(surface_); + +    host_window = surface_; +    window_info.type = Core::Frontend::WindowSystemType::Android; +    window_info.render_surface = reinterpret_cast<void*>(host_window); + +    input_subsystem->Initialize(); +} + +EmuWindow_Android::~EmuWindow_Android() { +    input_subsystem->Shutdown(); +} diff --git a/src/android/app/src/main/jni/emu_window/emu_window.h b/src/android/app/src/main/jni/emu_window/emu_window.h new file mode 100644 index 000000000..4af51c517 --- /dev/null +++ b/src/android/app/src/main/jni/emu_window/emu_window.h @@ -0,0 +1,51 @@ +#pragma once + +#include "core/frontend/emu_window.h" +#include "input_common/main.h" + +struct ANativeWindow; + +class SharedContext_Android : public Core::Frontend::GraphicsContext { +public: +    SharedContext_Android() = default; +    ~SharedContext_Android() = default; +    void MakeCurrent() override {} +    void DoneCurrent() override {} +}; + +class EmuWindow_Android : public Core::Frontend::EmuWindow { +public: +    EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem_, ANativeWindow* surface_); +    ~EmuWindow_Android(); + +    void OnSurfaceChanged(ANativeWindow* surface); +    bool OnTouchEvent(float x, float y, bool pressed); +    void OnTouchMoved(float x, float y); +    void OnGamepadEvent(int button, bool pressed); +    void OnGamepadMoveEvent(float x, float y); +    void OnFrameDisplayed() override {} + +    std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override { +        return {std::make_unique<SharedContext_Android>()}; +    } +    bool IsShown() const override { +        return true; +    }; + +private: +    float NormalizeX(float x) const { +        return std::clamp(x / window_width, 0.f, 1.f); +    } + +    float NormalizeY(float y) const { +        return std::clamp(y / window_height, 0.f, 1.f); +    } + +    InputCommon::InputSubsystem* input_subsystem{}; + +    ANativeWindow* render_window{}; +    ANativeWindow* host_window{}; + +    float window_width{}; +    float window_height{}; +}; diff --git a/src/android/app/src/main/jni/id_cache.cpp b/src/android/app/src/main/jni/id_cache.cpp new file mode 100644 index 000000000..2955122be --- /dev/null +++ b/src/android/app/src/main/jni/id_cache.cpp @@ -0,0 +1,36 @@ +#include "jni/id_cache.h" + +static JavaVM* s_java_vm; +static jclass s_native_library_class; +static jmethodID s_exit_emulation_activity; + +namespace IDCache { + +JNIEnv* GetEnvForThread() { +    thread_local static struct OwnedEnv { +        OwnedEnv() { +            status = s_java_vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6); +            if (status == JNI_EDETACHED) +                s_java_vm->AttachCurrentThread(&env, nullptr); +        } + +        ~OwnedEnv() { +            if (status == JNI_EDETACHED) +                s_java_vm->DetachCurrentThread(); +        } + +        int status; +        JNIEnv* env = nullptr; +    } owned; +    return owned.env; +} + +jclass GetNativeLibraryClass() { +    return s_native_library_class; +} + +jmethodID GetExitEmulationActivity() { +    return s_exit_emulation_activity; +} + +} // namespace IDCache diff --git a/src/android/app/src/main/jni/id_cache.h b/src/android/app/src/main/jni/id_cache.h new file mode 100644 index 000000000..2fe07169d --- /dev/null +++ b/src/android/app/src/main/jni/id_cache.h @@ -0,0 +1,11 @@ +#pragma once + +#include <jni.h> + +namespace IDCache { + +JNIEnv* GetEnvForThread(); +jclass GetNativeLibraryClass(); +jmethodID GetExitEmulationActivity(); + +} // namespace IDCache diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp new file mode 100644 index 000000000..b343a1453 --- /dev/null +++ b/src/android/app/src/main/jni/native.cpp @@ -0,0 +1,342 @@ +#include <codecvt> +#include <locale> +#include <string> +#include <string_view> + +#include <android/api-level.h> +#include <android/native_window_jni.h> + +#include "common/detached_tasks.h" +#include "common/logging/backend.h" +#include "common/logging/log.h" +#include "common/microprofile.h" +#include "common/scm_rev.h" +#include "common/scope_exit.h" +#include "common/settings.h" +#include "core/core.h" +#include "core/cpu_manager.h" +#include "core/file_sys/registered_cache.h" +#include "core/file_sys/vfs_real.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/perf_stats.h" +#include "jni/emu_window/emu_window.h" +#include "jni/id_cache.h" +#include "video_core/rasterizer_interface.h" + +namespace { + +ANativeWindow* s_surf{}; +std::unique_ptr<EmuWindow_Android> emu_window; +std::atomic<bool> stop_run{true}; +Core::System system_; + +std::string UTF16ToUTF8(std::u16string_view input) { +    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; +    return convert.to_bytes(input.data(), input.data() + input.size()); +} + +std::string GetJString(JNIEnv* env, jstring jstr) { +    if (!jstr) { +        return {}; +    } + +    const jchar* jchars = env->GetStringChars(jstr, nullptr); +    const jsize length = env->GetStringLength(jstr); +    const std::u16string_view string_view(reinterpret_cast<const char16_t*>(jchars), length); +    const std::string converted_string = UTF16ToUTF8(string_view); +    env->ReleaseStringChars(jstr, jchars); + +    return converted_string; +} + +} // Anonymous namespace + +static Core::SystemResultStatus RunEmulation(const std::string& filepath) { +    Common::Log::Initialize(); +    Common::Log::SetColorConsoleBackendEnabled(true); +    Common::Log::Start(); +    Common::DetachedTasks detached_tasks; + +    MicroProfileOnThreadCreate("EmuThread"); +    SCOPE_EXIT({ MicroProfileShutdown(); }); + +    LOG_INFO(Frontend, "starting"); + +    if (filepath.empty()) { +        LOG_CRITICAL(Frontend, "failed to load: filepath empty!"); +        return Core::SystemResultStatus::ErrorLoader; +    } + +    system_.Initialize(); +    system_.ApplySettings(); + +    InputCommon::InputSubsystem input_subsystem{}; + +    emu_window = std::make_unique<EmuWindow_Android>(&input_subsystem, s_surf); + +    system_.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>()); +    system_.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>()); +    system_.GetFileSystemController().CreateFactories(*system_.GetFilesystem()); + +    const Core::SystemResultStatus load_result{system_.Load(*emu_window, filepath)}; + +    if (load_result != Core::SystemResultStatus::Success) { +        return load_result; +    } + +    system_.GPU().Start(); +    system_.GetCpuManager().OnGpuReady(); +    system_.RegisterExitCallback([&] { exit(0); }); + +    void(system_.Run()); + +    if (system_.DebuggerEnabled()) { +        system_.InitializeDebugger(); +    } + +    stop_run = false; +    while (!stop_run) { +        std::this_thread::sleep_for(std::chrono::seconds(1)); +    } + +    system_.DetachDebugger(); +    void(system_.Pause()); +    system_.ShutdownMainProcess(); + +    detached_tasks.WaitForAllTasks(); + +    return Core::SystemResultStatus::Success; +} + +extern "C" { + +void Java_org_citra_citra_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env, +                                                            [[maybe_unused]] jclass clazz, +                                                            jobject surf) { +    s_surf = ANativeWindow_fromSurface(env, surf); + +    if (emu_window) { +        emu_window->OnSurfaceChanged(s_surf); +    } + +    LOG_INFO(Frontend, "surface changed"); +} + +void Java_org_citra_citra_1emu_NativeLibrary_SurfaceDestroyed(JNIEnv* env, +                                                              [[maybe_unused]] jclass clazz) { +    ANativeWindow_release(s_surf); +    s_surf = nullptr; +    if (emu_window) { +        emu_window->OnSurfaceChanged(s_surf); +    } +} + +void Java_org_citra_citra_1emu_NativeLibrary_DoFrame(JNIEnv* env, [[maybe_unused]] jclass clazz) {} + +void Java_org_citra_citra_1emu_NativeLibrary_NotifyOrientationChange(JNIEnv* env, +                                                                     [[maybe_unused]] jclass clazz, +                                                                     jint layout_option, +                                                                     jint rotation) {} + +void Java_org_citra_citra_1emu_NativeLibrary_SetUserDirectory( +    [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, +    [[maybe_unused]] jstring j_directory) {} + +void Java_org_citra_citra_1emu_NativeLibrary_UnPauseEmulation([[maybe_unused]] JNIEnv* env, +                                                              [[maybe_unused]] jclass clazz) {} + +void Java_org_citra_citra_1emu_NativeLibrary_PauseEmulation([[maybe_unused]] JNIEnv* env, +                                                            [[maybe_unused]] jclass clazz) {} + +void Java_org_citra_citra_1emu_NativeLibrary_StopEmulation([[maybe_unused]] JNIEnv* env, +                                                           [[maybe_unused]] jclass clazz) {} + +jboolean Java_org_citra_citra_1emu_NativeLibrary_IsRunning([[maybe_unused]] JNIEnv* env, +                                                           [[maybe_unused]] jclass clazz) { +    return static_cast<jboolean>(!stop_run); +} + +jboolean Java_org_citra_citra_1emu_NativeLibrary_onGamePadEvent([[maybe_unused]] JNIEnv* env, +                                                                [[maybe_unused]] jclass clazz, +                                                                [[maybe_unused]] jstring j_device, +                                                                jint j_button, jint action) { +    emu_window->OnGamepadEvent(j_button, action != 0); +    return static_cast<jboolean>(true); +} + +jboolean Java_org_citra_citra_1emu_NativeLibrary_onGamePadMoveEvent([[maybe_unused]] JNIEnv* env, +                                                                    [[maybe_unused]] jclass clazz, +                                                                    jstring j_device, jint axis, +                                                                    jfloat x, jfloat y) { +    // Clamp joystick movement to supported minimum and maximum. +    x = std::clamp(x, -1.f, 1.f); +    y = std::clamp(-y, -1.f, 1.f); + +    // Clamp the input to a circle. +    float r = x * x + y * y; +    if (r > 1.0f) { +        r = std::sqrt(r); +        x /= r; +        y /= r; +    } +    emu_window->OnGamepadMoveEvent(x, y); +    return static_cast<jboolean>(false); +} + +jboolean Java_org_citra_citra_1emu_NativeLibrary_onGamePadAxisEvent([[maybe_unused]] JNIEnv* env, +                                                                    [[maybe_unused]] jclass clazz, +                                                                    jstring j_device, jint axis_id, +                                                                    jfloat axis_val) { +    return {}; +} + +jboolean Java_org_citra_citra_1emu_NativeLibrary_onTouchEvent([[maybe_unused]] JNIEnv* env, +                                                              [[maybe_unused]] jclass clazz, +                                                              jfloat x, jfloat y, +                                                              jboolean pressed) { +    return static_cast<jboolean>(emu_window->OnTouchEvent(x, y, pressed)); +} + +void Java_org_citra_citra_1emu_NativeLibrary_onTouchMoved([[maybe_unused]] JNIEnv* env, +                                                          [[maybe_unused]] jclass clazz, jfloat x, +                                                          jfloat y) { +    emu_window->OnTouchMoved(x, y); +} + +jintArray Java_org_citra_citra_1emu_NativeLibrary_GetIcon([[maybe_unused]] JNIEnv* env, +                                                          [[maybe_unused]] jclass clazz, +                                                          [[maybe_unused]] jstring j_file) { +    return {}; +} + +jstring Java_org_citra_citra_1emu_NativeLibrary_GetTitle([[maybe_unused]] JNIEnv* env, +                                                         [[maybe_unused]] jclass clazz, +                                                         [[maybe_unused]] jstring j_filename) { +    return env->NewStringUTF(""); +} + +jstring Java_org_citra_citra_1emu_NativeLibrary_GetDescription([[maybe_unused]] JNIEnv* env, +                                                               [[maybe_unused]] jclass clazz, +                                                               jstring j_filename) { +    return j_filename; +} + +jstring Java_org_citra_citra_1emu_NativeLibrary_GetGameId([[maybe_unused]] JNIEnv* env, +                                                          [[maybe_unused]] jclass clazz, +                                                          jstring j_filename) { +    return j_filename; +} + +jstring Java_org_citra_citra_1emu_NativeLibrary_GetRegions([[maybe_unused]] JNIEnv* env, +                                                           [[maybe_unused]] jclass clazz, +                                                           [[maybe_unused]] jstring j_filename) { +    return env->NewStringUTF(""); +} + +jstring Java_org_citra_citra_1emu_NativeLibrary_GetCompany([[maybe_unused]] JNIEnv* env, +                                                           [[maybe_unused]] jclass clazz, +                                                           [[maybe_unused]] jstring j_filename) { +    return env->NewStringUTF(""); +} + +jstring Java_org_citra_citra_1emu_NativeLibrary_GetGitRevision([[maybe_unused]] JNIEnv* env, +                                                               [[maybe_unused]] jclass clazz) { +    return {}; +} + +void Java_org_citra_citra_1emu_NativeLibrary_CreateConfigFile +    [[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) {} + +jint Java_org_citra_citra_1emu_NativeLibrary_DefaultCPUCore([[maybe_unused]] JNIEnv* env, +                                                            [[maybe_unused]] jclass clazz) { +    return {}; +} + +void Java_org_citra_citra_1emu_NativeLibrary_Run__Ljava_lang_String_2Ljava_lang_String_2Z( +    [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, [[maybe_unused]] jstring j_file, +    [[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {} + +void Java_org_citra_citra_1emu_NativeLibrary_ReloadSettings([[maybe_unused]] JNIEnv* env, +                                                            [[maybe_unused]] jclass clazz) {} + +jstring Java_org_citra_citra_1emu_NativeLibrary_GetUserSetting([[maybe_unused]] JNIEnv* env, +                                                               [[maybe_unused]] jclass clazz, +                                                               jstring j_game_id, jstring j_section, +                                                               jstring j_key) { +    std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); +    std::string_view section = env->GetStringUTFChars(j_section, 0); +    std::string_view key = env->GetStringUTFChars(j_key, 0); + +    env->ReleaseStringUTFChars(j_game_id, game_id.data()); +    env->ReleaseStringUTFChars(j_section, section.data()); +    env->ReleaseStringUTFChars(j_key, key.data()); + +    return env->NewStringUTF(""); +} + +void Java_org_citra_citra_1emu_NativeLibrary_SetUserSetting([[maybe_unused]] JNIEnv* env, +                                                            [[maybe_unused]] jclass clazz, +                                                            jstring j_game_id, jstring j_section, +                                                            jstring j_key, jstring j_value) { +    std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); +    std::string_view section = env->GetStringUTFChars(j_section, 0); +    std::string_view key = env->GetStringUTFChars(j_key, 0); +    std::string_view value = env->GetStringUTFChars(j_value, 0); + +    env->ReleaseStringUTFChars(j_game_id, game_id.data()); +    env->ReleaseStringUTFChars(j_section, section.data()); +    env->ReleaseStringUTFChars(j_key, key.data()); +    env->ReleaseStringUTFChars(j_value, value.data()); +} + +void Java_org_citra_citra_1emu_NativeLibrary_InitGameIni([[maybe_unused]] JNIEnv* env, +                                                         [[maybe_unused]] jclass clazz, +                                                         jstring j_game_id) { +    std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); + +    env->ReleaseStringUTFChars(j_game_id, game_id.data()); +} + +jdoubleArray Java_org_citra_citra_1emu_NativeLibrary_GetPerfStats([[maybe_unused]] JNIEnv* env, +                                                                  [[maybe_unused]] jclass clazz) { +    jdoubleArray j_stats = env->NewDoubleArray(4); + +    if (!stop_run && system_.IsPoweredOn()) { +        const auto results = system_.GetAndResetPerfStats(); + +        // Converting the structure into an array makes it easier to pass it to the frontend +        double stats[4] = {results.system_fps, results.average_game_fps, results.frametime, +                           results.emulation_speed}; + +        env->SetDoubleArrayRegion(j_stats, 0, 4, stats); +    } + +    return j_stats; +} + +void Java_org_citra_citra_1emu_utils_DirectoryInitialization_SetSysDirectory( +    [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jstring j_path) {} + +void Java_org_citra_citra_1emu_NativeLibrary_Run__Ljava_lang_String_2([[maybe_unused]] JNIEnv* env, +                                                                      [[maybe_unused]] jclass clazz, +                                                                      jstring j_path) { +    const std::string path = GetJString(env, j_path); + +    if (!stop_run) { +        stop_run = true; +    } + +    const Core::SystemResultStatus result{RunEmulation(path)}; +    if (result != Core::SystemResultStatus::Success) { +        env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), +                                  IDCache::GetExitEmulationActivity(), static_cast<int>(result)); +    } +} + +void Java_org_citra_citra_1emu_NativeLibrary_LogDeviceInfo([[maybe_unused]] JNIEnv* env, +                                                           [[maybe_unused]] jclass clazz) { +    LOG_INFO(Frontend, "yuzu Version: {}-{}", Common::g_scm_branch, Common::g_scm_desc); +    LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level()); +} + +} // extern "C" diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h new file mode 100644 index 000000000..16c90e215 --- /dev/null +++ b/src/android/app/src/main/jni/native.h @@ -0,0 +1,127 @@ +#pragma once + +#include <jni.h> + +// Function calls from the Java side +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_UnPauseEmulation(JNIEnv* env, +                                                                                jclass clazz); + +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_PauseEmulation(JNIEnv* env, +                                                                              jclass clazz); + +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_StopEmulation(JNIEnv* env, +                                                                             jclass clazz); + +JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_IsRunning(JNIEnv* env, +                                                                             jclass clazz); + +JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_onGamePadEvent( +    JNIEnv* env, jclass clazz, jstring j_device, jint j_button, jint action); + +JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_onGamePadMoveEvent( +    JNIEnv* env, jclass clazz, jstring j_device, jint axis, jfloat x, jfloat y); + +JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_onGamePadAxisEvent( +    JNIEnv* env, jclass clazz, jstring j_device, jint axis_id, jfloat axis_val); + +JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_onTouchEvent(JNIEnv* env, +                                                                                jclass clazz, +                                                                                jfloat x, jfloat y, +                                                                                jboolean pressed); + +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_onTouchMoved(JNIEnv* env, +                                                                            jclass clazz, jfloat x, +                                                                            jfloat y); + +JNIEXPORT jintArray JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetIcon(JNIEnv* env, +                                                                            jclass clazz, +                                                                            jstring j_file); + +JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetTitle(JNIEnv* env, +                                                                           jclass clazz, +                                                                           jstring j_filename); + +JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetDescription( +    JNIEnv* env, jclass clazz, jstring j_filename); + +JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetGameId(JNIEnv* env, +                                                                            jclass clazz, +                                                                            jstring j_filename); + +JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetRegions(JNIEnv* env, +                                                                             jclass clazz, +                                                                             jstring j_filename); + +JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetCompany(JNIEnv* env, +                                                                             jclass clazz, +                                                                             jstring j_filename); + +JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetGitRevision(JNIEnv* env, +                                                                                 jclass clazz); + +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SetUserDirectory( +    JNIEnv* env, jclass clazz, jstring j_directory); + +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_utils_DirectoryInitialization_SetSysDirectory( +    JNIEnv* env, jclass clazz, jstring path_); + +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SetSysDirectory(JNIEnv* env, +                                                                               jclass clazz, +                                                                               jstring path); + +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_CreateConfigFile(JNIEnv* env, +                                                                                jclass clazz); + +JNIEXPORT jint JNICALL Java_org_citra_citra_1emu_NativeLibrary_DefaultCPUCore(JNIEnv* env, +                                                                              jclass clazz); +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SetProfiling(JNIEnv* env, +                                                                            jclass clazz, +                                                                            jboolean enable); + +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_WriteProfileResults(JNIEnv* env, +                                                                                   jclass clazz); + +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_NotifyOrientationChange( +    JNIEnv* env, jclass clazz, jint layout_option, jint rotation); + +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_Run__Ljava_lang_String_2( +    JNIEnv* env, jclass clazz, jstring j_path); + +JNIEXPORT void JNICALL +Java_org_citra_citra_1emu_NativeLibrary_Run__Ljava_lang_String_2Ljava_lang_String_2Z( +    JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate); + +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env, +                                                                              jclass clazz, +                                                                              jobject surf); + +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SurfaceDestroyed(JNIEnv* env, +                                                                                jclass clazz); + +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_InitGameIni(JNIEnv* env, +                                                                           jclass clazz, +                                                                           jstring j_game_id); + +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_ReloadSettings(JNIEnv* env, +                                                                              jclass clazz); + +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SetUserSetting( +    JNIEnv* env, jclass clazz, jstring j_game_id, jstring j_section, jstring j_key, +    jstring j_value); + +JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetUserSetting( +    JNIEnv* env, jclass clazz, jstring game_id, jstring section, jstring key); + +JNIEXPORT jdoubleArray JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetPerfStats(JNIEnv* env, +                                                                                    jclass clazz); + +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_LogDeviceInfo(JNIEnv* env, +                                                                             jclass clazz); + +#ifdef __cplusplus +} +#endif | 
