summaryrefslogtreecommitdiff
path: root/src/android/app
diff options
context:
space:
mode:
authorGravatar bunnei2023-04-11 22:03:19 -0700
committerGravatar bunnei2023-06-03 00:05:50 -0700
commit4006468f7368d0afe51be11a466e5b33c62e362d (patch)
treeca0294e6f596aa09a05352ad56687a41de60a764 /src/android/app
parentandroid: vulkan_debug_callback: Ignore many innocuous errors. (diff)
downloadyuzu-4006468f7368d0afe51be11a466e5b33c62e362d.tar.gz
yuzu-4006468f7368d0afe51be11a466e5b33c62e362d.tar.xz
yuzu-4006468f7368d0afe51be11a466e5b33c62e362d.zip
android: video_core: Add support for disk shader cache. (#64)
Diffstat (limited to 'src/android/app')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt1
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress.kt46
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ShaderProgressViewModel.kt31
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ui/ShaderProgressDialogFragment.kt101
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt12
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt1
-rw-r--r--src/android/app/src/main/jni/config.cpp4
-rw-r--r--src/android/app/src/main/jni/id_cache.cpp27
-rw-r--r--src/android/app/src/main/jni/id_cache.h5
-rw-r--r--src/android/app/src/main/jni/native.cpp18
-rw-r--r--src/android/app/src/main/res/layout/dialog_progress_bar.xml9
-rw-r--r--src/android/app/src/main/res/values/strings.xml7
12 files changed, 258 insertions, 4 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
index 3ab685b9b..1e654777a 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
@@ -42,6 +42,7 @@ object NativeLibrary {
42 const val Player8Device = 7 42 const val Player8Device = 7
43 const val ConsoleDevice = 8 43 const val ConsoleDevice = 8
44 44
45 @JvmField
45 var sEmulationActivity = WeakReference<EmulationActivity?>(null) 46 var sEmulationActivity = WeakReference<EmulationActivity?>(null)
46 47
47 init { 48 init {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress.kt
new file mode 100644
index 000000000..9b665c7a0
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress.kt
@@ -0,0 +1,46 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.disk_shader_cache
5
6import org.yuzu.yuzu_emu.NativeLibrary
7import org.yuzu.yuzu_emu.R
8import org.yuzu.yuzu_emu.disk_shader_cache.ui.ShaderProgressDialogFragment
9
10object DiskShaderCacheProgress {
11 val finishLock = Object()
12 private lateinit var fragment: ShaderProgressDialogFragment
13
14 private fun prepareDialog() {
15 val emulationActivity = NativeLibrary.sEmulationActivity.get()!!
16 emulationActivity.runOnUiThread {
17 fragment = ShaderProgressDialogFragment.newInstance(
18 emulationActivity.getString(R.string.loading),
19 emulationActivity.getString(R.string.preparing_shaders)
20 )
21 fragment.show(emulationActivity.supportFragmentManager, ShaderProgressDialogFragment.TAG)
22 }
23 synchronized(finishLock) { finishLock.wait() }
24 }
25
26 @JvmStatic
27 fun loadProgress(stage: Int, progress: Int, max: Int) {
28 val emulationActivity = NativeLibrary.sEmulationActivity.get()
29 ?: error("[DiskShaderCacheProgress] EmulationActivity not present")
30
31 when (LoadCallbackStage.values()[stage]) {
32 LoadCallbackStage.Prepare -> prepareDialog()
33 LoadCallbackStage.Build -> fragment.onUpdateProgress(
34 emulationActivity.getString(R.string.building_shaders),
35 progress,
36 max
37 )
38 LoadCallbackStage.Complete -> fragment.dismiss()
39 }
40 }
41
42 // Equivalent to VideoCore::LoadCallbackStage
43 enum class LoadCallbackStage {
44 Prepare, Build, Complete
45 }
46}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ShaderProgressViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ShaderProgressViewModel.kt
new file mode 100644
index 000000000..bf6f0366d
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ShaderProgressViewModel.kt
@@ -0,0 +1,31 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.disk_shader_cache
5
6import androidx.lifecycle.LiveData
7import androidx.lifecycle.MutableLiveData
8import androidx.lifecycle.ViewModel
9
10class ShaderProgressViewModel : ViewModel() {
11 private val _progress = MutableLiveData(0)
12 val progress: LiveData<Int> get() = _progress
13
14 private val _max = MutableLiveData(0)
15 val max: LiveData<Int> get() = _max
16
17 private val _message = MutableLiveData("")
18 val message: LiveData<String> get() = _message
19
20 fun setProgress(progress: Int) {
21 _progress.postValue(progress)
22 }
23
24 fun setMax(max: Int) {
25 _max.postValue(max)
26 }
27
28 fun setMessage(msg: String) {
29 _message.postValue(msg)
30 }
31}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ui/ShaderProgressDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ui/ShaderProgressDialogFragment.kt
new file mode 100644
index 000000000..2c68c9ac3
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ui/ShaderProgressDialogFragment.kt
@@ -0,0 +1,101 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.disk_shader_cache.ui
5
6import android.app.Dialog
7import android.os.Bundle
8import android.view.LayoutInflater
9import android.view.View
10import android.view.ViewGroup
11import androidx.appcompat.app.AlertDialog
12import androidx.fragment.app.DialogFragment
13import androidx.lifecycle.ViewModelProvider
14import com.google.android.material.dialog.MaterialAlertDialogBuilder
15import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
16import org.yuzu.yuzu_emu.disk_shader_cache.DiskShaderCacheProgress
17import org.yuzu.yuzu_emu.disk_shader_cache.ShaderProgressViewModel
18
19class ShaderProgressDialogFragment : DialogFragment() {
20 private var _binding: DialogProgressBarBinding? = null
21 private val binding get() = _binding!!
22
23 private lateinit var alertDialog: AlertDialog
24
25 private lateinit var shaderProgressViewModel: ShaderProgressViewModel
26
27 override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
28 _binding = DialogProgressBarBinding.inflate(layoutInflater)
29 shaderProgressViewModel =
30 ViewModelProvider(requireActivity())[ShaderProgressViewModel::class.java]
31
32 val title = requireArguments().getString(TITLE)
33 val message = requireArguments().getString(MESSAGE)
34
35 isCancelable = false
36 alertDialog = MaterialAlertDialogBuilder(requireActivity())
37 .setView(binding.root)
38 .setTitle(title)
39 .setMessage(message)
40 .create()
41 return alertDialog
42 }
43
44 override fun onCreateView(
45 inflater: LayoutInflater,
46 container: ViewGroup?,
47 savedInstanceState: Bundle?
48 ): View {
49 return binding.root
50 }
51
52 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
53 super.onViewCreated(view, savedInstanceState)
54 shaderProgressViewModel.progress.observe(viewLifecycleOwner) { progress ->
55 binding.progressBar.progress = progress
56 setUpdateText()
57 }
58 shaderProgressViewModel.max.observe(viewLifecycleOwner) { max ->
59 binding.progressBar.max = max
60 setUpdateText()
61 }
62 shaderProgressViewModel.message.observe(viewLifecycleOwner) { msg ->
63 alertDialog.setMessage(msg)
64 }
65 synchronized(DiskShaderCacheProgress.finishLock) { DiskShaderCacheProgress.finishLock.notifyAll() }
66 }
67
68 override fun onDestroyView() {
69 super.onDestroyView()
70 _binding = null
71 }
72
73 fun onUpdateProgress(msg: String, progress: Int, max: Int) {
74 shaderProgressViewModel.setProgress(progress)
75 shaderProgressViewModel.setMax(max)
76 shaderProgressViewModel.setMessage(msg)
77 }
78
79 private fun setUpdateText() {
80 binding.progressText.text = String.format(
81 "%d/%d",
82 shaderProgressViewModel.progress.value,
83 shaderProgressViewModel.max.value
84 )
85 }
86
87 companion object {
88 const val TAG = "ProgressDialogFragment"
89 const val TITLE = "title"
90 const val MESSAGE = "message"
91
92 fun newInstance(title: String, message: String): ShaderProgressDialogFragment {
93 val frag = ShaderProgressDialogFragment()
94 val args = Bundle()
95 args.putString(TITLE, title)
96 args.putString(MESSAGE, message)
97 frag.arguments = args
98 return frag
99 }
100 }
101}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
index f04b81335..a137d1c3a 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
@@ -196,6 +196,8 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
196 val rendererResolution = rendererSection.getSetting(SettingsFile.KEY_RENDERER_RESOLUTION) 196 val rendererResolution = rendererSection.getSetting(SettingsFile.KEY_RENDERER_RESOLUTION)
197 val rendererAspectRatio = 197 val rendererAspectRatio =
198 rendererSection.getSetting(SettingsFile.KEY_RENDERER_ASPECT_RATIO) 198 rendererSection.getSetting(SettingsFile.KEY_RENDERER_ASPECT_RATIO)
199 val rendererUseDiskShaderCache =
200 rendererSection.getSetting(SettingsFile.KEY_RENDERER_USE_DISK_SHADER_CACHE)
199 val rendererForceMaxClocks = 201 val rendererForceMaxClocks =
200 rendererSection.getSetting(SettingsFile.KEY_RENDERER_FORCE_MAX_CLOCK) 202 rendererSection.getSetting(SettingsFile.KEY_RENDERER_FORCE_MAX_CLOCK)
201 val rendererAsynchronousShaders = 203 val rendererAsynchronousShaders =
@@ -252,6 +254,16 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
252 ) 254 )
253 add( 255 add(
254 SwitchSetting( 256 SwitchSetting(
257 SettingsFile.KEY_RENDERER_USE_DISK_SHADER_CACHE,
258 Settings.SECTION_RENDERER,
259 rendererUseDiskShaderCache,
260 R.string.use_disk_shader_cache,
261 R.string.use_disk_shader_cache_description,
262 true
263 )
264 )
265 add(
266 SwitchSetting(
255 SettingsFile.KEY_RENDERER_FORCE_MAX_CLOCK, 267 SettingsFile.KEY_RENDERER_FORCE_MAX_CLOCK,
256 Settings.SECTION_RENDERER, 268 Settings.SECTION_RENDERER,
257 rendererForceMaxClocks, 269 rendererForceMaxClocks,
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt
index 37ae39fe6..c518d9ba0 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt
@@ -36,6 +36,7 @@ object SettingsFile {
36 const val KEY_RENDERER_RESOLUTION = "resolution_setup" 36 const val KEY_RENDERER_RESOLUTION = "resolution_setup"
37 const val KEY_RENDERER_ASPECT_RATIO = "aspect_ratio" 37 const val KEY_RENDERER_ASPECT_RATIO = "aspect_ratio"
38 const val KEY_RENDERER_ACCURACY = "gpu_accuracy" 38 const val KEY_RENDERER_ACCURACY = "gpu_accuracy"
39 const val KEY_RENDERER_USE_DISK_SHADER_CACHE = "use_disk_shader_cache"
39 const val KEY_RENDERER_ASYNCHRONOUS_SHADERS = "use_asynchronous_shaders" 40 const val KEY_RENDERER_ASYNCHRONOUS_SHADERS = "use_asynchronous_shaders"
40 const val KEY_RENDERER_FORCE_MAX_CLOCK = "force_max_clock" 41 const val KEY_RENDERER_FORCE_MAX_CLOCK = "force_max_clock"
41 const val KEY_RENDERER_USE_SPEED_LIMIT = "use_speed_limit" 42 const val KEY_RENDERER_USE_SPEED_LIMIT = "use_speed_limit"
diff --git a/src/android/app/src/main/jni/config.cpp b/src/android/app/src/main/jni/config.cpp
index d882688f1..0e86dea9e 100644
--- a/src/android/app/src/main/jni/config.cpp
+++ b/src/android/app/src/main/jni/config.cpp
@@ -226,10 +226,6 @@ void Config::ReadValues() {
226 ReadSetting("Renderer", Settings::values.bg_green); 226 ReadSetting("Renderer", Settings::values.bg_green);
227 ReadSetting("Renderer", Settings::values.bg_blue); 227 ReadSetting("Renderer", Settings::values.bg_blue);
228 228
229 // Disable shader cache by default on Android
230 Settings::values.use_disk_shader_cache =
231 config->GetBoolean("Renderer", "use_disk_shader_cache", false);
232
233 // Enable force_max_clock by default on Android 229 // Enable force_max_clock by default on Android
234 Settings::values.renderer_force_max_clock = 230 Settings::values.renderer_force_max_clock =
235 config->GetBoolean("Renderer", "force_max_clock", true); 231 config->GetBoolean("Renderer", "force_max_clock", true);
diff --git a/src/android/app/src/main/jni/id_cache.cpp b/src/android/app/src/main/jni/id_cache.cpp
index 6291c8652..7edadb94a 100644
--- a/src/android/app/src/main/jni/id_cache.cpp
+++ b/src/android/app/src/main/jni/id_cache.cpp
@@ -3,13 +3,18 @@
3 3
4#include <jni.h> 4#include <jni.h>
5 5
6#include "common/assert.h"
6#include "common/fs/fs_android.h" 7#include "common/fs/fs_android.h"
7#include "jni/applets/software_keyboard.h" 8#include "jni/applets/software_keyboard.h"
8#include "jni/id_cache.h" 9#include "jni/id_cache.h"
10#include "video_core/rasterizer_interface.h"
9 11
10static JavaVM* s_java_vm; 12static JavaVM* s_java_vm;
11static jclass s_native_library_class; 13static jclass s_native_library_class;
14static jclass s_disk_cache_progress_class;
15static jclass s_load_callback_stage_class;
12static jmethodID s_exit_emulation_activity; 16static jmethodID s_exit_emulation_activity;
17static jmethodID s_disk_cache_load_progress;
13 18
14static constexpr jint JNI_VERSION = JNI_VERSION_1_6; 19static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
15 20
@@ -38,10 +43,22 @@ jclass GetNativeLibraryClass() {
38 return s_native_library_class; 43 return s_native_library_class;
39} 44}
40 45
46jclass GetDiskCacheProgressClass() {
47 return s_disk_cache_progress_class;
48}
49
50jclass GetDiskCacheLoadCallbackStageClass() {
51 return s_load_callback_stage_class;
52}
53
41jmethodID GetExitEmulationActivity() { 54jmethodID GetExitEmulationActivity() {
42 return s_exit_emulation_activity; 55 return s_exit_emulation_activity;
43} 56}
44 57
58jmethodID GetDiskCacheLoadProgress() {
59 return s_disk_cache_load_progress;
60}
61
45} // namespace IDCache 62} // namespace IDCache
46 63
47#ifdef __cplusplus 64#ifdef __cplusplus
@@ -58,8 +75,16 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
58 // Initialize Java classes 75 // Initialize Java classes
59 const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary"); 76 const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary");
60 s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class)); 77 s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class));
78 s_disk_cache_progress_class = reinterpret_cast<jclass>(env->NewGlobalRef(
79 env->FindClass("org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress")));
80 s_load_callback_stage_class = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass(
81 "org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage")));
82
83 // Initialize methods
61 s_exit_emulation_activity = 84 s_exit_emulation_activity =
62 env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V"); 85 env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V");
86 s_disk_cache_load_progress =
87 env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V");
63 88
64 // Initialize Android Storage 89 // Initialize Android Storage
65 Common::FS::Android::RegisterCallbacks(env, s_native_library_class); 90 Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
@@ -79,6 +104,8 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) {
79 // UnInitialize Android Storage 104 // UnInitialize Android Storage
80 Common::FS::Android::UnRegisterCallbacks(); 105 Common::FS::Android::UnRegisterCallbacks();
81 env->DeleteGlobalRef(s_native_library_class); 106 env->DeleteGlobalRef(s_native_library_class);
107 env->DeleteGlobalRef(s_disk_cache_progress_class);
108 env->DeleteGlobalRef(s_load_callback_stage_class);
82 109
83 // UnInitialze applets 110 // UnInitialze applets
84 SoftwareKeyboard::CleanupJNI(env); 111 SoftwareKeyboard::CleanupJNI(env);
diff --git a/src/android/app/src/main/jni/id_cache.h b/src/android/app/src/main/jni/id_cache.h
index 2fe07169d..9337cd254 100644
--- a/src/android/app/src/main/jni/id_cache.h
+++ b/src/android/app/src/main/jni/id_cache.h
@@ -2,10 +2,15 @@
2 2
3#include <jni.h> 3#include <jni.h>
4 4
5#include "video_core/rasterizer_interface.h"
6
5namespace IDCache { 7namespace IDCache {
6 8
7JNIEnv* GetEnvForThread(); 9JNIEnv* GetEnvForThread();
8jclass GetNativeLibraryClass(); 10jclass GetNativeLibraryClass();
11jclass GetDiskCacheProgressClass();
12jclass GetDiskCacheLoadCallbackStageClass();
9jmethodID GetExitEmulationActivity(); 13jmethodID GetExitEmulationActivity();
14jmethodID GetDiskCacheLoadProgress();
10 15
11} // namespace IDCache 16} // namespace IDCache
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 55736bce2..b10c55a45 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -51,6 +51,7 @@
51#include "jni/emu_window/emu_window.h" 51#include "jni/emu_window/emu_window.h"
52#include "jni/id_cache.h" 52#include "jni/id_cache.h"
53#include "video_core/rasterizer_interface.h" 53#include "video_core/rasterizer_interface.h"
54#include "video_core/renderer_base.h"
54 55
55namespace { 56namespace {
56 57
@@ -229,6 +230,15 @@ public:
229 m_is_running = true; 230 m_is_running = true;
230 } 231 }
231 232
233 // Load the disk shader cache.
234 if (Settings::values.use_disk_shader_cache.GetValue()) {
235 LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
236 m_system.Renderer().ReadRasterizer()->LoadDiskResources(
237 m_system.GetApplicationProcessProgramID(), std::stop_token{},
238 LoadDiskCacheProgress);
239 LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
240 }
241
232 void(m_system.Run()); 242 void(m_system.Run());
233 243
234 if (m_system.DebuggerEnabled()) { 244 if (m_system.DebuggerEnabled()) {
@@ -296,6 +306,14 @@ private:
296 } 306 }
297 307
298private: 308private:
309 static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max) {
310 JNIEnv* env = IDCache::GetEnvForThread();
311 env->CallStaticVoidMethod(IDCache::GetDiskCacheProgressClass(),
312 IDCache::GetDiskCacheLoadProgress(), static_cast<jint>(stage),
313 static_cast<jint>(progress), static_cast<jint>(max));
314 }
315
316private:
299 static EmulationSession s_instance; 317 static EmulationSession s_instance;
300 318
301 // Frontend management 319 // Frontend management
diff --git a/src/android/app/src/main/res/layout/dialog_progress_bar.xml b/src/android/app/src/main/res/layout/dialog_progress_bar.xml
index 1dbfd4f7b..d17711a65 100644
--- a/src/android/app/src/main/res/layout/dialog_progress_bar.xml
+++ b/src/android/app/src/main/res/layout/dialog_progress_bar.xml
@@ -12,4 +12,13 @@
12 android:layout_margin="24dp" 12 android:layout_margin="24dp"
13 app:trackCornerRadius="4dp" /> 13 app:trackCornerRadius="4dp" />
14 14
15 <TextView
16 android:id="@+id/progress_text"
17 android:layout_width="match_parent"
18 android:layout_height="wrap_content"
19 android:layout_marginLeft="24dp"
20 android:layout_marginRight="24dp"
21 android:layout_marginBottom="24dp"
22 android:gravity="end" />
23
15</LinearLayout> 24</LinearLayout>
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 70bff5749..45a9694d4 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -35,6 +35,8 @@
35 <string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously, which will reduce stutter but may introduce glitches.</string> 35 <string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously, which will reduce stutter but may introduce glitches.</string>
36 <string name="renderer_debug">Enable graphics debugging</string> 36 <string name="renderer_debug">Enable graphics debugging</string>
37 <string name="renderer_debug_description">When checked, the graphics API enters a slower debugging mode.</string> 37 <string name="renderer_debug_description">When checked, the graphics API enters a slower debugging mode.</string>
38 <string name="use_disk_shader_cache">Use disk shader cache</string>
39 <string name="use_disk_shader_cache_description">Reduce stuttering by storing and loading generated shaders to disk.</string>
38 40
39 <!-- Audio settings strings --> 41 <!-- Audio settings strings -->
40 <string name="audio_volume">Volume</string> 42 <string name="audio_volume">Volume</string>
@@ -45,6 +47,7 @@
45 <string name="ini_saved">Saved settings</string> 47 <string name="ini_saved">Saved settings</string>
46 <string name="gameid_saved">Saved settings for %1$s</string> 48 <string name="gameid_saved">Saved settings for %1$s</string>
47 <string name="error_saving">Error saving %1$s.ini: %2$s</string> 49 <string name="error_saving">Error saving %1$s.ini: %2$s</string>
50 <string name="loading">Loading...</string>
48 51
49 <!-- Game Grid Screen--> 52 <!-- Game Grid Screen-->
50 <string name="grid_menu_core_settings">Settings</string> 53 <string name="grid_menu_core_settings">Settings</string>
@@ -183,4 +186,8 @@
183 <string name="gamepad_home">Home</string> 186 <string name="gamepad_home">Home</string>
184 <string name="gamepad_screenshot">Screenshot</string> 187 <string name="gamepad_screenshot">Screenshot</string>
185 188
189 <!-- Disk shader cache -->
190 <string name="preparing_shaders">Preparing shaders</string>
191 <string name="building_shaders">Building shaders</string>
192
186</resources> 193</resources>