android: Minimal JNI for yuzu.
This commit is contained in:
parent
bb2cbbfba3
commit
e6d5dbb58e
|
@ -195,3 +195,8 @@ endif()
|
||||||
if (ENABLE_WEB_SERVICE)
|
if (ENABLE_WEB_SERVICE)
|
||||||
add_subdirectory(web_service)
|
add_subdirectory(web_service)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (ANDROID)
|
||||||
|
add_subdirectory(android/app/src/main/jni)
|
||||||
|
target_include_directories(yuzu-android PRIVATE android/app/src/main)
|
||||||
|
endif()
|
||||||
|
|
15
src/android/app/src/main/jni/CMakeLists.txt
Normal file
15
src/android/app/src/main/jni/CMakeLists.txt
Normal file
|
@ -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)
|
58
src/android/app/src/main/jni/emu_window/emu_window.cpp
Normal file
58
src/android/app/src/main/jni/emu_window/emu_window.cpp
Normal file
|
@ -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();
|
||||||
|
}
|
51
src/android/app/src/main/jni/emu_window/emu_window.h
Normal file
51
src/android/app/src/main/jni/emu_window/emu_window.h
Normal file
|
@ -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{};
|
||||||
|
};
|
36
src/android/app/src/main/jni/id_cache.cpp
Normal file
36
src/android/app/src/main/jni/id_cache.cpp
Normal file
|
@ -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
|
11
src/android/app/src/main/jni/id_cache.h
Normal file
11
src/android/app/src/main/jni/id_cache.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
namespace IDCache {
|
||||||
|
|
||||||
|
JNIEnv* GetEnvForThread();
|
||||||
|
jclass GetNativeLibraryClass();
|
||||||
|
jmethodID GetExitEmulationActivity();
|
||||||
|
|
||||||
|
} // namespace IDCache
|
342
src/android/app/src/main/jni/native.cpp
Normal file
342
src/android/app/src/main/jni/native.cpp
Normal file
|
@ -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"
|
127
src/android/app/src/main/jni/native.h
Normal file
127
src/android/app/src/main/jni/native.h
Normal file
|
@ -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
|
Loading…
Reference in a new issue