diff options
16 files changed, 125 insertions, 82 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 ed8fe6c3f..9ebd6c732 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 | |||
| @@ -252,7 +252,7 @@ object NativeLibrary { | |||
| 252 | 252 | ||
| 253 | external fun reloadKeys(): Boolean | 253 | external fun reloadKeys(): Boolean |
| 254 | 254 | ||
| 255 | external fun initializeSystem() | 255 | external fun initializeSystem(reload: Boolean) |
| 256 | 256 | ||
| 257 | external fun defaultCPUCore(): Int | 257 | external fun defaultCPUCore(): Int |
| 258 | 258 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt index 8c053670c..d114bd53d 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt | |||
| @@ -11,6 +11,7 @@ import java.io.File | |||
| 11 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization | 11 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization |
| 12 | import org.yuzu.yuzu_emu.utils.DocumentsTree | 12 | import org.yuzu.yuzu_emu.utils.DocumentsTree |
| 13 | import org.yuzu.yuzu_emu.utils.GpuDriverHelper | 13 | import org.yuzu.yuzu_emu.utils.GpuDriverHelper |
| 14 | import org.yuzu.yuzu_emu.utils.Log | ||
| 14 | 15 | ||
| 15 | fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir | 16 | fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir |
| 16 | 17 | ||
| @@ -49,6 +50,7 @@ class YuzuApplication : Application() { | |||
| 49 | DirectoryInitialization.start() | 50 | DirectoryInitialization.start() |
| 50 | GpuDriverHelper.initializeDriverParameters() | 51 | GpuDriverHelper.initializeDriverParameters() |
| 51 | NativeLibrary.logDeviceInfo() | 52 | NativeLibrary.logDeviceInfo() |
| 53 | Log.logDeviceInfo() | ||
| 52 | 54 | ||
| 53 | createNotificationChannels() | 55 | createNotificationChannels() |
| 54 | } | 56 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt index da98d4ef5..054e4b755 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt | |||
| @@ -107,7 +107,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 107 | 107 | ||
| 108 | val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | 108 | val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) |
| 109 | if (!preferences.getBoolean(Settings.PREF_MEMORY_WARNING_SHOWN, false)) { | 109 | if (!preferences.getBoolean(Settings.PREF_MEMORY_WARNING_SHOWN, false)) { |
| 110 | if (MemoryUtil.isLessThan(MemoryUtil.REQUIRED_MEMORY, MemoryUtil.Gb)) { | 110 | if (MemoryUtil.isLessThan(MemoryUtil.REQUIRED_MEMORY, MemoryUtil.totalMemory)) { |
| 111 | Toast.makeText( | 111 | Toast.makeText( |
| 112 | this, | 112 | this, |
| 113 | getString( | 113 | getString( |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt index 07bd78bf7..c456c0592 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt | |||
| @@ -312,6 +312,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 312 | ViewUtils.showView(binding.surfaceInputOverlay) | 312 | ViewUtils.showView(binding.surfaceInputOverlay) |
| 313 | ViewUtils.hideView(binding.loadingIndicator) | 313 | ViewUtils.hideView(binding.loadingIndicator) |
| 314 | 314 | ||
| 315 | emulationState.updateSurface() | ||
| 316 | |||
| 315 | // Setup overlay | 317 | // Setup overlay |
| 316 | updateShowFpsOverlay() | 318 | updateShowFpsOverlay() |
| 317 | } | 319 | } |
| @@ -805,6 +807,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 805 | } | 807 | } |
| 806 | 808 | ||
| 807 | @Synchronized | 809 | @Synchronized |
| 810 | fun updateSurface() { | ||
| 811 | if (surface != null) { | ||
| 812 | NativeLibrary.surfaceChanged(surface) | ||
| 813 | } | ||
| 814 | } | ||
| 815 | |||
| 816 | @Synchronized | ||
| 808 | fun clearSurface() { | 817 | fun clearSurface() { |
| 809 | if (surface == null) { | 818 | if (surface == null) { |
| 810 | Log.warning("[EmulationFragment] clearSurface called, but surface already null.") | 819 | Log.warning("[EmulationFragment] clearSurface called, but surface already null.") |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index ba1177426..211b7cf69 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt | |||
| @@ -403,7 +403,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 403 | } else { | 403 | } else { |
| 404 | firmwarePath.deleteRecursively() | 404 | firmwarePath.deleteRecursively() |
| 405 | cacheFirmwareDir.copyRecursively(firmwarePath, true) | 405 | cacheFirmwareDir.copyRecursively(firmwarePath, true) |
| 406 | NativeLibrary.initializeSystem() | 406 | NativeLibrary.initializeSystem(true) |
| 407 | getString(R.string.save_file_imported_success) | 407 | getString(R.string.save_file_imported_success) |
| 408 | } | 408 | } |
| 409 | } catch (e: Exception) { | 409 | } catch (e: Exception) { |
| @@ -649,7 +649,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 649 | } | 649 | } |
| 650 | 650 | ||
| 651 | // Reinitialize relevant data | 651 | // Reinitialize relevant data |
| 652 | NativeLibrary.initializeSystem() | 652 | NativeLibrary.initializeSystem(true) |
| 653 | gamesViewModel.reloadGames(false) | 653 | gamesViewModel.reloadGames(false) |
| 654 | 654 | ||
| 655 | return@newInstance getString(R.string.user_data_import_success) | 655 | return@newInstance getString(R.string.user_data_import_success) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt index 79a07f7ef..5e9a1176a 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt | |||
| @@ -15,7 +15,7 @@ object DirectoryInitialization { | |||
| 15 | fun start() { | 15 | fun start() { |
| 16 | if (!areDirectoriesReady) { | 16 | if (!areDirectoriesReady) { |
| 17 | initializeInternalStorage() | 17 | initializeInternalStorage() |
| 18 | NativeLibrary.initializeSystem() | 18 | NativeLibrary.initializeSystem(false) |
| 19 | areDirectoriesReady = true | 19 | areDirectoriesReady = true |
| 20 | } | 20 | } |
| 21 | } | 21 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/Log.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/Log.kt index fb682c344..aebe84b0f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/Log.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/Log.kt | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.utils | 4 | package org.yuzu.yuzu_emu.utils |
| 5 | 5 | ||
| 6 | import android.os.Build | ||
| 7 | |||
| 6 | object Log { | 8 | object Log { |
| 7 | // Tracks whether we should share the old log or the current log | 9 | // Tracks whether we should share the old log or the current log |
| 8 | var gameLaunched = false | 10 | var gameLaunched = false |
| @@ -16,4 +18,14 @@ object Log { | |||
| 16 | external fun error(message: String) | 18 | external fun error(message: String) |
| 17 | 19 | ||
| 18 | external fun critical(message: String) | 20 | external fun critical(message: String) |
| 21 | |||
| 22 | fun logDeviceInfo() { | ||
| 23 | info("Device Manufacturer - ${Build.MANUFACTURER}") | ||
| 24 | info("Device Model - ${Build.MODEL}") | ||
| 25 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) { | ||
| 26 | info("SoC Manufacturer - ${Build.SOC_MANUFACTURER}") | ||
| 27 | info("SoC Model - ${Build.SOC_MODEL}") | ||
| 28 | } | ||
| 29 | info("Total System Memory - ${MemoryUtil.getDeviceRAM()}") | ||
| 30 | } | ||
| 19 | } | 31 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt index aa4a5539a..9076a86c4 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt | |||
| @@ -27,7 +27,7 @@ object MemoryUtil { | |||
| 27 | const val Pb = Tb * 1024 | 27 | const val Pb = Tb * 1024 |
| 28 | const val Eb = Pb * 1024 | 28 | const val Eb = Pb * 1024 |
| 29 | 29 | ||
| 30 | private fun bytesToSizeUnit(size: Float): String = | 30 | private fun bytesToSizeUnit(size: Float, roundUp: Boolean = false): String = |
| 31 | when { | 31 | when { |
| 32 | size < Kb -> { | 32 | size < Kb -> { |
| 33 | context.getString( | 33 | context.getString( |
| @@ -39,63 +39,59 @@ object MemoryUtil { | |||
| 39 | size < Mb -> { | 39 | size < Mb -> { |
| 40 | context.getString( | 40 | context.getString( |
| 41 | R.string.memory_formatted, | 41 | R.string.memory_formatted, |
| 42 | (size / Kb).hundredths, | 42 | if (roundUp) ceil(size / Kb) else (size / Kb).hundredths, |
| 43 | context.getString(R.string.memory_kilobyte) | 43 | context.getString(R.string.memory_kilobyte) |
| 44 | ) | 44 | ) |
| 45 | } | 45 | } |
| 46 | size < Gb -> { | 46 | size < Gb -> { |
| 47 | context.getString( | 47 | context.getString( |
| 48 | R.string.memory_formatted, | 48 | R.string.memory_formatted, |
| 49 | (size / Mb).hundredths, | 49 | if (roundUp) ceil(size / Mb) else (size / Mb).hundredths, |
| 50 | context.getString(R.string.memory_megabyte) | 50 | context.getString(R.string.memory_megabyte) |
| 51 | ) | 51 | ) |
| 52 | } | 52 | } |
| 53 | size < Tb -> { | 53 | size < Tb -> { |
| 54 | context.getString( | 54 | context.getString( |
| 55 | R.string.memory_formatted, | 55 | R.string.memory_formatted, |
| 56 | (size / Gb).hundredths, | 56 | if (roundUp) ceil(size / Gb) else (size / Gb).hundredths, |
| 57 | context.getString(R.string.memory_gigabyte) | 57 | context.getString(R.string.memory_gigabyte) |
| 58 | ) | 58 | ) |
| 59 | } | 59 | } |
| 60 | size < Pb -> { | 60 | size < Pb -> { |
| 61 | context.getString( | 61 | context.getString( |
| 62 | R.string.memory_formatted, | 62 | R.string.memory_formatted, |
| 63 | (size / Tb).hundredths, | 63 | if (roundUp) ceil(size / Tb) else (size / Tb).hundredths, |
| 64 | context.getString(R.string.memory_terabyte) | 64 | context.getString(R.string.memory_terabyte) |
| 65 | ) | 65 | ) |
| 66 | } | 66 | } |
| 67 | size < Eb -> { | 67 | size < Eb -> { |
| 68 | context.getString( | 68 | context.getString( |
| 69 | R.string.memory_formatted, | 69 | R.string.memory_formatted, |
| 70 | (size / Pb).hundredths, | 70 | if (roundUp) ceil(size / Pb) else (size / Pb).hundredths, |
| 71 | context.getString(R.string.memory_petabyte) | 71 | context.getString(R.string.memory_petabyte) |
| 72 | ) | 72 | ) |
| 73 | } | 73 | } |
| 74 | else -> { | 74 | else -> { |
| 75 | context.getString( | 75 | context.getString( |
| 76 | R.string.memory_formatted, | 76 | R.string.memory_formatted, |
| 77 | (size / Eb).hundredths, | 77 | if (roundUp) ceil(size / Eb) else (size / Eb).hundredths, |
| 78 | context.getString(R.string.memory_exabyte) | 78 | context.getString(R.string.memory_exabyte) |
| 79 | ) | 79 | ) |
| 80 | } | 80 | } |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | // Devices are unlikely to have 0.5GB increments of memory so we'll just round up to account for | 83 | val totalMemory: Float |
| 84 | // the potential error created by memInfo.totalMem | ||
| 85 | private val totalMemory: Float | ||
| 86 | get() { | 84 | get() { |
| 87 | val memInfo = ActivityManager.MemoryInfo() | 85 | val memInfo = ActivityManager.MemoryInfo() |
| 88 | with(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager) { | 86 | with(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager) { |
| 89 | getMemoryInfo(memInfo) | 87 | getMemoryInfo(memInfo) |
| 90 | } | 88 | } |
| 91 | 89 | ||
| 92 | return ceil( | 90 | return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { |
| 93 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { | 91 | memInfo.advertisedMem.toFloat() |
| 94 | memInfo.advertisedMem.toFloat() | 92 | } else { |
| 95 | } else { | 93 | memInfo.totalMem.toFloat() |
| 96 | memInfo.totalMem.toFloat() | 94 | } |
| 97 | } | ||
| 98 | ) | ||
| 99 | } | 95 | } |
| 100 | 96 | ||
| 101 | fun isLessThan(minimum: Int, size: Float): Boolean = | 97 | fun isLessThan(minimum: Int, size: Float): Boolean = |
| @@ -109,5 +105,7 @@ object MemoryUtil { | |||
| 109 | else -> totalMemory < Kb && totalMemory < minimum | 105 | else -> totalMemory < Kb && totalMemory < minimum |
| 110 | } | 106 | } |
| 111 | 107 | ||
| 112 | fun getDeviceRAM(): String = bytesToSizeUnit(totalMemory) | 108 | // Devices are unlikely to have 0.5GB increments of memory so we'll just round up to account for |
| 109 | // the potential error created by memInfo.totalMem | ||
| 110 | fun getDeviceRAM(): String = bytesToSizeUnit(totalMemory, true) | ||
| 113 | } | 111 | } |
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 294e41045..46438906e 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp | |||
| @@ -247,11 +247,13 @@ void EmulationSession::ConfigureFilesystemProvider(const std::string& filepath) | |||
| 247 | } | 247 | } |
| 248 | } | 248 | } |
| 249 | 249 | ||
| 250 | void EmulationSession::InitializeSystem() { | 250 | void EmulationSession::InitializeSystem(bool reload) { |
| 251 | // Initialize logging system | 251 | if (!reload) { |
| 252 | Common::Log::Initialize(); | 252 | // Initialize logging system |
| 253 | Common::Log::SetColorConsoleBackendEnabled(true); | 253 | Common::Log::Initialize(); |
| 254 | Common::Log::Start(); | 254 | Common::Log::SetColorConsoleBackendEnabled(true); |
| 255 | Common::Log::Start(); | ||
| 256 | } | ||
| 255 | 257 | ||
| 256 | // Initialize filesystem. | 258 | // Initialize filesystem. |
| 257 | m_system.SetFilesystem(m_vfs); | 259 | m_system.SetFilesystem(m_vfs); |
| @@ -667,12 +669,15 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased(JNIEnv* env, jclass c | |||
| 667 | } | 669 | } |
| 668 | } | 670 | } |
| 669 | 671 | ||
| 670 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz) { | 672 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz, |
| 673 | jboolean reload) { | ||
| 671 | // Create the default config.ini. | 674 | // Create the default config.ini. |
| 672 | Config{}; | 675 | Config{}; |
| 673 | // Initialize the emulated system. | 676 | // Initialize the emulated system. |
| 674 | EmulationSession::GetInstance().System().Initialize(); | 677 | if (!reload) { |
| 675 | EmulationSession::GetInstance().InitializeSystem(); | 678 | EmulationSession::GetInstance().System().Initialize(); |
| 679 | } | ||
| 680 | EmulationSession::GetInstance().InitializeSystem(reload); | ||
| 676 | } | 681 | } |
| 677 | 682 | ||
| 678 | jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass clazz) { | 683 | jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass clazz) { |
diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h index 0aa2b085b..3b9596459 100644 --- a/src/android/app/src/main/jni/native.h +++ b/src/android/app/src/main/jni/native.h | |||
| @@ -43,7 +43,7 @@ public: | |||
| 43 | 43 | ||
| 44 | const Core::PerfStatsResults& PerfStats() const; | 44 | const Core::PerfStatsResults& PerfStats() const; |
| 45 | void ConfigureFilesystemProvider(const std::string& filepath); | 45 | void ConfigureFilesystemProvider(const std::string& filepath); |
| 46 | void InitializeSystem(); | 46 | void InitializeSystem(bool reload); |
| 47 | Core::SystemResultStatus InitializeEmulation(const std::string& filepath); | 47 | Core::SystemResultStatus InitializeEmulation(const std::string& filepath); |
| 48 | 48 | ||
| 49 | bool IsHandheldOnly(); | 49 | bool IsHandheldOnly(); |
diff --git a/src/common/arm64/native_clock.cpp b/src/common/arm64/native_clock.cpp index 88fdba527..f437d7187 100644 --- a/src/common/arm64/native_clock.cpp +++ b/src/common/arm64/native_clock.cpp | |||
| @@ -1,6 +1,9 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #ifdef ANDROID | ||
| 5 | #include <sys/system_properties.h> | ||
| 6 | #endif | ||
| 4 | #include "common/arm64/native_clock.h" | 7 | #include "common/arm64/native_clock.h" |
| 5 | 8 | ||
| 6 | namespace Common::Arm64 { | 9 | namespace Common::Arm64 { |
| @@ -65,7 +68,23 @@ bool NativeClock::IsNative() const { | |||
| 65 | 68 | ||
| 66 | u64 NativeClock::GetHostCNTFRQ() { | 69 | u64 NativeClock::GetHostCNTFRQ() { |
| 67 | u64 cntfrq_el0 = 0; | 70 | u64 cntfrq_el0 = 0; |
| 68 | asm("mrs %[cntfrq_el0], cntfrq_el0" : [cntfrq_el0] "=r"(cntfrq_el0)); | 71 | std::string_view board{""}; |
| 72 | #ifdef ANDROID | ||
| 73 | char buffer[PROP_VALUE_MAX]; | ||
| 74 | int len{__system_property_get("ro.product.board", buffer)}; | ||
| 75 | board = std::string_view(buffer, static_cast<size_t>(len)); | ||
| 76 | #endif | ||
| 77 | if (board == "s5e9925") { // Exynos 2200 | ||
| 78 | cntfrq_el0 = 25600000; | ||
| 79 | } else if (board == "exynos2100") { // Exynos 2100 | ||
| 80 | cntfrq_el0 = 26000000; | ||
| 81 | } else if (board == "exynos9810") { // Exynos 9810 | ||
| 82 | cntfrq_el0 = 26000000; | ||
| 83 | } else if (board == "s5e8825") { // Exynos 1280 | ||
| 84 | cntfrq_el0 = 26000000; | ||
| 85 | } else { | ||
| 86 | asm("mrs %[cntfrq_el0], cntfrq_el0" : [cntfrq_el0] "=r"(cntfrq_el0)); | ||
| 87 | } | ||
| 69 | return cntfrq_el0; | 88 | return cntfrq_el0; |
| 70 | } | 89 | } |
| 71 | 90 | ||
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index 85849d5f3..dd652ca42 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp | |||
| @@ -39,6 +39,18 @@ bool IsConnectionBased(Type type) { | |||
| 39 | } | 39 | } |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | template <typename T> | ||
| 43 | T GetValue(std::span<const u8> buffer) { | ||
| 44 | T t{}; | ||
| 45 | std::memcpy(&t, buffer.data(), std::min(sizeof(T), buffer.size())); | ||
| 46 | return t; | ||
| 47 | } | ||
| 48 | |||
| 49 | template <typename T> | ||
| 50 | void PutValue(std::span<u8> buffer, const T& t) { | ||
| 51 | std::memcpy(buffer.data(), &t, std::min(sizeof(T), buffer.size())); | ||
| 52 | } | ||
| 53 | |||
| 42 | } // Anonymous namespace | 54 | } // Anonymous namespace |
| 43 | 55 | ||
| 44 | void BSD::PollWork::Execute(BSD* bsd) { | 56 | void BSD::PollWork::Execute(BSD* bsd) { |
| @@ -316,22 +328,12 @@ void BSD::SetSockOpt(HLERequestContext& ctx) { | |||
| 316 | const s32 fd = rp.Pop<s32>(); | 328 | const s32 fd = rp.Pop<s32>(); |
| 317 | const u32 level = rp.Pop<u32>(); | 329 | const u32 level = rp.Pop<u32>(); |
| 318 | const OptName optname = static_cast<OptName>(rp.Pop<u32>()); | 330 | const OptName optname = static_cast<OptName>(rp.Pop<u32>()); |
| 319 | 331 | const auto optval = ctx.ReadBuffer(); | |
| 320 | const auto buffer = ctx.ReadBuffer(); | ||
| 321 | const u8* optval = buffer.empty() ? nullptr : buffer.data(); | ||
| 322 | size_t optlen = buffer.size(); | ||
| 323 | |||
| 324 | std::array<u64, 2> values; | ||
| 325 | if ((optname == OptName::SNDTIMEO || optname == OptName::RCVTIMEO) && buffer.size() == 8) { | ||
| 326 | std::memcpy(values.data(), buffer.data(), sizeof(values)); | ||
| 327 | optlen = sizeof(values); | ||
| 328 | optval = reinterpret_cast<const u8*>(values.data()); | ||
| 329 | } | ||
| 330 | 332 | ||
| 331 | LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} optlen={}", fd, level, | 333 | LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} optlen={}", fd, level, |
| 332 | static_cast<u32>(optname), optlen); | 334 | static_cast<u32>(optname), optval.size()); |
| 333 | 335 | ||
| 334 | BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optlen, optval)); | 336 | BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval)); |
| 335 | } | 337 | } |
| 336 | 338 | ||
| 337 | void BSD::Shutdown(HLERequestContext& ctx) { | 339 | void BSD::Shutdown(HLERequestContext& ctx) { |
| @@ -521,18 +523,19 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco | |||
| 521 | 523 | ||
| 522 | std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, | 524 | std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, |
| 523 | s32 nfds, s32 timeout) { | 525 | s32 nfds, s32 timeout) { |
| 524 | if (write_buffer.size() < nfds * sizeof(PollFD)) { | 526 | if (nfds <= 0) { |
| 525 | return {-1, Errno::INVAL}; | ||
| 526 | } | ||
| 527 | |||
| 528 | if (nfds == 0) { | ||
| 529 | // When no entries are provided, -1 is returned with errno zero | 527 | // When no entries are provided, -1 is returned with errno zero |
| 530 | return {-1, Errno::SUCCESS}; | 528 | return {-1, Errno::SUCCESS}; |
| 531 | } | 529 | } |
| 530 | if (read_buffer.size() < nfds * sizeof(PollFD)) { | ||
| 531 | return {-1, Errno::INVAL}; | ||
| 532 | } | ||
| 533 | if (write_buffer.size() < nfds * sizeof(PollFD)) { | ||
| 534 | return {-1, Errno::INVAL}; | ||
| 535 | } | ||
| 532 | 536 | ||
| 533 | const size_t length = std::min(read_buffer.size(), write_buffer.size()); | ||
| 534 | std::vector<PollFD> fds(nfds); | 537 | std::vector<PollFD> fds(nfds); |
| 535 | std::memcpy(fds.data(), read_buffer.data(), length); | 538 | std::memcpy(fds.data(), read_buffer.data(), nfds * sizeof(PollFD)); |
| 536 | 539 | ||
| 537 | if (timeout >= 0) { | 540 | if (timeout >= 0) { |
| 538 | const s64 seconds = timeout / 1000; | 541 | const s64 seconds = timeout / 1000; |
| @@ -580,7 +583,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<con | |||
| 580 | for (size_t i = 0; i < num; ++i) { | 583 | for (size_t i = 0; i < num; ++i) { |
| 581 | fds[i].revents = Translate(host_pollfds[i].revents); | 584 | fds[i].revents = Translate(host_pollfds[i].revents); |
| 582 | } | 585 | } |
| 583 | std::memcpy(write_buffer.data(), fds.data(), length); | 586 | std::memcpy(write_buffer.data(), fds.data(), nfds * sizeof(PollFD)); |
| 584 | 587 | ||
| 585 | return Translate(result); | 588 | return Translate(result); |
| 586 | } | 589 | } |
| @@ -608,8 +611,7 @@ std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) { | |||
| 608 | new_descriptor.is_connection_based = descriptor.is_connection_based; | 611 | new_descriptor.is_connection_based = descriptor.is_connection_based; |
| 609 | 612 | ||
| 610 | const SockAddrIn guest_addr_in = Translate(result.sockaddr_in); | 613 | const SockAddrIn guest_addr_in = Translate(result.sockaddr_in); |
| 611 | const size_t length = std::min(sizeof(guest_addr_in), write_buffer.size()); | 614 | PutValue(write_buffer, guest_addr_in); |
| 612 | std::memcpy(write_buffer.data(), &guest_addr_in, length); | ||
| 613 | 615 | ||
| 614 | return {new_fd, Errno::SUCCESS}; | 616 | return {new_fd, Errno::SUCCESS}; |
| 615 | } | 617 | } |
| @@ -619,8 +621,7 @@ Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) { | |||
| 619 | return Errno::BADF; | 621 | return Errno::BADF; |
| 620 | } | 622 | } |
| 621 | ASSERT(addr.size() == sizeof(SockAddrIn)); | 623 | ASSERT(addr.size() == sizeof(SockAddrIn)); |
| 622 | SockAddrIn addr_in; | 624 | auto addr_in = GetValue<SockAddrIn>(addr); |
| 623 | std::memcpy(&addr_in, addr.data(), sizeof(addr_in)); | ||
| 624 | 625 | ||
| 625 | return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in))); | 626 | return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in))); |
| 626 | } | 627 | } |
| @@ -631,8 +632,7 @@ Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) { | |||
| 631 | } | 632 | } |
| 632 | 633 | ||
| 633 | UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn)); | 634 | UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn)); |
| 634 | SockAddrIn addr_in; | 635 | auto addr_in = GetValue<SockAddrIn>(addr); |
| 635 | std::memcpy(&addr_in, addr.data(), sizeof(addr_in)); | ||
| 636 | 636 | ||
| 637 | return Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in))); | 637 | return Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in))); |
| 638 | } | 638 | } |
| @@ -650,7 +650,7 @@ Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) { | |||
| 650 | 650 | ||
| 651 | ASSERT(write_buffer.size() >= sizeof(guest_addrin)); | 651 | ASSERT(write_buffer.size() >= sizeof(guest_addrin)); |
| 652 | write_buffer.resize(sizeof(guest_addrin)); | 652 | write_buffer.resize(sizeof(guest_addrin)); |
| 653 | std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin)); | 653 | PutValue(write_buffer, guest_addrin); |
| 654 | return Translate(bsd_errno); | 654 | return Translate(bsd_errno); |
| 655 | } | 655 | } |
| 656 | 656 | ||
| @@ -667,7 +667,7 @@ Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) { | |||
| 667 | 667 | ||
| 668 | ASSERT(write_buffer.size() >= sizeof(guest_addrin)); | 668 | ASSERT(write_buffer.size() >= sizeof(guest_addrin)); |
| 669 | write_buffer.resize(sizeof(guest_addrin)); | 669 | write_buffer.resize(sizeof(guest_addrin)); |
| 670 | std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin)); | 670 | PutValue(write_buffer, guest_addrin); |
| 671 | return Translate(bsd_errno); | 671 | return Translate(bsd_errno); |
| 672 | } | 672 | } |
| 673 | 673 | ||
| @@ -725,7 +725,7 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& o | |||
| 725 | optval.size() == sizeof(Errno), { return Errno::INVAL; }, | 725 | optval.size() == sizeof(Errno), { return Errno::INVAL; }, |
| 726 | "Incorrect getsockopt option size"); | 726 | "Incorrect getsockopt option size"); |
| 727 | optval.resize(sizeof(Errno)); | 727 | optval.resize(sizeof(Errno)); |
| 728 | memcpy(optval.data(), &translated_pending_err, sizeof(Errno)); | 728 | PutValue(optval, translated_pending_err); |
| 729 | } | 729 | } |
| 730 | return Translate(getsockopt_err); | 730 | return Translate(getsockopt_err); |
| 731 | } | 731 | } |
| @@ -735,7 +735,7 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& o | |||
| 735 | } | 735 | } |
| 736 | } | 736 | } |
| 737 | 737 | ||
| 738 | Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval) { | 738 | Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval) { |
| 739 | if (!IsFileDescriptorValid(fd)) { | 739 | if (!IsFileDescriptorValid(fd)) { |
| 740 | return Errno::BADF; | 740 | return Errno::BADF; |
| 741 | } | 741 | } |
| @@ -748,17 +748,15 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, con | |||
| 748 | Network::SocketBase* const socket = file_descriptors[fd]->socket.get(); | 748 | Network::SocketBase* const socket = file_descriptors[fd]->socket.get(); |
| 749 | 749 | ||
| 750 | if (optname == OptName::LINGER) { | 750 | if (optname == OptName::LINGER) { |
| 751 | ASSERT(optlen == sizeof(Linger)); | 751 | ASSERT(optval.size() == sizeof(Linger)); |
| 752 | Linger linger; | 752 | auto linger = GetValue<Linger>(optval); |
| 753 | std::memcpy(&linger, optval, sizeof(linger)); | ||
| 754 | ASSERT(linger.onoff == 0 || linger.onoff == 1); | 753 | ASSERT(linger.onoff == 0 || linger.onoff == 1); |
| 755 | 754 | ||
| 756 | return Translate(socket->SetLinger(linger.onoff != 0, linger.linger)); | 755 | return Translate(socket->SetLinger(linger.onoff != 0, linger.linger)); |
| 757 | } | 756 | } |
| 758 | 757 | ||
| 759 | ASSERT(optlen == sizeof(u32)); | 758 | ASSERT(optval.size() == sizeof(u32)); |
| 760 | u32 value; | 759 | auto value = GetValue<u32>(optval); |
| 761 | std::memcpy(&value, optval, sizeof(value)); | ||
| 762 | 760 | ||
| 763 | switch (optname) { | 761 | switch (optname) { |
| 764 | case OptName::REUSEADDR: | 762 | case OptName::REUSEADDR: |
| @@ -862,7 +860,7 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess | |||
| 862 | } else { | 860 | } else { |
| 863 | ASSERT(addr.size() == sizeof(SockAddrIn)); | 861 | ASSERT(addr.size() == sizeof(SockAddrIn)); |
| 864 | const SockAddrIn result = Translate(addr_in); | 862 | const SockAddrIn result = Translate(addr_in); |
| 865 | std::memcpy(addr.data(), &result, sizeof(result)); | 863 | PutValue(addr, result); |
| 866 | } | 864 | } |
| 867 | } | 865 | } |
| 868 | 866 | ||
| @@ -886,8 +884,7 @@ std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> mes | |||
| 886 | Network::SockAddrIn* p_addr_in = nullptr; | 884 | Network::SockAddrIn* p_addr_in = nullptr; |
| 887 | if (!addr.empty()) { | 885 | if (!addr.empty()) { |
| 888 | ASSERT(addr.size() == sizeof(SockAddrIn)); | 886 | ASSERT(addr.size() == sizeof(SockAddrIn)); |
| 889 | SockAddrIn guest_addr_in; | 887 | auto guest_addr_in = GetValue<SockAddrIn>(addr); |
| 890 | std::memcpy(&guest_addr_in, addr.data(), sizeof(guest_addr_in)); | ||
| 891 | addr_in = Translate(guest_addr_in); | 888 | addr_in = Translate(guest_addr_in); |
| 892 | p_addr_in = &addr_in; | 889 | p_addr_in = &addr_in; |
| 893 | } | 890 | } |
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index 161f22b9b..4f69d382c 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h | |||
| @@ -163,7 +163,7 @@ private: | |||
| 163 | Errno ListenImpl(s32 fd, s32 backlog); | 163 | Errno ListenImpl(s32 fd, s32 backlog); |
| 164 | std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg); | 164 | std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg); |
| 165 | Errno GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval); | 165 | Errno GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval); |
| 166 | Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval); | 166 | Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval); |
| 167 | Errno ShutdownImpl(s32 fd, s32 how); | 167 | Errno ShutdownImpl(s32 fd, s32 how); |
| 168 | std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message); | 168 | std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message); |
| 169 | std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message, | 169 | std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message, |
diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index 3fe448f27..1434b1a56 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp | |||
| @@ -156,7 +156,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) { | |||
| 156 | // Ui General | 156 | // Ui General |
| 157 | INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", ""); | 157 | INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", ""); |
| 158 | INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", ""); | 158 | INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", ""); |
| 159 | INSERT(UISettings, confirm_before_closing, "Confirm exit while emulation is running", ""); | ||
| 160 | INSERT(UISettings, confirm_before_stopping, "Confirm before stopping emulation", ""); | 159 | INSERT(UISettings, confirm_before_stopping, "Confirm before stopping emulation", ""); |
| 161 | INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", ""); | 160 | INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", ""); |
| 162 | INSERT(UISettings, controller_applet_disabled, "Disable controller applet", ""); | 161 | INSERT(UISettings, controller_applet_disabled, "Disable controller applet", ""); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index db9da6dc8..91aba118a 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -2174,6 +2174,7 @@ void GMainWindow::ShutdownGame() { | |||
| 2174 | return; | 2174 | return; |
| 2175 | } | 2175 | } |
| 2176 | 2176 | ||
| 2177 | play_time_manager->Stop(); | ||
| 2177 | OnShutdownBegin(); | 2178 | OnShutdownBegin(); |
| 2178 | OnEmulationStopTimeExpired(); | 2179 | OnEmulationStopTimeExpired(); |
| 2179 | OnEmulationStopped(); | 2180 | OnEmulationStopped(); |
| @@ -3484,7 +3485,7 @@ void GMainWindow::OnExecuteProgram(std::size_t program_index) { | |||
| 3484 | } | 3485 | } |
| 3485 | 3486 | ||
| 3486 | void GMainWindow::OnExit() { | 3487 | void GMainWindow::OnExit() { |
| 3487 | OnStopGame(); | 3488 | ShutdownGame(); |
| 3488 | } | 3489 | } |
| 3489 | 3490 | ||
| 3490 | void GMainWindow::OnSaveConfig() { | 3491 | void GMainWindow::OnSaveConfig() { |
| @@ -4847,7 +4848,12 @@ bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installe | |||
| 4847 | } | 4848 | } |
| 4848 | 4849 | ||
| 4849 | bool GMainWindow::ConfirmClose() { | 4850 | bool GMainWindow::ConfirmClose() { |
| 4850 | if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) { | 4851 | if (emu_thread == nullptr || |
| 4852 | UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Never) { | ||
| 4853 | return true; | ||
| 4854 | } | ||
| 4855 | if (!system->GetExitLocked() && | ||
| 4856 | UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Based_On_Game) { | ||
| 4851 | return true; | 4857 | return true; |
| 4852 | } | 4858 | } |
| 4853 | const auto text = tr("Are you sure you want to close yuzu?"); | 4859 | const auto text = tr("Are you sure you want to close yuzu?"); |
| @@ -4952,7 +4958,7 @@ bool GMainWindow::ConfirmChangeGame() { | |||
| 4952 | } | 4958 | } |
| 4953 | 4959 | ||
| 4954 | bool GMainWindow::ConfirmForceLockedExit() { | 4960 | bool GMainWindow::ConfirmForceLockedExit() { |
| 4955 | if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) { | 4961 | if (emu_thread == nullptr) { |
| 4956 | return true; | 4962 | return true; |
| 4957 | } | 4963 | } |
| 4958 | const auto text = tr("The currently running application has requested yuzu to not exit.\n\n" | 4964 | const auto text = tr("The currently running application has requested yuzu to not exit.\n\n" |
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index b62ff620c..77d992c54 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h | |||
| @@ -93,10 +93,6 @@ struct Values { | |||
| 93 | Setting<bool> show_filter_bar{linkage, true, "showFilterBar", Category::Ui}; | 93 | Setting<bool> show_filter_bar{linkage, true, "showFilterBar", Category::Ui}; |
| 94 | Setting<bool> show_status_bar{linkage, true, "showStatusBar", Category::Ui}; | 94 | Setting<bool> show_status_bar{linkage, true, "showStatusBar", Category::Ui}; |
| 95 | 95 | ||
| 96 | Setting<bool> confirm_before_closing{ | ||
| 97 | linkage, true, "confirmClose", Category::UiGeneral, Settings::Specialization::Default, | ||
| 98 | true, true}; | ||
| 99 | |||
| 100 | SwitchableSetting<ConfirmStop> confirm_before_stopping{linkage, | 96 | SwitchableSetting<ConfirmStop> confirm_before_stopping{linkage, |
| 101 | ConfirmStop::Ask_Always, | 97 | ConfirmStop::Ask_Always, |
| 102 | "confirmStop", | 98 | "confirmStop", |