From f9cbc3acfb2e1a0277c9d8a18d398a1c478ff8d5 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sat, 11 Jul 2020 03:29:15 +1000 Subject: [PATCH] Android: Hook up settings interface --- android/.idea/gradle.xml | 12 +- android/.idea/jarRepositories.xml | 25 +++ android/app/build.gradle | 1 + android/app/src/cpp/CMakeLists.txt | 2 + .../app/src/cpp/android_host_interface.cpp | 57 +++--- android/app/src/cpp/android_host_interface.h | 13 +- .../src/cpp/android_settings_interface.cpp | 178 ++++++++++++++++++ .../app/src/cpp/android_settings_interface.h | 37 ++++ .../duckstation/AndroidHostInterface.java | 3 +- .../duckstation/EmulationActivity.java | 2 +- android/app/src/main/res/values/strings.xml | 11 +- .../app/src/main/res/xml/root_preferences.xml | 35 +++- 12 files changed, 334 insertions(+), 42 deletions(-) create mode 100644 android/.idea/jarRepositories.xml create mode 100644 android/app/src/cpp/android_settings_interface.cpp create mode 100644 android/app/src/cpp/android_settings_interface.h diff --git a/android/.idea/gradle.xml b/android/.idea/gradle.xml index d291b3d7c..5cd135a06 100644 --- a/android/.idea/gradle.xml +++ b/android/.idea/gradle.xml @@ -1,15 +1,19 @@ + diff --git a/android/.idea/jarRepositories.xml b/android/.idea/jarRepositories.xml new file mode 100644 index 000000000..a5f05cd8c --- /dev/null +++ b/android/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index 022d4179e..782b0d479 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -28,6 +28,7 @@ android { externalNativeBuild { cmake { arguments "-DCMAKE_BUILD_TYPE=RelWithDebInfo" + abiFilters "arm64-v8a" } } } diff --git a/android/app/src/cpp/CMakeLists.txt b/android/app/src/cpp/CMakeLists.txt index 83e3d3240..d8b1d9d3f 100644 --- a/android/app/src/cpp/CMakeLists.txt +++ b/android/app/src/cpp/CMakeLists.txt @@ -1,6 +1,8 @@ set(SRCS android_host_interface.cpp android_host_interface.h + android_settings_interface.cpp + android_settings_interface.h main.cpp ) diff --git a/android/app/src/cpp/android_host_interface.cpp b/android/app/src/cpp/android_host_interface.cpp index d9db45ebf..0e4ba0d30 100644 --- a/android/app/src/cpp/android_host_interface.cpp +++ b/android/app/src/cpp/android_host_interface.cpp @@ -21,8 +21,9 @@ static jclass s_AndroidHostInterface_class; static jmethodID s_AndroidHostInterface_constructor; static jfieldID s_AndroidHostInterface_field_nativePointer; +namespace AndroidHelpers { // helper for retrieving the current per-thread jni environment -static JNIEnv* GetJNIEnv() +JNIEnv* GetJNIEnv() { JNIEnv* env; if (s_jvm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) @@ -31,13 +32,13 @@ static JNIEnv* GetJNIEnv() return env; } -static AndroidHostInterface* GetNativeClass(JNIEnv* env, jobject obj) +AndroidHostInterface* GetNativeClass(JNIEnv* env, jobject obj) { return reinterpret_cast( static_cast(env->GetLongField(obj, s_AndroidHostInterface_field_nativePointer))); } -static std::string JStringToString(JNIEnv* env, jstring str) +std::string JStringToString(JNIEnv* env, jstring str) { if (str == nullptr) return {}; @@ -54,13 +55,17 @@ static std::string JStringToString(JNIEnv* env, jstring str) return ret; } +} // namespace AndroidHelpers -AndroidHostInterface::AndroidHostInterface(jobject java_object) : m_java_object(java_object) {} +AndroidHostInterface::AndroidHostInterface(jobject java_object, jobject context_object) + : m_java_object(java_object), m_settings_interface(context_object) +{ +} AndroidHostInterface::~AndroidHostInterface() { ImGui::DestroyContext(); - GetJNIEnv()->DeleteGlobalRef(m_java_object); + AndroidHelpers::GetJNIEnv()->DeleteGlobalRef(m_java_object); } bool AndroidHostInterface::Initialize() @@ -98,7 +103,7 @@ void AndroidHostInterface::ReportMessage(const char* message) std::string AndroidHostInterface::GetSettingValue(const char* section, const char* key, const char* default_value) { - return m_settings_interface->GetStringValue(section, key, default_value); + return m_settings_interface.GetStringValue(section, key, default_value); } void AndroidHostInterface::SetUserDirectory() @@ -109,13 +114,12 @@ void AndroidHostInterface::SetUserDirectory() void AndroidHostInterface::LoadSettings() { - m_settings_interface = std::make_unique(GetSettingsFileName()); - CommonHostInterface::LoadSettings(*m_settings_interface); + CommonHostInterface::LoadSettings(m_settings_interface); } void AndroidHostInterface::UpdateInputMap() { - CommonHostInterface::UpdateInputMap(*m_settings_interface); + CommonHostInterface::UpdateInputMap(m_settings_interface); } bool AndroidHostInterface::StartEmulationThread(ANativeWindow* initial_surface, SystemBootParameters boot_params) @@ -382,7 +386,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) Log::SetDebugOutputParams(true, nullptr, LOGLEVEL_DEV); s_jvm = vm; - JNIEnv* env = GetJNIEnv(); + JNIEnv* env = AndroidHelpers::GetJNIEnv(); if ((s_AndroidHostInterface_class = env->FindClass("com/github/stenzek/duckstation/AndroidHostInterface")) == nullptr) { Log_ErrorPrint("AndroidHostInterface class lookup failed"); @@ -415,7 +419,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) #define DEFINE_JNI_ARGS_METHOD(return_type, name, ...) \ extern "C" JNIEXPORT return_type JNICALL Java_com_github_stenzek_duckstation_##name(JNIEnv* env, __VA_ARGS__) -DEFINE_JNI_ARGS_METHOD(jobject, AndroidHostInterface_create, jobject unused) +DEFINE_JNI_ARGS_METHOD(jobject, AndroidHostInterface_create, jobject unused, jobject context_object) { Log::SetDebugOutputParams(true, nullptr, LOGLEVEL_DEBUG); @@ -431,7 +435,7 @@ DEFINE_JNI_ARGS_METHOD(jobject, AndroidHostInterface_create, jobject unused) Assert(java_obj_ref != nullptr); // initialize the C++ side - AndroidHostInterface* cpp_obj = new AndroidHostInterface(java_obj_ref); + AndroidHostInterface* cpp_obj = new AndroidHostInterface(java_obj_ref, context_object); if (!cpp_obj->Initialize()) { // TODO: Do we need to release the original java object reference? @@ -448,7 +452,7 @@ DEFINE_JNI_ARGS_METHOD(jobject, AndroidHostInterface_create, jobject unused) DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_isEmulationThreadRunning, jobject obj) { - return GetNativeClass(env, obj)->IsEmulationThreadRunning(); + return AndroidHelpers::GetNativeClass(env, obj)->IsEmulationThreadRunning(); } DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_startEmulationThread, jobject obj, jobject surface, @@ -461,17 +465,17 @@ DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_startEmulationThread, jobj return false; } - std::string state_filename_str = JStringToString(env, state_filename); + std::string state_filename_str = AndroidHelpers::JStringToString(env, state_filename); SystemBootParameters boot_params; - boot_params.filename = JStringToString(env, filename); + boot_params.filename = AndroidHelpers::JStringToString(env, filename); - return GetNativeClass(env, obj)->StartEmulationThread(native_surface, std::move(boot_params)); + return AndroidHelpers::GetNativeClass(env, obj)->StartEmulationThread(native_surface, std::move(boot_params)); } DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_stopEmulationThread, jobject obj) { - GetNativeClass(env, obj)->StopEmulationThread(); + AndroidHelpers::GetNativeClass(env, obj)->StopEmulationThread(); } DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_surfaceChanged, jobject obj, jobject surface, jint format, jint width, @@ -481,38 +485,41 @@ DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_surfaceChanged, jobject obj, j if (!native_surface) Log_ErrorPrint("ANativeWindow_fromSurface() returned null"); - AndroidHostInterface* hi = GetNativeClass(env, obj); + AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj); hi->RunOnEmulationThread( [hi, native_surface, format, width, height]() { hi->SurfaceChanged(native_surface, format, width, height); }, true); } DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_setControllerType, jobject obj, jint index, jstring controller_type) { - GetNativeClass(env, obj)->SetControllerType(index, JStringToString(env, controller_type)); + AndroidHelpers::GetNativeClass(env, obj)->SetControllerType(index, + AndroidHelpers::JStringToString(env, controller_type)); } DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_setControllerButtonState, jobject obj, jint index, jint button_code, jboolean pressed) { - GetNativeClass(env, obj)->SetControllerButtonState(index, button_code, pressed); + AndroidHelpers::GetNativeClass(env, obj)->SetControllerButtonState(index, button_code, pressed); } DEFINE_JNI_ARGS_METHOD(jint, AndroidHostInterface_getControllerButtonCode, jobject unused, jstring controller_type, jstring button_name) { - std::optional type = Settings::ParseControllerTypeName(JStringToString(env, controller_type).c_str()); + std::optional type = + Settings::ParseControllerTypeName(AndroidHelpers::JStringToString(env, controller_type).c_str()); if (!type) return -1; - std::optional code = Controller::GetButtonCodeByName(type.value(), JStringToString(env, button_name)); + std::optional code = + Controller::GetButtonCodeByName(type.value(), AndroidHelpers::JStringToString(env, button_name)); return code.value_or(-1); } DEFINE_JNI_ARGS_METHOD(jarray, GameList_getEntries, jobject unused, jstring j_cache_path, jstring j_redump_dat_path, jarray j_search_directories, jboolean search_recursively) { - // const std::string cache_path = JStringToString(env, j_cache_path); - std::string redump_dat_path = JStringToString(env, j_redump_dat_path); + // const std::string cache_path = AndroidHelpers::JStringToString(env, j_cache_path); + std::string redump_dat_path = AndroidHelpers::JStringToString(env, j_redump_dat_path); // TODO: This should use the base HostInterface. GameList gl; @@ -523,7 +530,7 @@ DEFINE_JNI_ARGS_METHOD(jarray, GameList_getEntries, jobject unused, jstring j_ca for (jsize i = 0; i < search_directories_size; i++) { jobject search_dir_obj = env->GetObjectArrayElement(reinterpret_cast(j_search_directories), i); - const std::string search_dir = JStringToString(env, reinterpret_cast(search_dir_obj)); + const std::string search_dir = AndroidHelpers::JStringToString(env, reinterpret_cast(search_dir_obj)); if (!search_dir.empty()) gl.AddDirectory(search_dir.c_str(), search_recursively); } diff --git a/android/app/src/cpp/android_host_interface.h b/android/app/src/cpp/android_host_interface.h index fedf2ebca..4988a12dc 100644 --- a/android/app/src/cpp/android_host_interface.h +++ b/android/app/src/cpp/android_host_interface.h @@ -1,12 +1,13 @@ #pragma once +#include "android_settings_interface.h" #include "common/event.h" #include "frontend-common/common_host_interface.h" -#include "frontend-common/ini_settings_interface.h" #include #include #include #include #include +#include #include struct ANativeWindow; @@ -16,7 +17,7 @@ class Controller; class AndroidHostInterface final : public CommonHostInterface { public: - AndroidHostInterface(jobject java_object); + AndroidHostInterface(jobject java_object, jobject context_object); ~AndroidHostInterface() override; bool Initialize() override; @@ -57,7 +58,7 @@ private: jobject m_java_object = {}; - std::unique_ptr m_settings_interface; + AndroidSettingsInterface m_settings_interface; ANativeWindow* m_surface = nullptr; @@ -69,3 +70,9 @@ private: std::atomic_bool m_emulation_thread_start_result{false}; Common::Event m_emulation_thread_started; }; + +namespace AndroidHelpers { +JNIEnv* GetJNIEnv(); +AndroidHostInterface* GetNativeClass(JNIEnv* env, jobject obj); +std::string JStringToString(JNIEnv* env, jstring str); +} // namespace AndroidHelpers diff --git a/android/app/src/cpp/android_settings_interface.cpp b/android/app/src/cpp/android_settings_interface.cpp new file mode 100644 index 000000000..674731e38 --- /dev/null +++ b/android/app/src/cpp/android_settings_interface.cpp @@ -0,0 +1,178 @@ +#include "android_settings_interface.h" +#include "android_host_interface.h" +#include "common/assert.h" +#include "common/log.h" +#include "common/string.h" +#include "common/string_util.h" +#include +Log_SetChannel(AndroidSettingsInterface); + +ALWAYS_INLINE TinyString GetSettingKey(const char* section, const char* key) +{ + return TinyString::FromFormat("%s/%s", section, key); +} + +AndroidSettingsInterface::AndroidSettingsInterface(jobject java_context) +{ + JNIEnv* env = AndroidHelpers::GetJNIEnv(); + jclass c_preference_manager = env->FindClass("androidx/preference/PreferenceManager"); + jclass c_set = env->FindClass("java/util/Set"); + jmethodID m_get_default_shared_preferences = + env->GetStaticMethodID(c_preference_manager, "getDefaultSharedPreferences", + "(Landroid/content/Context;)Landroid/content/SharedPreferences;"); + Assert(c_preference_manager && c_set && m_get_default_shared_preferences); + + m_java_shared_preferences = + env->CallStaticObjectMethod(c_preference_manager, m_get_default_shared_preferences, java_context); + Assert(m_java_shared_preferences); + m_java_shared_preferences = env->NewGlobalRef(m_java_shared_preferences); + jclass c_shared_preferences = env->GetObjectClass(m_java_shared_preferences); + + m_get_boolean = env->GetMethodID(c_shared_preferences, "getBoolean", "(Ljava/lang/String;Z)Z"); + m_get_int = env->GetMethodID(c_shared_preferences, "getInt", "(Ljava/lang/String;I)I"); + m_get_float = env->GetMethodID(c_shared_preferences, "getFloat", "(Ljava/lang/String;F)F"); + m_get_string = + env->GetMethodID(c_shared_preferences, "getString", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); + m_get_string_set = + env->GetMethodID(c_shared_preferences, "getStringSet", "(Ljava/lang/String;Ljava/util/Set;)Ljava/util/Set;"); + m_set_to_array = env->GetMethodID(c_set, "toArray", "()[Ljava/lang/Object;"); + Assert(m_get_boolean && m_get_int && m_get_float && m_get_string && m_get_string_set && m_set_to_array); +} + +AndroidSettingsInterface::~AndroidSettingsInterface() +{ + if (m_java_shared_preferences) + AndroidHelpers::GetJNIEnv()->DeleteGlobalRef(m_java_shared_preferences); +} + +void AndroidSettingsInterface::Clear() +{ + Log_ErrorPrint("Not implemented"); +} + +int AndroidSettingsInterface::GetIntValue(const char* section, const char* key, int default_value /*= 0*/) +{ + JNIEnv* env = AndroidHelpers::GetJNIEnv(); +#if 0 + return static_cast(env->CallIntMethod(m_java_shared_preferences, m_get_int, + env->NewStringUTF(GetSettingKey(section, key)), default_value)); +#else + // Some of these settings are string lists... + jstring string_object = reinterpret_cast( + env->CallObjectMethod(m_java_shared_preferences, m_get_string, env->NewStringUTF(GetSettingKey(section, key)), + env->NewStringUTF(TinyString::FromFormat("%d", default_value)))); + if (!string_object) + return default_value; + + const char* data = env->GetStringUTFChars(string_object, nullptr); + Assert(data != nullptr); + + std::optional value = StringUtil::FromChars(data); + env->ReleaseStringUTFChars(string_object, data); + return value.value_or(default_value); +#endif +} + +float AndroidSettingsInterface::GetFloatValue(const char* section, const char* key, float default_value /*= 0.0f*/) +{ + JNIEnv* env = AndroidHelpers::GetJNIEnv(); +#if 0 + return static_cast(env->CallFloatMethod(m_java_shared_preferences, m_get_float, + env->NewStringUTF(GetSettingKey(section, key)), default_value)); +#else + // Some of these settings are string lists... + jstring string_object = reinterpret_cast( + env->CallObjectMethod(m_java_shared_preferences, m_get_string, env->NewStringUTF(GetSettingKey(section, key)), + env->NewStringUTF(TinyString::FromFormat("%f", default_value)))); + if (!string_object) + return default_value; + + const char* data = env->GetStringUTFChars(string_object, nullptr); + Assert(data != nullptr); + + std::optional value = StringUtil::FromChars(data); + env->ReleaseStringUTFChars(string_object, data); + return value.value_or(default_value); +#endif +} + +bool AndroidSettingsInterface::GetBoolValue(const char* section, const char* key, bool default_value /*= false*/) +{ + JNIEnv* env = AndroidHelpers::GetJNIEnv(); + return static_cast(env->CallBooleanMethod(m_java_shared_preferences, m_get_boolean, + env->NewStringUTF(GetSettingKey(section, key)), default_value)); +} + +std::string AndroidSettingsInterface::GetStringValue(const char* section, const char* key, + const char* default_value /*= ""*/) +{ + JNIEnv* env = AndroidHelpers::GetJNIEnv(); + jobject string_object = + env->CallObjectMethod(m_java_shared_preferences, m_get_string, env->NewStringUTF(GetSettingKey(section, key)), + env->NewStringUTF(default_value)); + return AndroidHelpers::JStringToString(env, reinterpret_cast(string_object)); +} + +void AndroidSettingsInterface::SetIntValue(const char* section, const char* key, int value) +{ + Log_ErrorPrintf("SetIntValue(\"%s\", \"%s\", %d) not implemented", section, key, value); +} + +void AndroidSettingsInterface::SetFloatValue(const char* section, const char* key, float value) +{ + Log_ErrorPrintf("SetFloatValue(\"%s\", \"%s\", %f) not implemented", section, key, value); +} + +void AndroidSettingsInterface::SetBoolValue(const char* section, const char* key, bool value) +{ + Log_ErrorPrintf("SetBoolValue(\"%s\", \"%s\", %u) not implemented", section, key, static_cast(value)); +} + +void AndroidSettingsInterface::SetStringValue(const char* section, const char* key, const char* value) +{ + Log_ErrorPrintf("SetStringValue(\"%s\", \"%s\", \"%s\") not implemented", section, key, value); +} + +void AndroidSettingsInterface::DeleteValue(const char* section, const char* key) +{ + Log_ErrorPrintf("DeleteValue(\"%s\", \"%s\") not implemented", section, key); +} + +std::vector AndroidSettingsInterface::GetStringList(const char* section, const char* key) +{ + JNIEnv* env = AndroidHelpers::GetJNIEnv(); + jobject values_set = env->CallObjectMethod(m_java_shared_preferences, m_get_string_set, nullptr); + if (!values_set) + return {}; + + jobjectArray values_array = reinterpret_cast(env->CallObjectMethod(values_set, m_set_to_array)); + if (!values_array) + return {}; + + jsize size = env->GetArrayLength(values_array); + std::vector values; + values.reserve(size); + for (jsize i = 0; i < size; i++) + values.push_back( + AndroidHelpers::JStringToString(env, reinterpret_cast(env->GetObjectArrayElement(values_array, i)))); + + return values; +} + +void AndroidSettingsInterface::SetStringList(const char* section, const char* key, + const std::vector& items) +{ + Log_ErrorPrintf("SetStringList(\"%s\", \"%s\") not implemented", section, key); +} + +bool AndroidSettingsInterface::RemoveFromStringList(const char* section, const char* key, const char* item) +{ + Log_ErrorPrintf("RemoveFromStringList(\"%s\", \"%s\", \"%s\") not implemented", section, key, item); + return false; +} + +bool AndroidSettingsInterface::AddToStringList(const char* section, const char* key, const char* item) +{ + Log_ErrorPrintf("AddToStringList(\"%s\", \"%s\", \"%s\") not implemented", section, key, item); + return false; +} diff --git a/android/app/src/cpp/android_settings_interface.h b/android/app/src/cpp/android_settings_interface.h new file mode 100644 index 000000000..2841b601d --- /dev/null +++ b/android/app/src/cpp/android_settings_interface.h @@ -0,0 +1,37 @@ +#pragma once +#include "core/settings.h" +#include + +class AndroidSettingsInterface : public SettingsInterface +{ +public: + AndroidSettingsInterface(jobject java_context); + ~AndroidSettingsInterface(); + + void Clear() override; + + int GetIntValue(const char* section, const char* key, int default_value = 0) override; + float GetFloatValue(const char* section, const char* key, float default_value = 0.0f) override; + bool GetBoolValue(const char* section, const char* key, bool default_value = false) override; + std::string GetStringValue(const char* section, const char* key, const char* default_value = "") override; + + void SetIntValue(const char* section, const char* key, int value) override; + void SetFloatValue(const char* section, const char* key, float value) override; + void SetBoolValue(const char* section, const char* key, bool value) override; + void SetStringValue(const char* section, const char* key, const char* value) override; + void DeleteValue(const char* section, const char* key) override; + + std::vector GetStringList(const char* section, const char* key) override; + void SetStringList(const char* section, const char* key, const std::vector& items) override; + bool RemoveFromStringList(const char* section, const char* key, const char* item) override; + bool AddToStringList(const char* section, const char* key, const char* item) override; + +private: + jobject m_java_shared_preferences{}; + jmethodID m_get_boolean{}; + jmethodID m_get_int{}; + jmethodID m_get_float{}; + jmethodID m_get_string{}; + jmethodID m_get_string_set{}; + jmethodID m_set_to_array{}; +}; diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/AndroidHostInterface.java b/android/app/src/main/java/com/github/stenzek/duckstation/AndroidHostInterface.java index 8769967e8..79eb44374 100644 --- a/android/app/src/main/java/com/github/stenzek/duckstation/AndroidHostInterface.java +++ b/android/app/src/main/java/com/github/stenzek/duckstation/AndroidHostInterface.java @@ -1,5 +1,6 @@ package com.github.stenzek.duckstation; +import android.content.Context; import android.view.Surface; public class AndroidHostInterface @@ -10,7 +11,7 @@ public class AndroidHostInterface System.loadLibrary("duckstation-native"); } - static public native AndroidHostInterface create(); + static public native AndroidHostInterface create(Context context); public AndroidHostInterface(long nativePointer) { diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java index 38ab77914..1aecad6dc 100644 --- a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java +++ b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java @@ -142,7 +142,7 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde } }); - mHostInterface = AndroidHostInterface.create(); + mHostInterface = AndroidHostInterface.create(this); if (mHostInterface == null) throw new InstantiationError("Failed to create host interface"); diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 1c275b09a..4e41aacef 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -6,7 +6,7 @@ Console Behavior - Host Synchronization + On-Screen Display CPU GPU @@ -20,18 +20,21 @@ Enable Speed Limiter Pause On Start - - Sync To Audio Sync To Video + + Show Messages + Show Emulation Speed + Show FPS + Show VPS + Execution Mode Interpreter Renderer - OpenGL Display Linear Filtering Resolution Scale True 24-Bit Color (Disables Dithering) diff --git a/android/app/src/main/res/xml/root_preferences.xml b/android/app/src/main/res/xml/root_preferences.xml index 723111c01..1b2b84515 100644 --- a/android/app/src/main/res/xml/root_preferences.xml +++ b/android/app/src/main/res/xml/root_preferences.xml @@ -49,11 +49,13 @@ @@ -62,6 +64,7 @@ + + + + + + + @@ -95,7 +121,7 @@ app:title="@string/settings_gpu_renderer" app:entries="@array/gpu_renderer_entries" app:entryValues="@array/gpu_renderer_values" - app:defaultValue="@string/settings_gpu_renderer_default" + app:defaultValue="OpenGL" app:useSimpleSummaryProvider="true" /> + + app:defaultValue="false"/>