From 8fab363237083a8130a7b2a023cd9c5dd83f8f4f Mon Sep 17 00:00:00 2001
From: GPUCode <geoster3d@gmail.com>
Date: Sat, 18 Nov 2023 16:10:39 +0200
Subject: [PATCH] android: Add cpu bakend gui toggle

---
 .codespellrc                                           |  2 +-
 .../yuzu_emu/features/settings/model/IntSetting.kt     |  1 +
 .../features/settings/model/view/SettingsItem.kt       |  9 +++++++++
 .../features/settings/ui/SettingsFragmentPresenter.kt  |  1 +
 src/android/app/src/main/res/values/arrays.xml         | 10 ++++++++++
 src/android/app/src/main/res/values/strings.xml        |  5 +++++
 src/common/host_memory.cpp                             |  6 +++---
 src/common/settings.cpp                                |  8 +++++++-
 src/common/signal_chain.cpp                            |  2 +-
 src/core/loader/deconstructed_rom_directory.cpp        |  6 ++++--
 src/core/loader/nro.cpp                                |  2 +-
 11 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/.codespellrc b/.codespellrc
index 3336d31fec..9ff49898b8 100644
--- a/.codespellrc
+++ b/.codespellrc
@@ -3,4 +3,4 @@
 
 [codespell]
 skip = ./.git,./build,./dist,./Doxyfile,./externals,./LICENSES,./src/android/app/src/main/res
-ignore-words-list = aci,allright,ba,canonicalizations,deques,froms,hda,inout,lod,masia,nam,nax,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,vas,zink
+ignore-words-list = aci,allright,ba,canonicalizations,deques,froms,hda,inout,lod,masia,nam,nax,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,vas,zink,nce
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt
index 1513621243..ef10b209fd 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt
@@ -10,6 +10,7 @@ enum class IntSetting(
     override val category: Settings.Category,
     override val androidDefault: Int? = null
 ) : AbstractIntSetting {
+    CPU_BACKEND("cpu_backend", Settings.Category.Cpu),
     CPU_ACCURACY("cpu_accuracy", Settings.Category.Cpu),
     REGION_INDEX("region_index", Settings.Category.System),
     LANGUAGE_INDEX("language_index", Settings.Category.System),
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
index 6aba69dbee..1f090424b9 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
@@ -77,6 +77,15 @@ abstract class SettingsItem(
                     "%"
                 )
             )
+            put(
+                SingleChoiceSetting(
+                    IntSetting.CPU_BACKEND,
+                    R.string.cpu_backend,
+                    0,
+                    R.array.cpuBackendNames,
+                    R.array.cpuBackendValues
+                )
+            )
             put(
                 SingleChoiceSetting(
                     IntSetting.CPU_ACCURACY,
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 8b71e32f3d..7425728c60 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
@@ -269,6 +269,7 @@ class SettingsFragmentPresenter(
             add(BooleanSetting.RENDERER_DEBUG.key)
 
             add(HeaderSetting(R.string.cpu))
+            add(IntSetting.CPU_BACKEND.key)
             add(IntSetting.CPU_ACCURACY.key)
             add(BooleanSetting.CPU_DEBUG_MODE.key)
             add(SettingsItem.FASTMEM_COMBINED)
diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml
index 51bcc49a38..2756e5cc93 100644
--- a/src/android/app/src/main/res/values/arrays.xml
+++ b/src/android/app/src/main/res/values/arrays.xml
@@ -175,6 +175,16 @@
         <item>2</item>
     </integer-array>
 
+    <string-array name="cpuBackendNames">
+        <item>@string/cpu_backend_dynarmic</item>
+        <item>@string/cpu_backend_nce</item>
+    </string-array>
+
+    <integer-array name="cpuBackendValues">
+        <item>0</item>
+        <item>1</item>
+    </integer-array>
+
     <string-array name="cpuAccuracyNames">
         <item>@string/auto</item>
         <item>@string/cpu_accuracy_accurate</item>
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 471af87959..f07121f6a3 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -185,6 +185,7 @@
     <string name="frame_limit_enable_description">Limits emulation speed to a specified percentage of normal speed.</string>
     <string name="frame_limit_slider">Limit speed percent</string>
     <string name="frame_limit_slider_description">Specifies the percentage to limit emulation speed. 100% is the normal speed. Values higher or lower will increase or decrease the speed limit.</string>
+    <string name="cpu_backend">CPU Backend</string>
     <string name="cpu_accuracy">CPU accuracy</string>
     <string name="value_with_units">%1$s%2$s</string>
 
@@ -416,6 +417,10 @@
     <string name="ratio_force_sixteen_ten">Force 16:10</string>
     <string name="ratio_stretch">Stretch to window</string>
 
+    <!-- CPU Backend -->
+    <string name="cpu_backend_dynarmic">Dynarmic (Slow)</string>
+    <string name="cpu_backend_nce">Native code execution (NCE)</string>
+
     <!-- CPU Accuracy -->
     <string name="cpu_accuracy_accurate">Accurate</string>
     <string name="cpu_accuracy_unsafe">Unsafe</string>
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp
index 38d7b29f7f..8a869e5589 100644
--- a/src/common/host_memory.cpp
+++ b/src/common/host_memory.cpp
@@ -363,13 +363,13 @@ private:
 
 #ifdef ARCHITECTURE_arm64
 
-uint64_t GetRandomU64() {
+static uint64_t GetRandomU64() {
     uint64_t ret;
     ASSERT(getrandom(&ret, sizeof(ret), 0) == 0);
     return ret;
 }
 
-void* ChooseVirtualBase(size_t virtual_size) {
+static void* ChooseVirtualBase(size_t virtual_size) {
     constexpr uintptr_t Map39BitSize = (1ULL << 39);
     constexpr uintptr_t Map36BitSize = (1ULL << 36);
 
@@ -410,7 +410,7 @@ void* ChooseVirtualBase(size_t virtual_size) {
     return MAP_FAILED;
 }
 #else
-void* ChooseVirtualBase(size_t virtual_size) {
+static void* ChooseVirtualBase(size_t virtual_size) {
     return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE,
                 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
 }
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 81a036ef07..90e7475d70 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -159,7 +159,13 @@ bool IsFastmemEnabled() {
 static bool is_nce_enabled = false;
 
 void SetNceEnabled(bool is_39bit) {
-    is_nce_enabled = values.cpu_backend.GetValue() == CpuBackend::Nce && is_39bit;
+    const bool is_nce_selected = values.cpu_backend.GetValue() == CpuBackend::Nce;
+    is_nce_enabled = is_nce_selected && is_39bit;
+    if (is_nce_selected && !is_nce_enabled) {
+        LOG_WARNING(
+            Common,
+            "Program does not utilize 39-bit address space, unable to natively execute code");
+    }
 }
 
 bool IsNceEnabled() {
diff --git a/src/common/signal_chain.cpp b/src/common/signal_chain.cpp
index e0c6b9d4e3..2e4fecc482 100644
--- a/src/common/signal_chain.cpp
+++ b/src/common/signal_chain.cpp
@@ -18,7 +18,7 @@ T* LookupLibcSymbol(const char* name) {
         UNREACHABLE_MSG("Failed to open libc!");
     }
 #else
-    // For other operating environments, we assume the symbol is not overriden.
+    // For other operating environments, we assume the symbol is not overridden.
     const char* base = nullptr;
     Common::DynamicLibrary provider(base);
 #endif
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index e7fc8f438d..31c00f0a31 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -129,8 +129,10 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
     }
     metadata.Print();
 
-    // Enable NCE only for 64-bit programs.
-    Settings::SetNceEnabled(metadata.Is64BitProgram());
+    // Enable NCE only for programs with 39-bit address space.
+    const bool is_39bit =
+        metadata.GetAddressSpaceType() == FileSys::ProgramAddressSpaceType::Is39Bit;
+    Settings::SetNceEnabled(is_39bit);
 
     const std::array static_modules = {"rtld",    "main",    "subsdk0", "subsdk1", "subsdk2",
                                        "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7",
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 49cf903172..76ff380418 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -199,6 +199,7 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
 
     codeset.DataSegment().size += bss_size;
     program_image.resize(static_cast<u32>(program_image.size()) + bss_size);
+    size_t image_size = program_image.size();
 
 #ifdef ARCHITECTURE_arm64
     const auto& code = codeset.CodeSegment();
@@ -208,7 +209,6 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
 
     // Create NCE patcher
     Core::NCE::Patcher patch{};
-    size_t image_size = program_image.size();
 
     if (Settings::IsNceEnabled()) {
         // Patch SVCs and MRS calls in the guest code