diff options
Diffstat (limited to 'src')
109 files changed, 3131 insertions, 1499 deletions
diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index f763c657e..53aafa08c 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts | |||
| @@ -10,7 +10,7 @@ plugins { | |||
| 10 | id("com.android.application") | 10 | id("com.android.application") |
| 11 | id("org.jetbrains.kotlin.android") | 11 | id("org.jetbrains.kotlin.android") |
| 12 | id("kotlin-parcelize") | 12 | id("kotlin-parcelize") |
| 13 | kotlin("plugin.serialization") version "1.8.21" | 13 | kotlin("plugin.serialization") version "1.9.20" |
| 14 | id("androidx.navigation.safeargs.kotlin") | 14 | id("androidx.navigation.safeargs.kotlin") |
| 15 | id("org.jlleitschuh.gradle.ktlint") version "11.4.0" | 15 | id("org.jlleitschuh.gradle.ktlint") version "11.4.0" |
| 16 | } | 16 | } |
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 9b08f008d..93c8ce922 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 | |||
| @@ -49,6 +49,7 @@ import org.yuzu.yuzu_emu.utils.ForegroundService | |||
| 49 | import org.yuzu.yuzu_emu.utils.InputHandler | 49 | import org.yuzu.yuzu_emu.utils.InputHandler |
| 50 | import org.yuzu.yuzu_emu.utils.Log | 50 | import org.yuzu.yuzu_emu.utils.Log |
| 51 | import org.yuzu.yuzu_emu.utils.MemoryUtil | 51 | import org.yuzu.yuzu_emu.utils.MemoryUtil |
| 52 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 52 | import org.yuzu.yuzu_emu.utils.NfcReader | 53 | import org.yuzu.yuzu_emu.utils.NfcReader |
| 53 | import org.yuzu.yuzu_emu.utils.ThemeHelper | 54 | import org.yuzu.yuzu_emu.utils.ThemeHelper |
| 54 | import java.text.NumberFormat | 55 | import java.text.NumberFormat |
| @@ -170,6 +171,11 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 170 | stopMotionSensorListener() | 171 | stopMotionSensorListener() |
| 171 | } | 172 | } |
| 172 | 173 | ||
| 174 | override fun onStop() { | ||
| 175 | super.onStop() | ||
| 176 | NativeConfig.saveGlobalConfig() | ||
| 177 | } | ||
| 178 | |||
| 173 | override fun onUserLeaveHint() { | 179 | override fun onUserLeaveHint() { |
| 174 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { | 180 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { |
| 175 | if (BooleanSetting.PICTURE_IN_PICTURE.getBoolean() && !isInPictureInPictureMode) { | 181 | if (BooleanSetting.PICTURE_IN_PICTURE.getBoolean() && !isInPictureInPictureMode) { |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index 16f06cd0a..86bd33672 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt | |||
| @@ -18,7 +18,14 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { | |||
| 18 | RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"), | 18 | RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"), |
| 19 | RENDERER_DEBUG("debug"), | 19 | RENDERER_DEBUG("debug"), |
| 20 | PICTURE_IN_PICTURE("picture_in_picture"), | 20 | PICTURE_IN_PICTURE("picture_in_picture"), |
| 21 | USE_CUSTOM_RTC("custom_rtc_enabled"); | 21 | USE_CUSTOM_RTC("custom_rtc_enabled"), |
| 22 | BLACK_BACKGROUNDS("black_backgrounds"), | ||
| 23 | JOYSTICK_REL_CENTER("joystick_rel_center"), | ||
| 24 | DPAD_SLIDE("dpad_slide"), | ||
| 25 | HAPTIC_FEEDBACK("haptic_feedback"), | ||
| 26 | SHOW_PERFORMANCE_OVERLAY("show_performance_overlay"), | ||
| 27 | SHOW_INPUT_OVERLAY("show_input_overlay"), | ||
| 28 | TOUCHSCREEN("touchscreen"); | ||
| 22 | 29 | ||
| 23 | override fun getBoolean(needsGlobal: Boolean): Boolean = | 30 | override fun getBoolean(needsGlobal: Boolean): Boolean = |
| 24 | NativeConfig.getBoolean(key, needsGlobal) | 31 | NativeConfig.getBoolean(key, needsGlobal) |
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 df760440f..16fb87614 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 | |||
| @@ -19,7 +19,11 @@ enum class IntSetting(override val key: String) : AbstractIntSetting { | |||
| 19 | RENDERER_SCREEN_LAYOUT("screen_layout"), | 19 | RENDERER_SCREEN_LAYOUT("screen_layout"), |
| 20 | RENDERER_ASPECT_RATIO("aspect_ratio"), | 20 | RENDERER_ASPECT_RATIO("aspect_ratio"), |
| 21 | AUDIO_OUTPUT_ENGINE("output_engine"), | 21 | AUDIO_OUTPUT_ENGINE("output_engine"), |
| 22 | MAX_ANISOTROPY("max_anisotropy"); | 22 | MAX_ANISOTROPY("max_anisotropy"), |
| 23 | THEME("theme"), | ||
| 24 | THEME_MODE("theme_mode"), | ||
| 25 | OVERLAY_SCALE("control_scale"), | ||
| 26 | OVERLAY_OPACITY("control_opacity"); | ||
| 23 | 27 | ||
| 24 | override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal) | 28 | override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal) |
| 25 | 29 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt index 9551fc05e..43caac989 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt | |||
| @@ -15,18 +15,10 @@ object Settings { | |||
| 15 | SECTION_DEBUG(R.string.preferences_debug); | 15 | SECTION_DEBUG(R.string.preferences_debug); |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch" | ||
| 18 | const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown" | 19 | const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown" |
| 19 | 20 | ||
| 20 | const val PREF_OVERLAY_VERSION = "OverlayVersion" | 21 | // Deprecated input overlay preference keys |
| 21 | const val PREF_LANDSCAPE_OVERLAY_VERSION = "LandscapeOverlayVersion" | ||
| 22 | const val PREF_PORTRAIT_OVERLAY_VERSION = "PortraitOverlayVersion" | ||
| 23 | const val PREF_FOLDABLE_OVERLAY_VERSION = "FoldableOverlayVersion" | ||
| 24 | val overlayLayoutPrefs = listOf( | ||
| 25 | PREF_LANDSCAPE_OVERLAY_VERSION, | ||
| 26 | PREF_PORTRAIT_OVERLAY_VERSION, | ||
| 27 | PREF_FOLDABLE_OVERLAY_VERSION | ||
| 28 | ) | ||
| 29 | |||
| 30 | const val PREF_CONTROL_SCALE = "controlScale" | 22 | const val PREF_CONTROL_SCALE = "controlScale" |
| 31 | const val PREF_CONTROL_OPACITY = "controlOpacity" | 23 | const val PREF_CONTROL_OPACITY = "controlOpacity" |
| 32 | const val PREF_TOUCH_ENABLED = "isTouchEnabled" | 24 | const val PREF_TOUCH_ENABLED = "isTouchEnabled" |
| @@ -47,23 +39,12 @@ object Settings { | |||
| 47 | const val PREF_BUTTON_STICK_R = "buttonToggle14" | 39 | const val PREF_BUTTON_STICK_R = "buttonToggle14" |
| 48 | const val PREF_BUTTON_HOME = "buttonToggle15" | 40 | const val PREF_BUTTON_HOME = "buttonToggle15" |
| 49 | const val PREF_BUTTON_SCREENSHOT = "buttonToggle16" | 41 | const val PREF_BUTTON_SCREENSHOT = "buttonToggle16" |
| 50 | |||
| 51 | const val PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER = "EmulationMenuSettings_JoystickRelCenter" | 42 | const val PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER = "EmulationMenuSettings_JoystickRelCenter" |
| 52 | const val PREF_MENU_SETTINGS_DPAD_SLIDE = "EmulationMenuSettings_DpadSlideEnable" | 43 | const val PREF_MENU_SETTINGS_DPAD_SLIDE = "EmulationMenuSettings_DpadSlideEnable" |
| 53 | const val PREF_MENU_SETTINGS_HAPTICS = "EmulationMenuSettings_Haptics" | 44 | const val PREF_MENU_SETTINGS_HAPTICS = "EmulationMenuSettings_Haptics" |
| 54 | const val PREF_MENU_SETTINGS_SHOW_FPS = "EmulationMenuSettings_ShowFps" | 45 | const val PREF_MENU_SETTINGS_SHOW_FPS = "EmulationMenuSettings_ShowFps" |
| 55 | const val PREF_MENU_SETTINGS_SHOW_OVERLAY = "EmulationMenuSettings_ShowOverlay" | 46 | const val PREF_MENU_SETTINGS_SHOW_OVERLAY = "EmulationMenuSettings_ShowOverlay" |
| 56 | |||
| 57 | const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch" | ||
| 58 | const val PREF_THEME = "Theme" | ||
| 59 | const val PREF_THEME_MODE = "ThemeMode" | ||
| 60 | const val PREF_BLACK_BACKGROUNDS = "BlackBackgrounds" | ||
| 61 | |||
| 62 | val overlayPreferences = listOf( | 47 | val overlayPreferences = listOf( |
| 63 | PREF_OVERLAY_VERSION, | ||
| 64 | PREF_CONTROL_SCALE, | ||
| 65 | PREF_CONTROL_OPACITY, | ||
| 66 | PREF_TOUCH_ENABLED, | ||
| 67 | PREF_BUTTON_A, | 48 | PREF_BUTTON_A, |
| 68 | PREF_BUTTON_B, | 49 | PREF_BUTTON_B, |
| 69 | PREF_BUTTON_X, | 50 | PREF_BUTTON_X, |
| @@ -83,6 +64,21 @@ object Settings { | |||
| 83 | PREF_BUTTON_STICK_R | 64 | PREF_BUTTON_STICK_R |
| 84 | ) | 65 | ) |
| 85 | 66 | ||
| 67 | // Deprecated layout preference keys | ||
| 68 | const val PREF_LANDSCAPE_SUFFIX = "_Landscape" | ||
| 69 | const val PREF_PORTRAIT_SUFFIX = "_Portrait" | ||
| 70 | const val PREF_FOLDABLE_SUFFIX = "_Foldable" | ||
| 71 | val overlayLayoutSuffixes = listOf( | ||
| 72 | PREF_LANDSCAPE_SUFFIX, | ||
| 73 | PREF_PORTRAIT_SUFFIX, | ||
| 74 | PREF_FOLDABLE_SUFFIX | ||
| 75 | ) | ||
| 76 | |||
| 77 | // Deprecated theme preference keys | ||
| 78 | const val PREF_THEME = "Theme" | ||
| 79 | const val PREF_THEME_MODE = "ThemeMode" | ||
| 80 | const val PREF_BLACK_BACKGROUNDS = "BlackBackgrounds" | ||
| 81 | |||
| 86 | const val LayoutOption_Unspecified = 0 | 82 | const val LayoutOption_Unspecified = 0 |
| 87 | const val LayoutOption_MobilePortrait = 4 | 83 | const val LayoutOption_MobilePortrait = 4 |
| 88 | const val LayoutOption_MobileLandscape = 5 | 84 | const val LayoutOption_MobileLandscape = 5 |
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 db1a1076c..2ad2f4966 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 | |||
| @@ -3,10 +3,8 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.ui | 4 | package org.yuzu.yuzu_emu.features.settings.ui |
| 5 | 5 | ||
| 6 | import android.content.SharedPreferences | ||
| 7 | import android.os.Build | 6 | import android.os.Build |
| 8 | import android.widget.Toast | 7 | import android.widget.Toast |
| 9 | import androidx.preference.PreferenceManager | ||
| 10 | import org.yuzu.yuzu_emu.NativeLibrary | 8 | import org.yuzu.yuzu_emu.NativeLibrary |
| 11 | import org.yuzu.yuzu_emu.R | 9 | import org.yuzu.yuzu_emu.R |
| 12 | import org.yuzu.yuzu_emu.YuzuApplication | 10 | import org.yuzu.yuzu_emu.YuzuApplication |
| @@ -29,9 +27,6 @@ class SettingsFragmentPresenter( | |||
| 29 | ) { | 27 | ) { |
| 30 | private var settingsList = ArrayList<SettingsItem>() | 28 | private var settingsList = ArrayList<SettingsItem>() |
| 31 | 29 | ||
| 32 | private val preferences: SharedPreferences | ||
| 33 | get() = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||
| 34 | |||
| 35 | // Extension for altering settings list based on each setting's properties | 30 | // Extension for altering settings list based on each setting's properties |
| 36 | fun ArrayList<SettingsItem>.add(key: String) { | 31 | fun ArrayList<SettingsItem>.add(key: String) { |
| 37 | val item = SettingsItem.settingsItems[key]!! | 32 | val item = SettingsItem.settingsItems[key]!! |
| @@ -170,25 +165,19 @@ class SettingsFragmentPresenter( | |||
| 170 | private fun addThemeSettings(sl: ArrayList<SettingsItem>) { | 165 | private fun addThemeSettings(sl: ArrayList<SettingsItem>) { |
| 171 | sl.apply { | 166 | sl.apply { |
| 172 | val theme: AbstractIntSetting = object : AbstractIntSetting { | 167 | val theme: AbstractIntSetting = object : AbstractIntSetting { |
| 173 | override fun getInt(needsGlobal: Boolean): Int = | 168 | override fun getInt(needsGlobal: Boolean): Int = IntSetting.THEME.getInt() |
| 174 | preferences.getInt(Settings.PREF_THEME, 0) | ||
| 175 | |||
| 176 | override fun setInt(value: Int) { | 169 | override fun setInt(value: Int) { |
| 177 | preferences.edit() | 170 | IntSetting.THEME.setInt(value) |
| 178 | .putInt(Settings.PREF_THEME, value) | ||
| 179 | .apply() | ||
| 180 | settingsViewModel.setShouldRecreate(true) | 171 | settingsViewModel.setShouldRecreate(true) |
| 181 | } | 172 | } |
| 182 | 173 | ||
| 183 | override val key: String = Settings.PREF_THEME | 174 | override val key: String = IntSetting.THEME.key |
| 184 | override val isRuntimeModifiable: Boolean = false | 175 | override val isRuntimeModifiable: Boolean = IntSetting.THEME.isRuntimeModifiable |
| 185 | override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString() | 176 | override fun getValueAsString(needsGlobal: Boolean): String = |
| 186 | override val defaultValue: Int = 0 | 177 | IntSetting.THEME.getValueAsString() |
| 187 | override fun reset() { | 178 | |
| 188 | preferences.edit() | 179 | override val defaultValue: Int = IntSetting.THEME.defaultValue |
| 189 | .putInt(Settings.PREF_THEME, defaultValue) | 180 | override fun reset() = IntSetting.THEME.setInt(defaultValue) |
| 190 | .apply() | ||
| 191 | } | ||
| 192 | } | 181 | } |
| 193 | 182 | ||
| 194 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { | 183 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { |
| @@ -214,24 +203,22 @@ class SettingsFragmentPresenter( | |||
| 214 | } | 203 | } |
| 215 | 204 | ||
| 216 | val themeMode: AbstractIntSetting = object : AbstractIntSetting { | 205 | val themeMode: AbstractIntSetting = object : AbstractIntSetting { |
| 217 | override fun getInt(needsGlobal: Boolean): Int = | 206 | override fun getInt(needsGlobal: Boolean): Int = IntSetting.THEME_MODE.getInt() |
| 218 | preferences.getInt(Settings.PREF_THEME_MODE, -1) | ||
| 219 | |||
| 220 | override fun setInt(value: Int) { | 207 | override fun setInt(value: Int) { |
| 221 | preferences.edit() | 208 | IntSetting.THEME_MODE.setInt(value) |
| 222 | .putInt(Settings.PREF_THEME_MODE, value) | ||
| 223 | .apply() | ||
| 224 | settingsViewModel.setShouldRecreate(true) | 209 | settingsViewModel.setShouldRecreate(true) |
| 225 | } | 210 | } |
| 226 | 211 | ||
| 227 | override val key: String = Settings.PREF_THEME_MODE | 212 | override val key: String = IntSetting.THEME_MODE.key |
| 228 | override val isRuntimeModifiable: Boolean = false | 213 | override val isRuntimeModifiable: Boolean = |
| 229 | override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString() | 214 | IntSetting.THEME_MODE.isRuntimeModifiable |
| 230 | override val defaultValue: Int = -1 | 215 | |
| 216 | override fun getValueAsString(needsGlobal: Boolean): String = | ||
| 217 | IntSetting.THEME_MODE.getValueAsString() | ||
| 218 | |||
| 219 | override val defaultValue: Int = IntSetting.THEME_MODE.defaultValue | ||
| 231 | override fun reset() { | 220 | override fun reset() { |
| 232 | preferences.edit() | 221 | IntSetting.THEME_MODE.setInt(defaultValue) |
| 233 | .putInt(Settings.PREF_BLACK_BACKGROUNDS, defaultValue) | ||
| 234 | .apply() | ||
| 235 | settingsViewModel.setShouldRecreate(true) | 222 | settingsViewModel.setShouldRecreate(true) |
| 236 | } | 223 | } |
| 237 | } | 224 | } |
| @@ -248,25 +235,24 @@ class SettingsFragmentPresenter( | |||
| 248 | 235 | ||
| 249 | val blackBackgrounds: AbstractBooleanSetting = object : AbstractBooleanSetting { | 236 | val blackBackgrounds: AbstractBooleanSetting = object : AbstractBooleanSetting { |
| 250 | override fun getBoolean(needsGlobal: Boolean): Boolean = | 237 | override fun getBoolean(needsGlobal: Boolean): Boolean = |
| 251 | preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false) | 238 | BooleanSetting.BLACK_BACKGROUNDS.getBoolean() |
| 252 | 239 | ||
| 253 | override fun setBoolean(value: Boolean) { | 240 | override fun setBoolean(value: Boolean) { |
| 254 | preferences.edit() | 241 | BooleanSetting.BLACK_BACKGROUNDS.setBoolean(value) |
| 255 | .putBoolean(Settings.PREF_BLACK_BACKGROUNDS, value) | ||
| 256 | .apply() | ||
| 257 | settingsViewModel.setShouldRecreate(true) | 242 | settingsViewModel.setShouldRecreate(true) |
| 258 | } | 243 | } |
| 259 | 244 | ||
| 260 | override val key: String = Settings.PREF_BLACK_BACKGROUNDS | 245 | override val key: String = BooleanSetting.BLACK_BACKGROUNDS.key |
| 261 | override val isRuntimeModifiable: Boolean = false | 246 | override val isRuntimeModifiable: Boolean = |
| 247 | BooleanSetting.BLACK_BACKGROUNDS.isRuntimeModifiable | ||
| 248 | |||
| 262 | override fun getValueAsString(needsGlobal: Boolean): String = | 249 | override fun getValueAsString(needsGlobal: Boolean): String = |
| 263 | getBoolean().toString() | 250 | BooleanSetting.BLACK_BACKGROUNDS.getValueAsString() |
| 264 | 251 | ||
| 265 | override val defaultValue: Boolean = false | 252 | override val defaultValue: Boolean = BooleanSetting.BLACK_BACKGROUNDS.defaultValue |
| 266 | override fun reset() { | 253 | override fun reset() { |
| 267 | preferences.edit() | 254 | BooleanSetting.BLACK_BACKGROUNDS |
| 268 | .putBoolean(Settings.PREF_BLACK_BACKGROUNDS, defaultValue) | 255 | .setBoolean(BooleanSetting.BLACK_BACKGROUNDS.defaultValue) |
| 269 | .apply() | ||
| 270 | settingsViewModel.setShouldRecreate(true) | 256 | settingsViewModel.setShouldRecreate(true) |
| 271 | } | 257 | } |
| 272 | } | 258 | } |
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 d7b38f62d..510b2b5eb 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 | |||
| @@ -7,7 +7,6 @@ import android.annotation.SuppressLint | |||
| 7 | import android.app.AlertDialog | 7 | import android.app.AlertDialog |
| 8 | import android.content.Context | 8 | import android.content.Context |
| 9 | import android.content.DialogInterface | 9 | import android.content.DialogInterface |
| 10 | import android.content.SharedPreferences | ||
| 11 | import android.content.pm.ActivityInfo | 10 | import android.content.pm.ActivityInfo |
| 12 | import android.content.res.Configuration | 11 | import android.content.res.Configuration |
| 13 | import android.net.Uri | 12 | import android.net.Uri |
| @@ -33,7 +32,6 @@ import androidx.lifecycle.lifecycleScope | |||
| 33 | import androidx.lifecycle.repeatOnLifecycle | 32 | import androidx.lifecycle.repeatOnLifecycle |
| 34 | import androidx.navigation.findNavController | 33 | import androidx.navigation.findNavController |
| 35 | import androidx.navigation.fragment.navArgs | 34 | import androidx.navigation.fragment.navArgs |
| 36 | import androidx.preference.PreferenceManager | ||
| 37 | import androidx.window.layout.FoldingFeature | 35 | import androidx.window.layout.FoldingFeature |
| 38 | import androidx.window.layout.WindowInfoTracker | 36 | import androidx.window.layout.WindowInfoTracker |
| 39 | import androidx.window.layout.WindowLayoutInfo | 37 | import androidx.window.layout.WindowLayoutInfo |
| @@ -46,22 +44,22 @@ import kotlinx.coroutines.launch | |||
| 46 | import org.yuzu.yuzu_emu.HomeNavigationDirections | 44 | import org.yuzu.yuzu_emu.HomeNavigationDirections |
| 47 | import org.yuzu.yuzu_emu.NativeLibrary | 45 | import org.yuzu.yuzu_emu.NativeLibrary |
| 48 | import org.yuzu.yuzu_emu.R | 46 | import org.yuzu.yuzu_emu.R |
| 49 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 50 | import org.yuzu.yuzu_emu.activities.EmulationActivity | 47 | import org.yuzu.yuzu_emu.activities.EmulationActivity |
| 51 | import org.yuzu.yuzu_emu.databinding.DialogOverlayAdjustBinding | 48 | import org.yuzu.yuzu_emu.databinding.DialogOverlayAdjustBinding |
| 52 | import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding | 49 | import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding |
| 50 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting | ||
| 53 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting | 51 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting |
| 54 | import org.yuzu.yuzu_emu.features.settings.model.Settings | 52 | import org.yuzu.yuzu_emu.features.settings.model.Settings |
| 55 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile | 53 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile |
| 56 | import org.yuzu.yuzu_emu.model.DriverViewModel | 54 | import org.yuzu.yuzu_emu.model.DriverViewModel |
| 57 | import org.yuzu.yuzu_emu.model.Game | 55 | import org.yuzu.yuzu_emu.model.Game |
| 58 | import org.yuzu.yuzu_emu.model.EmulationViewModel | 56 | import org.yuzu.yuzu_emu.model.EmulationViewModel |
| 59 | import org.yuzu.yuzu_emu.overlay.InputOverlay | 57 | import org.yuzu.yuzu_emu.overlay.model.OverlayControl |
| 58 | import org.yuzu.yuzu_emu.overlay.model.OverlayLayout | ||
| 60 | import org.yuzu.yuzu_emu.utils.* | 59 | import org.yuzu.yuzu_emu.utils.* |
| 61 | import java.lang.NullPointerException | 60 | import java.lang.NullPointerException |
| 62 | 61 | ||
| 63 | class EmulationFragment : Fragment(), SurfaceHolder.Callback { | 62 | class EmulationFragment : Fragment(), SurfaceHolder.Callback { |
| 64 | private lateinit var preferences: SharedPreferences | ||
| 65 | private lateinit var emulationState: EmulationState | 63 | private lateinit var emulationState: EmulationState |
| 66 | private var emulationActivity: EmulationActivity? = null | 64 | private var emulationActivity: EmulationActivity? = null |
| 67 | private var perfStatsUpdater: (() -> Unit)? = null | 65 | private var perfStatsUpdater: (() -> Unit)? = null |
| @@ -141,7 +139,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 141 | 139 | ||
| 142 | // So this fragment doesn't restart on configuration changes; i.e. rotation. | 140 | // So this fragment doesn't restart on configuration changes; i.e. rotation. |
| 143 | retainInstance = true | 141 | retainInstance = true |
| 144 | preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||
| 145 | emulationState = EmulationState(game.path) | 142 | emulationState = EmulationState(game.path) |
| 146 | } | 143 | } |
| 147 | 144 | ||
| @@ -382,24 +379,25 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 382 | } | 379 | } |
| 383 | 380 | ||
| 384 | updateScreenLayout() | 381 | updateScreenLayout() |
| 382 | val showInputOverlay = BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean() | ||
| 385 | if (emulationActivity?.isInPictureInPictureMode == true) { | 383 | if (emulationActivity?.isInPictureInPictureMode == true) { |
| 386 | if (binding.drawerLayout.isOpen) { | 384 | if (binding.drawerLayout.isOpen) { |
| 387 | binding.drawerLayout.close() | 385 | binding.drawerLayout.close() |
| 388 | } | 386 | } |
| 389 | if (EmulationMenuSettings.showOverlay) { | 387 | if (showInputOverlay) { |
| 390 | binding.surfaceInputOverlay.visibility = View.INVISIBLE | 388 | binding.surfaceInputOverlay.visibility = View.INVISIBLE |
| 391 | } | 389 | } |
| 392 | } else { | 390 | } else { |
| 393 | if (EmulationMenuSettings.showOverlay && emulationViewModel.emulationStarted.value) { | 391 | if (showInputOverlay && emulationViewModel.emulationStarted.value) { |
| 394 | binding.surfaceInputOverlay.visibility = View.VISIBLE | 392 | binding.surfaceInputOverlay.visibility = View.VISIBLE |
| 395 | } else { | 393 | } else { |
| 396 | binding.surfaceInputOverlay.visibility = View.INVISIBLE | 394 | binding.surfaceInputOverlay.visibility = View.INVISIBLE |
| 397 | } | 395 | } |
| 398 | if (!isInFoldableLayout) { | 396 | if (!isInFoldableLayout) { |
| 399 | if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { | 397 | if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { |
| 400 | binding.surfaceInputOverlay.layout = InputOverlay.PORTRAIT | 398 | binding.surfaceInputOverlay.layout = OverlayLayout.Portrait |
| 401 | } else { | 399 | } else { |
| 402 | binding.surfaceInputOverlay.layout = InputOverlay.LANDSCAPE | 400 | binding.surfaceInputOverlay.layout = OverlayLayout.Landscape |
| 403 | } | 401 | } |
| 404 | } | 402 | } |
| 405 | } | 403 | } |
| @@ -423,17 +421,15 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 423 | } | 421 | } |
| 424 | 422 | ||
| 425 | private fun resetInputOverlay() { | 423 | private fun resetInputOverlay() { |
| 426 | preferences.edit() | 424 | IntSetting.OVERLAY_SCALE.reset() |
| 427 | .remove(Settings.PREF_CONTROL_SCALE) | 425 | IntSetting.OVERLAY_OPACITY.reset() |
| 428 | .remove(Settings.PREF_CONTROL_OPACITY) | ||
| 429 | .apply() | ||
| 430 | binding.surfaceInputOverlay.post { | 426 | binding.surfaceInputOverlay.post { |
| 431 | binding.surfaceInputOverlay.resetLayoutVisibilityAndPlacement() | 427 | binding.surfaceInputOverlay.resetLayoutVisibilityAndPlacement() |
| 432 | } | 428 | } |
| 433 | } | 429 | } |
| 434 | 430 | ||
| 435 | private fun updateShowFpsOverlay() { | 431 | private fun updateShowFpsOverlay() { |
| 436 | if (EmulationMenuSettings.showFps) { | 432 | if (BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()) { |
| 437 | val SYSTEM_FPS = 0 | 433 | val SYSTEM_FPS = 0 |
| 438 | val FPS = 1 | 434 | val FPS = 1 |
| 439 | val FRAMETIME = 2 | 435 | val FRAMETIME = 2 |
| @@ -496,7 +492,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 496 | binding.inGameMenu.layoutParams.height = it.bounds.bottom | 492 | binding.inGameMenu.layoutParams.height = it.bounds.bottom |
| 497 | 493 | ||
| 498 | isInFoldableLayout = true | 494 | isInFoldableLayout = true |
| 499 | binding.surfaceInputOverlay.layout = InputOverlay.FOLDABLE | 495 | binding.surfaceInputOverlay.layout = OverlayLayout.Foldable |
| 500 | } | 496 | } |
| 501 | } | 497 | } |
| 502 | it.isSeparating | 498 | it.isSeparating |
| @@ -535,18 +531,22 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 535 | popup.menuInflater.inflate(R.menu.menu_overlay_options, popup.menu) | 531 | popup.menuInflater.inflate(R.menu.menu_overlay_options, popup.menu) |
| 536 | 532 | ||
| 537 | popup.menu.apply { | 533 | popup.menu.apply { |
| 538 | findItem(R.id.menu_toggle_fps).isChecked = EmulationMenuSettings.showFps | 534 | findItem(R.id.menu_toggle_fps).isChecked = |
| 539 | findItem(R.id.menu_rel_stick_center).isChecked = EmulationMenuSettings.joystickRelCenter | 535 | BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean() |
| 540 | findItem(R.id.menu_dpad_slide).isChecked = EmulationMenuSettings.dpadSlide | 536 | findItem(R.id.menu_rel_stick_center).isChecked = |
| 541 | findItem(R.id.menu_show_overlay).isChecked = EmulationMenuSettings.showOverlay | 537 | BooleanSetting.JOYSTICK_REL_CENTER.getBoolean() |
| 542 | findItem(R.id.menu_haptics).isChecked = EmulationMenuSettings.hapticFeedback | 538 | findItem(R.id.menu_dpad_slide).isChecked = BooleanSetting.DPAD_SLIDE.getBoolean() |
| 539 | findItem(R.id.menu_show_overlay).isChecked = | ||
| 540 | BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean() | ||
| 541 | findItem(R.id.menu_haptics).isChecked = BooleanSetting.HAPTIC_FEEDBACK.getBoolean() | ||
| 542 | findItem(R.id.menu_touchscreen).isChecked = BooleanSetting.TOUCHSCREEN.getBoolean() | ||
| 543 | } | 543 | } |
| 544 | 544 | ||
| 545 | popup.setOnMenuItemClickListener { | 545 | popup.setOnMenuItemClickListener { |
| 546 | when (it.itemId) { | 546 | when (it.itemId) { |
| 547 | R.id.menu_toggle_fps -> { | 547 | R.id.menu_toggle_fps -> { |
| 548 | it.isChecked = !it.isChecked | 548 | it.isChecked = !it.isChecked |
| 549 | EmulationMenuSettings.showFps = it.isChecked | 549 | BooleanSetting.SHOW_PERFORMANCE_OVERLAY.setBoolean(it.isChecked) |
| 550 | updateShowFpsOverlay() | 550 | updateShowFpsOverlay() |
| 551 | true | 551 | true |
| 552 | } | 552 | } |
| @@ -564,11 +564,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 564 | } | 564 | } |
| 565 | 565 | ||
| 566 | R.id.menu_toggle_controls -> { | 566 | R.id.menu_toggle_controls -> { |
| 567 | val preferences = | 567 | val overlayControlData = NativeConfig.getOverlayControlData() |
| 568 | PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | 568 | val optionsArray = BooleanArray(overlayControlData.size) |
| 569 | val optionsArray = BooleanArray(Settings.overlayPreferences.size) | 569 | overlayControlData.forEachIndexed { i, _ -> |
| 570 | Settings.overlayPreferences.forEachIndexed { i, _ -> | 570 | optionsArray[i] = overlayControlData.firstOrNull { data -> |
| 571 | optionsArray[i] = preferences.getBoolean("buttonToggle$i", i < 15) | 571 | OverlayControl.entries[i].id == data.id |
| 572 | }?.enabled == true | ||
| 572 | } | 573 | } |
| 573 | 574 | ||
| 574 | val dialog = MaterialAlertDialogBuilder(requireContext()) | 575 | val dialog = MaterialAlertDialogBuilder(requireContext()) |
| @@ -577,11 +578,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 577 | R.array.gamepadButtons, | 578 | R.array.gamepadButtons, |
| 578 | optionsArray | 579 | optionsArray |
| 579 | ) { _, indexSelected, isChecked -> | 580 | ) { _, indexSelected, isChecked -> |
| 580 | preferences.edit() | 581 | overlayControlData.firstOrNull { data -> |
| 581 | .putBoolean("buttonToggle$indexSelected", isChecked) | 582 | OverlayControl.entries[indexSelected].id == data.id |
| 582 | .apply() | 583 | }?.enabled = isChecked |
| 583 | } | 584 | } |
| 584 | .setPositiveButton(android.R.string.ok) { _, _ -> | 585 | .setPositiveButton(android.R.string.ok) { _, _ -> |
| 586 | NativeConfig.setOverlayControlData(overlayControlData) | ||
| 587 | NativeConfig.saveGlobalConfig() | ||
| 585 | binding.surfaceInputOverlay.refreshControls() | 588 | binding.surfaceInputOverlay.refreshControls() |
| 586 | } | 589 | } |
| 587 | .setNegativeButton(android.R.string.cancel, null) | 590 | .setNegativeButton(android.R.string.cancel, null) |
| @@ -592,12 +595,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 592 | dialog.getButton(AlertDialog.BUTTON_NEUTRAL) | 595 | dialog.getButton(AlertDialog.BUTTON_NEUTRAL) |
| 593 | .setOnClickListener { | 596 | .setOnClickListener { |
| 594 | val isChecked = !optionsArray[0] | 597 | val isChecked = !optionsArray[0] |
| 595 | Settings.overlayPreferences.forEachIndexed { i, _ -> | 598 | overlayControlData.forEachIndexed { i, _ -> |
| 596 | optionsArray[i] = isChecked | 599 | optionsArray[i] = isChecked |
| 597 | dialog.listView.setItemChecked(i, isChecked) | 600 | dialog.listView.setItemChecked(i, isChecked) |
| 598 | preferences.edit() | 601 | overlayControlData[i].enabled = isChecked |
| 599 | .putBoolean("buttonToggle$i", isChecked) | ||
| 600 | .apply() | ||
| 601 | } | 602 | } |
| 602 | } | 603 | } |
| 603 | true | 604 | true |
| @@ -605,26 +606,32 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 605 | 606 | ||
| 606 | R.id.menu_show_overlay -> { | 607 | R.id.menu_show_overlay -> { |
| 607 | it.isChecked = !it.isChecked | 608 | it.isChecked = !it.isChecked |
| 608 | EmulationMenuSettings.showOverlay = it.isChecked | 609 | BooleanSetting.SHOW_INPUT_OVERLAY.setBoolean(it.isChecked) |
| 609 | binding.surfaceInputOverlay.refreshControls() | 610 | binding.surfaceInputOverlay.refreshControls() |
| 610 | true | 611 | true |
| 611 | } | 612 | } |
| 612 | 613 | ||
| 613 | R.id.menu_rel_stick_center -> { | 614 | R.id.menu_rel_stick_center -> { |
| 614 | it.isChecked = !it.isChecked | 615 | it.isChecked = !it.isChecked |
| 615 | EmulationMenuSettings.joystickRelCenter = it.isChecked | 616 | BooleanSetting.JOYSTICK_REL_CENTER.setBoolean(it.isChecked) |
| 616 | true | 617 | true |
| 617 | } | 618 | } |
| 618 | 619 | ||
| 619 | R.id.menu_dpad_slide -> { | 620 | R.id.menu_dpad_slide -> { |
| 620 | it.isChecked = !it.isChecked | 621 | it.isChecked = !it.isChecked |
| 621 | EmulationMenuSettings.dpadSlide = it.isChecked | 622 | BooleanSetting.DPAD_SLIDE.setBoolean(it.isChecked) |
| 622 | true | 623 | true |
| 623 | } | 624 | } |
| 624 | 625 | ||
| 625 | R.id.menu_haptics -> { | 626 | R.id.menu_haptics -> { |
| 626 | it.isChecked = !it.isChecked | 627 | it.isChecked = !it.isChecked |
| 627 | EmulationMenuSettings.hapticFeedback = it.isChecked | 628 | BooleanSetting.HAPTIC_FEEDBACK.setBoolean(it.isChecked) |
| 629 | true | ||
| 630 | } | ||
| 631 | |||
| 632 | R.id.menu_touchscreen -> { | ||
| 633 | it.isChecked = !it.isChecked | ||
| 634 | BooleanSetting.TOUCHSCREEN.setBoolean(it.isChecked) | ||
| 628 | true | 635 | true |
| 629 | } | 636 | } |
| 630 | 637 | ||
| @@ -667,6 +674,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 667 | it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED | 674 | it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED |
| 668 | } | 675 | } |
| 669 | } | 676 | } |
| 677 | NativeConfig.saveGlobalConfig() | ||
| 670 | } | 678 | } |
| 671 | 679 | ||
| 672 | @SuppressLint("SetTextI18n") | 680 | @SuppressLint("SetTextI18n") |
| @@ -675,7 +683,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 675 | adjustBinding.apply { | 683 | adjustBinding.apply { |
| 676 | inputScaleSlider.apply { | 684 | inputScaleSlider.apply { |
| 677 | valueTo = 150F | 685 | valueTo = 150F |
| 678 | value = preferences.getInt(Settings.PREF_CONTROL_SCALE, 50).toFloat() | 686 | value = IntSetting.OVERLAY_SCALE.getInt().toFloat() |
| 679 | addOnChangeListener( | 687 | addOnChangeListener( |
| 680 | Slider.OnChangeListener { _, value, _ -> | 688 | Slider.OnChangeListener { _, value, _ -> |
| 681 | inputScaleValue.text = "${value.toInt()}%" | 689 | inputScaleValue.text = "${value.toInt()}%" |
| @@ -685,7 +693,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 685 | } | 693 | } |
| 686 | inputOpacitySlider.apply { | 694 | inputOpacitySlider.apply { |
| 687 | valueTo = 100F | 695 | valueTo = 100F |
| 688 | value = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100).toFloat() | 696 | value = IntSetting.OVERLAY_OPACITY.getInt().toFloat() |
| 689 | addOnChangeListener( | 697 | addOnChangeListener( |
| 690 | Slider.OnChangeListener { _, value, _ -> | 698 | Slider.OnChangeListener { _, value, _ -> |
| 691 | inputOpacityValue.text = "${value.toInt()}%" | 699 | inputOpacityValue.text = "${value.toInt()}%" |
| @@ -709,16 +717,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 709 | } | 717 | } |
| 710 | 718 | ||
| 711 | private fun setControlScale(scale: Int) { | 719 | private fun setControlScale(scale: Int) { |
| 712 | preferences.edit() | 720 | IntSetting.OVERLAY_SCALE.setInt(scale) |
| 713 | .putInt(Settings.PREF_CONTROL_SCALE, scale) | ||
| 714 | .apply() | ||
| 715 | binding.surfaceInputOverlay.refreshControls() | 721 | binding.surfaceInputOverlay.refreshControls() |
| 716 | } | 722 | } |
| 717 | 723 | ||
| 718 | private fun setControlOpacity(opacity: Int) { | 724 | private fun setControlOpacity(opacity: Int) { |
| 719 | preferences.edit() | 725 | IntSetting.OVERLAY_OPACITY.setInt(opacity) |
| 720 | .putInt(Settings.PREF_CONTROL_OPACITY, opacity) | ||
| 721 | .apply() | ||
| 722 | binding.surfaceInputOverlay.refreshControls() | 726 | binding.surfaceInputOverlay.refreshControls() |
| 723 | } | 727 | } |
| 724 | 728 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt index a13faf3c7..bb69b8bd5 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt | |||
| @@ -21,7 +21,6 @@ import android.view.View | |||
| 21 | import android.view.View.OnTouchListener | 21 | import android.view.View.OnTouchListener |
| 22 | import android.view.WindowInsets | 22 | import android.view.WindowInsets |
| 23 | import androidx.core.content.ContextCompat | 23 | import androidx.core.content.ContextCompat |
| 24 | import androidx.preference.PreferenceManager | ||
| 25 | import androidx.window.layout.WindowMetricsCalculator | 24 | import androidx.window.layout.WindowMetricsCalculator |
| 26 | import kotlin.math.max | 25 | import kotlin.math.max |
| 27 | import kotlin.math.min | 26 | import kotlin.math.min |
| @@ -29,9 +28,13 @@ import org.yuzu.yuzu_emu.NativeLibrary | |||
| 29 | import org.yuzu.yuzu_emu.NativeLibrary.ButtonType | 28 | import org.yuzu.yuzu_emu.NativeLibrary.ButtonType |
| 30 | import org.yuzu.yuzu_emu.NativeLibrary.StickType | 29 | import org.yuzu.yuzu_emu.NativeLibrary.StickType |
| 31 | import org.yuzu.yuzu_emu.R | 30 | import org.yuzu.yuzu_emu.R |
| 32 | import org.yuzu.yuzu_emu.YuzuApplication | 31 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting |
| 32 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting | ||
| 33 | import org.yuzu.yuzu_emu.features.settings.model.Settings | 33 | import org.yuzu.yuzu_emu.features.settings.model.Settings |
| 34 | import org.yuzu.yuzu_emu.utils.EmulationMenuSettings | 34 | import org.yuzu.yuzu_emu.overlay.model.OverlayControl |
| 35 | import org.yuzu.yuzu_emu.overlay.model.OverlayControlData | ||
| 36 | import org.yuzu.yuzu_emu.overlay.model.OverlayLayout | ||
| 37 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 35 | 38 | ||
| 36 | /** | 39 | /** |
| 37 | * Draws the interactive input overlay on top of the | 40 | * Draws the interactive input overlay on top of the |
| @@ -51,23 +54,18 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 51 | 54 | ||
| 52 | private lateinit var windowInsets: WindowInsets | 55 | private lateinit var windowInsets: WindowInsets |
| 53 | 56 | ||
| 54 | var layout = LANDSCAPE | 57 | var layout = OverlayLayout.Landscape |
| 55 | 58 | ||
| 56 | override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { | 59 | override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { |
| 57 | super.onLayout(changed, left, top, right, bottom) | 60 | super.onLayout(changed, left, top, right, bottom) |
| 58 | 61 | ||
| 59 | windowInsets = rootWindowInsets | 62 | windowInsets = rootWindowInsets |
| 60 | 63 | ||
| 61 | val overlayVersion = preferences.getInt(Settings.PREF_OVERLAY_VERSION, 0) | 64 | val overlayControlData = NativeConfig.getOverlayControlData() |
| 62 | if (overlayVersion != OVERLAY_VERSION) { | 65 | if (overlayControlData.isEmpty()) { |
| 63 | resetAllLayouts() | 66 | populateDefaultConfig() |
| 64 | } else { | 67 | } else { |
| 65 | val layoutIndex = overlayLayouts.indexOf(layout) | 68 | checkForNewControls(overlayControlData) |
| 66 | val currentLayoutVersion = | ||
| 67 | preferences.getInt(Settings.overlayLayoutPrefs[layoutIndex], 0) | ||
| 68 | if (currentLayoutVersion != overlayLayoutVersions[layoutIndex]) { | ||
| 69 | resetCurrentLayout() | ||
| 70 | } | ||
| 71 | } | 69 | } |
| 72 | 70 | ||
| 73 | // Load the controls. | 71 | // Load the controls. |
| @@ -123,7 +121,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 123 | } | 121 | } |
| 124 | 122 | ||
| 125 | for (dpad in overlayDpads) { | 123 | for (dpad in overlayDpads) { |
| 126 | if (!dpad.updateStatus(event, EmulationMenuSettings.dpadSlide)) { | 124 | if (!dpad.updateStatus(event, BooleanSetting.DPAD_SLIDE.getBoolean())) { |
| 127 | continue | 125 | continue |
| 128 | } | 126 | } |
| 129 | NativeLibrary.onGamePadButtonEvent( | 127 | NativeLibrary.onGamePadButtonEvent( |
| @@ -174,7 +172,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 174 | invalidate() | 172 | invalidate() |
| 175 | } | 173 | } |
| 176 | 174 | ||
| 177 | if (!preferences.getBoolean(Settings.PREF_TOUCH_ENABLED, true)) { | 175 | if (!BooleanSetting.TOUCHSCREEN.getBoolean()) { |
| 178 | return true | 176 | return true |
| 179 | } | 177 | } |
| 180 | 178 | ||
| @@ -211,7 +209,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 211 | } | 209 | } |
| 212 | 210 | ||
| 213 | private fun playHaptics(event: MotionEvent) { | 211 | private fun playHaptics(event: MotionEvent) { |
| 214 | if (EmulationMenuSettings.hapticFeedback) { | 212 | if (BooleanSetting.HAPTIC_FEEDBACK.getBoolean()) { |
| 215 | when (event.actionMasked) { | 213 | when (event.actionMasked) { |
| 216 | MotionEvent.ACTION_DOWN, | 214 | MotionEvent.ACTION_DOWN, |
| 217 | MotionEvent.ACTION_POINTER_DOWN -> | 215 | MotionEvent.ACTION_POINTER_DOWN -> |
| @@ -255,10 +253,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 255 | MotionEvent.ACTION_POINTER_DOWN -> | 253 | MotionEvent.ACTION_POINTER_DOWN -> |
| 256 | // If no button is being moved now, remember the currently touched button to move. | 254 | // If no button is being moved now, remember the currently touched button to move. |
| 257 | if (buttonBeingConfigured == null && | 255 | if (buttonBeingConfigured == null && |
| 258 | button.bounds.contains( | 256 | button.bounds.contains(fingerPositionX, fingerPositionY) |
| 259 | fingerPositionX, | ||
| 260 | fingerPositionY | ||
| 261 | ) | ||
| 262 | ) { | 257 | ) { |
| 263 | buttonBeingConfigured = button | 258 | buttonBeingConfigured = button |
| 264 | buttonBeingConfigured!!.onConfigureTouch(event) | 259 | buttonBeingConfigured!!.onConfigureTouch(event) |
| @@ -274,7 +269,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 274 | MotionEvent.ACTION_POINTER_UP -> if (buttonBeingConfigured === button) { | 269 | MotionEvent.ACTION_POINTER_UP -> if (buttonBeingConfigured === button) { |
| 275 | // Persist button position by saving new place. | 270 | // Persist button position by saving new place. |
| 276 | saveControlPosition( | 271 | saveControlPosition( |
| 277 | buttonBeingConfigured!!.prefId, | 272 | buttonBeingConfigured!!.overlayControlData.id, |
| 278 | buttonBeingConfigured!!.bounds.centerX(), | 273 | buttonBeingConfigured!!.bounds.centerX(), |
| 279 | buttonBeingConfigured!!.bounds.centerY(), | 274 | buttonBeingConfigured!!.bounds.centerY(), |
| 280 | layout | 275 | layout |
| @@ -321,10 +316,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 321 | when (event.action) { | 316 | when (event.action) { |
| 322 | MotionEvent.ACTION_DOWN, | 317 | MotionEvent.ACTION_DOWN, |
| 323 | MotionEvent.ACTION_POINTER_DOWN -> if (joystickBeingConfigured == null && | 318 | MotionEvent.ACTION_POINTER_DOWN -> if (joystickBeingConfigured == null && |
| 324 | joystick.bounds.contains( | 319 | joystick.bounds.contains(fingerPositionX, fingerPositionY) |
| 325 | fingerPositionX, | ||
| 326 | fingerPositionY | ||
| 327 | ) | ||
| 328 | ) { | 320 | ) { |
| 329 | joystickBeingConfigured = joystick | 321 | joystickBeingConfigured = joystick |
| 330 | joystickBeingConfigured!!.onConfigureTouch(event) | 322 | joystickBeingConfigured!!.onConfigureTouch(event) |
| @@ -351,231 +343,257 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 351 | return true | 343 | return true |
| 352 | } | 344 | } |
| 353 | 345 | ||
| 354 | private fun addOverlayControls(layout: String) { | 346 | private fun addOverlayControls(layout: OverlayLayout) { |
| 355 | val windowSize = getSafeScreenSize(context, Pair(measuredWidth, measuredHeight)) | 347 | val windowSize = getSafeScreenSize(context, Pair(measuredWidth, measuredHeight)) |
| 356 | if (preferences.getBoolean(Settings.PREF_BUTTON_A, true)) { | 348 | val overlayControlData = NativeConfig.getOverlayControlData() |
| 357 | overlayButtons.add( | 349 | for (data in overlayControlData) { |
| 358 | initializeOverlayButton( | 350 | if (!data.enabled) { |
| 359 | context, | 351 | continue |
| 360 | windowSize, | 352 | } |
| 361 | R.drawable.facebutton_a, | 353 | |
| 362 | R.drawable.facebutton_a_depressed, | 354 | val position = data.positionFromLayout(layout) |
| 363 | ButtonType.BUTTON_A, | 355 | when (data.id) { |
| 364 | Settings.PREF_BUTTON_A, | 356 | OverlayControl.BUTTON_A.id -> { |
| 365 | layout | 357 | overlayButtons.add( |
| 366 | ) | 358 | initializeOverlayButton( |
| 367 | ) | 359 | context, |
| 368 | } | 360 | windowSize, |
| 369 | if (preferences.getBoolean(Settings.PREF_BUTTON_B, true)) { | 361 | R.drawable.facebutton_a, |
| 370 | overlayButtons.add( | 362 | R.drawable.facebutton_a_depressed, |
| 371 | initializeOverlayButton( | 363 | ButtonType.BUTTON_A, |
| 372 | context, | 364 | data, |
| 373 | windowSize, | 365 | position |
| 374 | R.drawable.facebutton_b, | 366 | ) |
| 375 | R.drawable.facebutton_b_depressed, | 367 | ) |
| 376 | ButtonType.BUTTON_B, | 368 | } |
| 377 | Settings.PREF_BUTTON_B, | 369 | |
| 378 | layout | 370 | OverlayControl.BUTTON_B.id -> { |
| 379 | ) | 371 | overlayButtons.add( |
| 380 | ) | 372 | initializeOverlayButton( |
| 381 | } | 373 | context, |
| 382 | if (preferences.getBoolean(Settings.PREF_BUTTON_X, true)) { | 374 | windowSize, |
| 383 | overlayButtons.add( | 375 | R.drawable.facebutton_b, |
| 384 | initializeOverlayButton( | 376 | R.drawable.facebutton_b_depressed, |
| 385 | context, | 377 | ButtonType.BUTTON_B, |
| 386 | windowSize, | 378 | data, |
| 387 | R.drawable.facebutton_x, | 379 | position |
| 388 | R.drawable.facebutton_x_depressed, | 380 | ) |
| 389 | ButtonType.BUTTON_X, | 381 | ) |
| 390 | Settings.PREF_BUTTON_X, | 382 | } |
| 391 | layout | 383 | |
| 392 | ) | 384 | OverlayControl.BUTTON_X.id -> { |
| 393 | ) | 385 | overlayButtons.add( |
| 394 | } | 386 | initializeOverlayButton( |
| 395 | if (preferences.getBoolean(Settings.PREF_BUTTON_Y, true)) { | 387 | context, |
| 396 | overlayButtons.add( | 388 | windowSize, |
| 397 | initializeOverlayButton( | 389 | R.drawable.facebutton_x, |
| 398 | context, | 390 | R.drawable.facebutton_x_depressed, |
| 399 | windowSize, | 391 | ButtonType.BUTTON_X, |
| 400 | R.drawable.facebutton_y, | 392 | data, |
| 401 | R.drawable.facebutton_y_depressed, | 393 | position |
| 402 | ButtonType.BUTTON_Y, | 394 | ) |
| 403 | Settings.PREF_BUTTON_Y, | 395 | ) |
| 404 | layout | 396 | } |
| 405 | ) | 397 | |
| 406 | ) | 398 | OverlayControl.BUTTON_Y.id -> { |
| 407 | } | 399 | overlayButtons.add( |
| 408 | if (preferences.getBoolean(Settings.PREF_BUTTON_L, true)) { | 400 | initializeOverlayButton( |
| 409 | overlayButtons.add( | 401 | context, |
| 410 | initializeOverlayButton( | 402 | windowSize, |
| 411 | context, | 403 | R.drawable.facebutton_y, |
| 412 | windowSize, | 404 | R.drawable.facebutton_y_depressed, |
| 413 | R.drawable.l_shoulder, | 405 | ButtonType.BUTTON_Y, |
| 414 | R.drawable.l_shoulder_depressed, | 406 | data, |
| 415 | ButtonType.TRIGGER_L, | 407 | position |
| 416 | Settings.PREF_BUTTON_L, | 408 | ) |
| 417 | layout | 409 | ) |
| 418 | ) | 410 | } |
| 419 | ) | 411 | |
| 420 | } | 412 | OverlayControl.BUTTON_PLUS.id -> { |
| 421 | if (preferences.getBoolean(Settings.PREF_BUTTON_R, true)) { | 413 | overlayButtons.add( |
| 422 | overlayButtons.add( | 414 | initializeOverlayButton( |
| 423 | initializeOverlayButton( | 415 | context, |
| 424 | context, | 416 | windowSize, |
| 425 | windowSize, | 417 | R.drawable.facebutton_plus, |
| 426 | R.drawable.r_shoulder, | 418 | R.drawable.facebutton_plus_depressed, |
| 427 | R.drawable.r_shoulder_depressed, | 419 | ButtonType.BUTTON_PLUS, |
| 428 | ButtonType.TRIGGER_R, | 420 | data, |
| 429 | Settings.PREF_BUTTON_R, | 421 | position |
| 430 | layout | 422 | ) |
| 431 | ) | 423 | ) |
| 432 | ) | 424 | } |
| 433 | } | 425 | |
| 434 | if (preferences.getBoolean(Settings.PREF_BUTTON_ZL, true)) { | 426 | OverlayControl.BUTTON_MINUS.id -> { |
| 435 | overlayButtons.add( | 427 | overlayButtons.add( |
| 436 | initializeOverlayButton( | 428 | initializeOverlayButton( |
| 437 | context, | 429 | context, |
| 438 | windowSize, | 430 | windowSize, |
| 439 | R.drawable.zl_trigger, | 431 | R.drawable.facebutton_minus, |
| 440 | R.drawable.zl_trigger_depressed, | 432 | R.drawable.facebutton_minus_depressed, |
| 441 | ButtonType.TRIGGER_ZL, | 433 | ButtonType.BUTTON_MINUS, |
| 442 | Settings.PREF_BUTTON_ZL, | 434 | data, |
| 443 | layout | 435 | position |
| 444 | ) | 436 | ) |
| 445 | ) | 437 | ) |
| 446 | } | 438 | } |
| 447 | if (preferences.getBoolean(Settings.PREF_BUTTON_ZR, true)) { | 439 | |
| 448 | overlayButtons.add( | 440 | OverlayControl.BUTTON_HOME.id -> { |
| 449 | initializeOverlayButton( | 441 | overlayButtons.add( |
| 450 | context, | 442 | initializeOverlayButton( |
| 451 | windowSize, | 443 | context, |
| 452 | R.drawable.zr_trigger, | 444 | windowSize, |
| 453 | R.drawable.zr_trigger_depressed, | 445 | R.drawable.facebutton_home, |
| 454 | ButtonType.TRIGGER_ZR, | 446 | R.drawable.facebutton_home_depressed, |
| 455 | Settings.PREF_BUTTON_ZR, | 447 | ButtonType.BUTTON_HOME, |
| 456 | layout | 448 | data, |
| 457 | ) | 449 | position |
| 458 | ) | 450 | ) |
| 459 | } | 451 | ) |
| 460 | if (preferences.getBoolean(Settings.PREF_BUTTON_PLUS, true)) { | 452 | } |
| 461 | overlayButtons.add( | 453 | |
| 462 | initializeOverlayButton( | 454 | OverlayControl.BUTTON_CAPTURE.id -> { |
| 463 | context, | 455 | overlayButtons.add( |
| 464 | windowSize, | 456 | initializeOverlayButton( |
| 465 | R.drawable.facebutton_plus, | 457 | context, |
| 466 | R.drawable.facebutton_plus_depressed, | 458 | windowSize, |
| 467 | ButtonType.BUTTON_PLUS, | 459 | R.drawable.facebutton_screenshot, |
| 468 | Settings.PREF_BUTTON_PLUS, | 460 | R.drawable.facebutton_screenshot_depressed, |
| 469 | layout | 461 | ButtonType.BUTTON_CAPTURE, |
| 470 | ) | 462 | data, |
| 471 | ) | 463 | position |
| 472 | } | 464 | ) |
| 473 | if (preferences.getBoolean(Settings.PREF_BUTTON_MINUS, true)) { | 465 | ) |
| 474 | overlayButtons.add( | 466 | } |
| 475 | initializeOverlayButton( | 467 | |
| 476 | context, | 468 | OverlayControl.BUTTON_L.id -> { |
| 477 | windowSize, | 469 | overlayButtons.add( |
| 478 | R.drawable.facebutton_minus, | 470 | initializeOverlayButton( |
| 479 | R.drawable.facebutton_minus_depressed, | 471 | context, |
| 480 | ButtonType.BUTTON_MINUS, | 472 | windowSize, |
| 481 | Settings.PREF_BUTTON_MINUS, | 473 | R.drawable.l_shoulder, |
| 482 | layout | 474 | R.drawable.l_shoulder_depressed, |
| 483 | ) | 475 | ButtonType.TRIGGER_L, |
| 484 | ) | 476 | data, |
| 485 | } | 477 | position |
| 486 | if (preferences.getBoolean(Settings.PREF_BUTTON_DPAD, true)) { | 478 | ) |
| 487 | overlayDpads.add( | 479 | ) |
| 488 | initializeOverlayDpad( | 480 | } |
| 489 | context, | 481 | |
| 490 | windowSize, | 482 | OverlayControl.BUTTON_R.id -> { |
| 491 | R.drawable.dpad_standard, | 483 | overlayButtons.add( |
| 492 | R.drawable.dpad_standard_cardinal_depressed, | 484 | initializeOverlayButton( |
| 493 | R.drawable.dpad_standard_diagonal_depressed, | 485 | context, |
| 494 | layout | 486 | windowSize, |
| 495 | ) | 487 | R.drawable.r_shoulder, |
| 496 | ) | 488 | R.drawable.r_shoulder_depressed, |
| 497 | } | 489 | ButtonType.TRIGGER_R, |
| 498 | if (preferences.getBoolean(Settings.PREF_STICK_L, true)) { | 490 | data, |
| 499 | overlayJoysticks.add( | 491 | position |
| 500 | initializeOverlayJoystick( | 492 | ) |
| 501 | context, | 493 | ) |
| 502 | windowSize, | 494 | } |
| 503 | R.drawable.joystick_range, | 495 | |
| 504 | R.drawable.joystick, | 496 | OverlayControl.BUTTON_ZL.id -> { |
| 505 | R.drawable.joystick_depressed, | 497 | overlayButtons.add( |
| 506 | StickType.STICK_L, | 498 | initializeOverlayButton( |
| 507 | ButtonType.STICK_L, | 499 | context, |
| 508 | Settings.PREF_STICK_L, | 500 | windowSize, |
| 509 | layout | 501 | R.drawable.zl_trigger, |
| 510 | ) | 502 | R.drawable.zl_trigger_depressed, |
| 511 | ) | 503 | ButtonType.TRIGGER_ZL, |
| 512 | } | 504 | data, |
| 513 | if (preferences.getBoolean(Settings.PREF_STICK_R, true)) { | 505 | position |
| 514 | overlayJoysticks.add( | 506 | ) |
| 515 | initializeOverlayJoystick( | 507 | ) |
| 516 | context, | 508 | } |
| 517 | windowSize, | 509 | |
| 518 | R.drawable.joystick_range, | 510 | OverlayControl.BUTTON_ZR.id -> { |
| 519 | R.drawable.joystick, | 511 | overlayButtons.add( |
| 520 | R.drawable.joystick_depressed, | 512 | initializeOverlayButton( |
| 521 | StickType.STICK_R, | 513 | context, |
| 522 | ButtonType.STICK_R, | 514 | windowSize, |
| 523 | Settings.PREF_STICK_R, | 515 | R.drawable.zr_trigger, |
| 524 | layout | 516 | R.drawable.zr_trigger_depressed, |
| 525 | ) | 517 | ButtonType.TRIGGER_ZR, |
| 526 | ) | 518 | data, |
| 527 | } | 519 | position |
| 528 | if (preferences.getBoolean(Settings.PREF_BUTTON_HOME, false)) { | 520 | ) |
| 529 | overlayButtons.add( | 521 | ) |
| 530 | initializeOverlayButton( | 522 | } |
| 531 | context, | 523 | |
| 532 | windowSize, | 524 | OverlayControl.BUTTON_STICK_L.id -> { |
| 533 | R.drawable.facebutton_home, | 525 | overlayButtons.add( |
| 534 | R.drawable.facebutton_home_depressed, | 526 | initializeOverlayButton( |
| 535 | ButtonType.BUTTON_HOME, | 527 | context, |
| 536 | Settings.PREF_BUTTON_HOME, | 528 | windowSize, |
| 537 | layout | 529 | R.drawable.button_l3, |
| 538 | ) | 530 | R.drawable.button_l3_depressed, |
| 539 | ) | 531 | ButtonType.STICK_L, |
| 540 | } | 532 | data, |
| 541 | if (preferences.getBoolean(Settings.PREF_BUTTON_SCREENSHOT, false)) { | 533 | position |
| 542 | overlayButtons.add( | 534 | ) |
| 543 | initializeOverlayButton( | 535 | ) |
| 544 | context, | 536 | } |
| 545 | windowSize, | 537 | |
| 546 | R.drawable.facebutton_screenshot, | 538 | OverlayControl.BUTTON_STICK_R.id -> { |
| 547 | R.drawable.facebutton_screenshot_depressed, | 539 | overlayButtons.add( |
| 548 | ButtonType.BUTTON_CAPTURE, | 540 | initializeOverlayButton( |
| 549 | Settings.PREF_BUTTON_SCREENSHOT, | 541 | context, |
| 550 | layout | 542 | windowSize, |
| 551 | ) | 543 | R.drawable.button_r3, |
| 552 | ) | 544 | R.drawable.button_r3_depressed, |
| 553 | } | 545 | ButtonType.STICK_R, |
| 554 | if (preferences.getBoolean(Settings.PREF_BUTTON_STICK_L, true)) { | 546 | data, |
| 555 | overlayButtons.add( | 547 | position |
| 556 | initializeOverlayButton( | 548 | ) |
| 557 | context, | 549 | ) |
| 558 | windowSize, | 550 | } |
| 559 | R.drawable.button_l3, | 551 | |
| 560 | R.drawable.button_l3_depressed, | 552 | OverlayControl.STICK_L.id -> { |
| 561 | ButtonType.STICK_L, | 553 | overlayJoysticks.add( |
| 562 | Settings.PREF_BUTTON_STICK_L, | 554 | initializeOverlayJoystick( |
| 563 | layout | 555 | context, |
| 564 | ) | 556 | windowSize, |
| 565 | ) | 557 | R.drawable.joystick_range, |
| 566 | } | 558 | R.drawable.joystick, |
| 567 | if (preferences.getBoolean(Settings.PREF_BUTTON_STICK_R, true)) { | 559 | R.drawable.joystick_depressed, |
| 568 | overlayButtons.add( | 560 | StickType.STICK_L, |
| 569 | initializeOverlayButton( | 561 | ButtonType.STICK_L, |
| 570 | context, | 562 | data, |
| 571 | windowSize, | 563 | position |
| 572 | R.drawable.button_r3, | 564 | ) |
| 573 | R.drawable.button_r3_depressed, | 565 | ) |
| 574 | ButtonType.STICK_R, | 566 | } |
| 575 | Settings.PREF_BUTTON_STICK_R, | 567 | |
| 576 | layout | 568 | OverlayControl.STICK_R.id -> { |
| 577 | ) | 569 | overlayJoysticks.add( |
| 578 | ) | 570 | initializeOverlayJoystick( |
| 571 | context, | ||
| 572 | windowSize, | ||
| 573 | R.drawable.joystick_range, | ||
| 574 | R.drawable.joystick, | ||
| 575 | R.drawable.joystick_depressed, | ||
| 576 | StickType.STICK_R, | ||
| 577 | ButtonType.STICK_R, | ||
| 578 | data, | ||
| 579 | position | ||
| 580 | ) | ||
| 581 | ) | ||
| 582 | } | ||
| 583 | |||
| 584 | OverlayControl.COMBINED_DPAD.id -> { | ||
| 585 | overlayDpads.add( | ||
| 586 | initializeOverlayDpad( | ||
| 587 | context, | ||
| 588 | windowSize, | ||
| 589 | R.drawable.dpad_standard, | ||
| 590 | R.drawable.dpad_standard_cardinal_depressed, | ||
| 591 | R.drawable.dpad_standard_diagonal_depressed, | ||
| 592 | position | ||
| 593 | ) | ||
| 594 | ) | ||
| 595 | } | ||
| 596 | } | ||
| 579 | } | 597 | } |
| 580 | } | 598 | } |
| 581 | 599 | ||
| @@ -586,313 +604,87 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 586 | overlayJoysticks.clear() | 604 | overlayJoysticks.clear() |
| 587 | 605 | ||
| 588 | // Add all the enabled overlay items back to the HashSet. | 606 | // Add all the enabled overlay items back to the HashSet. |
| 589 | if (EmulationMenuSettings.showOverlay) { | 607 | if (BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()) { |
| 590 | addOverlayControls(layout) | 608 | addOverlayControls(layout) |
| 591 | } | 609 | } |
| 592 | invalidate() | 610 | invalidate() |
| 593 | } | 611 | } |
| 594 | 612 | ||
| 595 | private fun saveControlPosition(prefId: String, x: Int, y: Int, layout: String) { | 613 | private fun saveControlPosition(id: String, x: Int, y: Int, layout: OverlayLayout) { |
| 596 | val windowSize = getSafeScreenSize(context, Pair(measuredWidth, measuredHeight)) | 614 | val windowSize = getSafeScreenSize(context, Pair(measuredWidth, measuredHeight)) |
| 597 | val min = windowSize.first | 615 | val min = windowSize.first |
| 598 | val max = windowSize.second | 616 | val max = windowSize.second |
| 599 | PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext).edit() | 617 | val overlayControlData = NativeConfig.getOverlayControlData() |
| 600 | .putFloat("$prefId-X$layout", (x - min.x).toFloat() / max.x) | 618 | val data = overlayControlData.firstOrNull { it.id == id } |
| 601 | .putFloat("$prefId-Y$layout", (y - min.y).toFloat() / max.y) | 619 | val newPosition = Pair((x - min.x).toDouble() / max.x, (y - min.y).toDouble() / max.y) |
| 602 | .apply() | 620 | when (layout) { |
| 621 | OverlayLayout.Landscape -> data?.landscapePosition = newPosition | ||
| 622 | OverlayLayout.Portrait -> data?.portraitPosition = newPosition | ||
| 623 | OverlayLayout.Foldable -> data?.foldablePosition = newPosition | ||
| 624 | } | ||
| 625 | NativeConfig.setOverlayControlData(overlayControlData) | ||
| 603 | } | 626 | } |
| 604 | 627 | ||
| 605 | fun setIsInEditMode(editMode: Boolean) { | 628 | fun setIsInEditMode(editMode: Boolean) { |
| 606 | inEditMode = editMode | 629 | inEditMode = editMode |
| 607 | } | 630 | } |
| 608 | 631 | ||
| 609 | private fun resetCurrentLayout() { | 632 | /** |
| 610 | defaultOverlayByLayout(layout) | 633 | * Applies and saves all default values for the overlay |
| 611 | val layoutIndex = overlayLayouts.indexOf(layout) | 634 | */ |
| 612 | preferences.edit() | 635 | private fun populateDefaultConfig() { |
| 613 | .putInt(Settings.overlayLayoutPrefs[layoutIndex], overlayLayoutVersions[layoutIndex]) | 636 | val newConfig = OverlayControl.entries.map { it.toOverlayControlData() } |
| 614 | .apply() | 637 | NativeConfig.setOverlayControlData(newConfig.toTypedArray()) |
| 638 | NativeConfig.saveGlobalConfig() | ||
| 615 | } | 639 | } |
| 616 | 640 | ||
| 617 | private fun resetAllLayouts() { | 641 | /** |
| 618 | val editor = preferences.edit() | 642 | * Checks if any new controls were added to OverlayControl that do not exist within deserialized |
| 619 | overlayLayouts.forEachIndexed { i, layout -> | 643 | * config and adds / saves them if necessary |
| 620 | defaultOverlayByLayout(layout) | 644 | * |
| 621 | editor.putInt(Settings.overlayLayoutPrefs[i], overlayLayoutVersions[i]) | 645 | * @param overlayControlData Overlay control data from [NativeConfig.getOverlayControlData] |
| 646 | */ | ||
| 647 | private fun checkForNewControls(overlayControlData: Array<OverlayControlData>) { | ||
| 648 | val missingControls = mutableListOf<OverlayControlData>() | ||
| 649 | OverlayControl.entries.forEach { defaultControl -> | ||
| 650 | val controlData = overlayControlData.firstOrNull { it.id == defaultControl.id } | ||
| 651 | if (controlData == null) { | ||
| 652 | missingControls.add(defaultControl.toOverlayControlData()) | ||
| 653 | } | ||
| 654 | } | ||
| 655 | |||
| 656 | if (missingControls.isNotEmpty()) { | ||
| 657 | NativeConfig.setOverlayControlData( | ||
| 658 | arrayOf(*overlayControlData, *(missingControls.toTypedArray())) | ||
| 659 | ) | ||
| 660 | NativeConfig.saveGlobalConfig() | ||
| 622 | } | 661 | } |
| 623 | editor.putInt(Settings.PREF_OVERLAY_VERSION, OVERLAY_VERSION) | ||
| 624 | editor.apply() | ||
| 625 | } | 662 | } |
| 626 | 663 | ||
| 627 | fun resetLayoutVisibilityAndPlacement() { | 664 | fun resetLayoutVisibilityAndPlacement() { |
| 628 | defaultOverlayByLayout(layout) | 665 | defaultOverlayPositionByLayout(layout) |
| 629 | val editor = preferences.edit() | 666 | |
| 630 | Settings.overlayPreferences.forEachIndexed { _, pref -> | 667 | val overlayControlData = NativeConfig.getOverlayControlData() |
| 631 | editor.remove(pref) | 668 | overlayControlData.forEach { |
| 669 | it.enabled = OverlayControl.from(it.id)?.defaultVisibility == false | ||
| 632 | } | 670 | } |
| 633 | editor.apply() | 671 | NativeConfig.setOverlayControlData(overlayControlData) |
| 672 | |||
| 634 | refreshControls() | 673 | refreshControls() |
| 635 | } | 674 | } |
| 636 | 675 | ||
| 637 | private val landscapeResources = arrayOf( | 676 | private fun defaultOverlayPositionByLayout(layout: OverlayLayout) { |
| 638 | R.integer.SWITCH_BUTTON_A_X, | 677 | val overlayControlData = NativeConfig.getOverlayControlData() |
| 639 | R.integer.SWITCH_BUTTON_A_Y, | 678 | for (data in overlayControlData) { |
| 640 | R.integer.SWITCH_BUTTON_B_X, | 679 | val defaultControlData = OverlayControl.from(data.id) ?: continue |
| 641 | R.integer.SWITCH_BUTTON_B_Y, | 680 | val position = defaultControlData.getDefaultPositionForLayout(layout) |
| 642 | R.integer.SWITCH_BUTTON_X_X, | 681 | when (layout) { |
| 643 | R.integer.SWITCH_BUTTON_X_Y, | 682 | OverlayLayout.Landscape -> data.landscapePosition = position |
| 644 | R.integer.SWITCH_BUTTON_Y_X, | 683 | OverlayLayout.Portrait -> data.portraitPosition = position |
| 645 | R.integer.SWITCH_BUTTON_Y_Y, | 684 | OverlayLayout.Foldable -> data.foldablePosition = position |
| 646 | R.integer.SWITCH_TRIGGER_ZL_X, | 685 | } |
| 647 | R.integer.SWITCH_TRIGGER_ZL_Y, | ||
| 648 | R.integer.SWITCH_TRIGGER_ZR_X, | ||
| 649 | R.integer.SWITCH_TRIGGER_ZR_Y, | ||
| 650 | R.integer.SWITCH_BUTTON_DPAD_X, | ||
| 651 | R.integer.SWITCH_BUTTON_DPAD_Y, | ||
| 652 | R.integer.SWITCH_TRIGGER_L_X, | ||
| 653 | R.integer.SWITCH_TRIGGER_L_Y, | ||
| 654 | R.integer.SWITCH_TRIGGER_R_X, | ||
| 655 | R.integer.SWITCH_TRIGGER_R_Y, | ||
| 656 | R.integer.SWITCH_BUTTON_PLUS_X, | ||
| 657 | R.integer.SWITCH_BUTTON_PLUS_Y, | ||
| 658 | R.integer.SWITCH_BUTTON_MINUS_X, | ||
| 659 | R.integer.SWITCH_BUTTON_MINUS_Y, | ||
| 660 | R.integer.SWITCH_BUTTON_HOME_X, | ||
| 661 | R.integer.SWITCH_BUTTON_HOME_Y, | ||
| 662 | R.integer.SWITCH_BUTTON_CAPTURE_X, | ||
| 663 | R.integer.SWITCH_BUTTON_CAPTURE_Y, | ||
| 664 | R.integer.SWITCH_STICK_R_X, | ||
| 665 | R.integer.SWITCH_STICK_R_Y, | ||
| 666 | R.integer.SWITCH_STICK_L_X, | ||
| 667 | R.integer.SWITCH_STICK_L_Y, | ||
| 668 | R.integer.SWITCH_BUTTON_STICK_L_X, | ||
| 669 | R.integer.SWITCH_BUTTON_STICK_L_Y, | ||
| 670 | R.integer.SWITCH_BUTTON_STICK_R_X, | ||
| 671 | R.integer.SWITCH_BUTTON_STICK_R_Y | ||
| 672 | ) | ||
| 673 | |||
| 674 | private val portraitResources = arrayOf( | ||
| 675 | R.integer.SWITCH_BUTTON_A_X_PORTRAIT, | ||
| 676 | R.integer.SWITCH_BUTTON_A_Y_PORTRAIT, | ||
| 677 | R.integer.SWITCH_BUTTON_B_X_PORTRAIT, | ||
| 678 | R.integer.SWITCH_BUTTON_B_Y_PORTRAIT, | ||
| 679 | R.integer.SWITCH_BUTTON_X_X_PORTRAIT, | ||
| 680 | R.integer.SWITCH_BUTTON_X_Y_PORTRAIT, | ||
| 681 | R.integer.SWITCH_BUTTON_Y_X_PORTRAIT, | ||
| 682 | R.integer.SWITCH_BUTTON_Y_Y_PORTRAIT, | ||
| 683 | R.integer.SWITCH_TRIGGER_ZL_X_PORTRAIT, | ||
| 684 | R.integer.SWITCH_TRIGGER_ZL_Y_PORTRAIT, | ||
| 685 | R.integer.SWITCH_TRIGGER_ZR_X_PORTRAIT, | ||
| 686 | R.integer.SWITCH_TRIGGER_ZR_Y_PORTRAIT, | ||
| 687 | R.integer.SWITCH_BUTTON_DPAD_X_PORTRAIT, | ||
| 688 | R.integer.SWITCH_BUTTON_DPAD_Y_PORTRAIT, | ||
| 689 | R.integer.SWITCH_TRIGGER_L_X_PORTRAIT, | ||
| 690 | R.integer.SWITCH_TRIGGER_L_Y_PORTRAIT, | ||
| 691 | R.integer.SWITCH_TRIGGER_R_X_PORTRAIT, | ||
| 692 | R.integer.SWITCH_TRIGGER_R_Y_PORTRAIT, | ||
| 693 | R.integer.SWITCH_BUTTON_PLUS_X_PORTRAIT, | ||
| 694 | R.integer.SWITCH_BUTTON_PLUS_Y_PORTRAIT, | ||
| 695 | R.integer.SWITCH_BUTTON_MINUS_X_PORTRAIT, | ||
| 696 | R.integer.SWITCH_BUTTON_MINUS_Y_PORTRAIT, | ||
| 697 | R.integer.SWITCH_BUTTON_HOME_X_PORTRAIT, | ||
| 698 | R.integer.SWITCH_BUTTON_HOME_Y_PORTRAIT, | ||
| 699 | R.integer.SWITCH_BUTTON_CAPTURE_X_PORTRAIT, | ||
| 700 | R.integer.SWITCH_BUTTON_CAPTURE_Y_PORTRAIT, | ||
| 701 | R.integer.SWITCH_STICK_R_X_PORTRAIT, | ||
| 702 | R.integer.SWITCH_STICK_R_Y_PORTRAIT, | ||
| 703 | R.integer.SWITCH_STICK_L_X_PORTRAIT, | ||
| 704 | R.integer.SWITCH_STICK_L_Y_PORTRAIT, | ||
| 705 | R.integer.SWITCH_BUTTON_STICK_L_X_PORTRAIT, | ||
| 706 | R.integer.SWITCH_BUTTON_STICK_L_Y_PORTRAIT, | ||
| 707 | R.integer.SWITCH_BUTTON_STICK_R_X_PORTRAIT, | ||
| 708 | R.integer.SWITCH_BUTTON_STICK_R_Y_PORTRAIT | ||
| 709 | ) | ||
| 710 | |||
| 711 | private val foldableResources = arrayOf( | ||
| 712 | R.integer.SWITCH_BUTTON_A_X_FOLDABLE, | ||
| 713 | R.integer.SWITCH_BUTTON_A_Y_FOLDABLE, | ||
| 714 | R.integer.SWITCH_BUTTON_B_X_FOLDABLE, | ||
| 715 | R.integer.SWITCH_BUTTON_B_Y_FOLDABLE, | ||
| 716 | R.integer.SWITCH_BUTTON_X_X_FOLDABLE, | ||
| 717 | R.integer.SWITCH_BUTTON_X_Y_FOLDABLE, | ||
| 718 | R.integer.SWITCH_BUTTON_Y_X_FOLDABLE, | ||
| 719 | R.integer.SWITCH_BUTTON_Y_Y_FOLDABLE, | ||
| 720 | R.integer.SWITCH_TRIGGER_ZL_X_FOLDABLE, | ||
| 721 | R.integer.SWITCH_TRIGGER_ZL_Y_FOLDABLE, | ||
| 722 | R.integer.SWITCH_TRIGGER_ZR_X_FOLDABLE, | ||
| 723 | R.integer.SWITCH_TRIGGER_ZR_Y_FOLDABLE, | ||
| 724 | R.integer.SWITCH_BUTTON_DPAD_X_FOLDABLE, | ||
| 725 | R.integer.SWITCH_BUTTON_DPAD_Y_FOLDABLE, | ||
| 726 | R.integer.SWITCH_TRIGGER_L_X_FOLDABLE, | ||
| 727 | R.integer.SWITCH_TRIGGER_L_Y_FOLDABLE, | ||
| 728 | R.integer.SWITCH_TRIGGER_R_X_FOLDABLE, | ||
| 729 | R.integer.SWITCH_TRIGGER_R_Y_FOLDABLE, | ||
| 730 | R.integer.SWITCH_BUTTON_PLUS_X_FOLDABLE, | ||
| 731 | R.integer.SWITCH_BUTTON_PLUS_Y_FOLDABLE, | ||
| 732 | R.integer.SWITCH_BUTTON_MINUS_X_FOLDABLE, | ||
| 733 | R.integer.SWITCH_BUTTON_MINUS_Y_FOLDABLE, | ||
| 734 | R.integer.SWITCH_BUTTON_HOME_X_FOLDABLE, | ||
| 735 | R.integer.SWITCH_BUTTON_HOME_Y_FOLDABLE, | ||
| 736 | R.integer.SWITCH_BUTTON_CAPTURE_X_FOLDABLE, | ||
| 737 | R.integer.SWITCH_BUTTON_CAPTURE_Y_FOLDABLE, | ||
| 738 | R.integer.SWITCH_STICK_R_X_FOLDABLE, | ||
| 739 | R.integer.SWITCH_STICK_R_Y_FOLDABLE, | ||
| 740 | R.integer.SWITCH_STICK_L_X_FOLDABLE, | ||
| 741 | R.integer.SWITCH_STICK_L_Y_FOLDABLE, | ||
| 742 | R.integer.SWITCH_BUTTON_STICK_L_X_FOLDABLE, | ||
| 743 | R.integer.SWITCH_BUTTON_STICK_L_Y_FOLDABLE, | ||
| 744 | R.integer.SWITCH_BUTTON_STICK_R_X_FOLDABLE, | ||
| 745 | R.integer.SWITCH_BUTTON_STICK_R_Y_FOLDABLE | ||
| 746 | ) | ||
| 747 | |||
| 748 | private fun getResourceValue(layout: String, position: Int): Float { | ||
| 749 | return when (layout) { | ||
| 750 | PORTRAIT -> resources.getInteger(portraitResources[position]).toFloat() / 1000 | ||
| 751 | FOLDABLE -> resources.getInteger(foldableResources[position]).toFloat() / 1000 | ||
| 752 | else -> resources.getInteger(landscapeResources[position]).toFloat() / 1000 | ||
| 753 | } | 686 | } |
| 754 | } | 687 | NativeConfig.setOverlayControlData(overlayControlData) |
| 755 | |||
| 756 | private fun defaultOverlayByLayout(layout: String) { | ||
| 757 | // Each value represents the position of the button in relation to the screen size without insets. | ||
| 758 | preferences.edit() | ||
| 759 | .putFloat( | ||
| 760 | "${Settings.PREF_BUTTON_A}-X$layout", | ||
| 761 | getResourceValue(layout, 0) | ||
| 762 | ) | ||
| 763 | .putFloat( | ||
| 764 | "${Settings.PREF_BUTTON_A}-Y$layout", | ||
| 765 | getResourceValue(layout, 1) | ||
| 766 | ) | ||
| 767 | .putFloat( | ||
| 768 | "${Settings.PREF_BUTTON_B}-X$layout", | ||
| 769 | getResourceValue(layout, 2) | ||
| 770 | ) | ||
| 771 | .putFloat( | ||
| 772 | "${Settings.PREF_BUTTON_B}-Y$layout", | ||
| 773 | getResourceValue(layout, 3) | ||
| 774 | ) | ||
| 775 | .putFloat( | ||
| 776 | "${Settings.PREF_BUTTON_X}-X$layout", | ||
| 777 | getResourceValue(layout, 4) | ||
| 778 | ) | ||
| 779 | .putFloat( | ||
| 780 | "${Settings.PREF_BUTTON_X}-Y$layout", | ||
| 781 | getResourceValue(layout, 5) | ||
| 782 | ) | ||
| 783 | .putFloat( | ||
| 784 | "${Settings.PREF_BUTTON_Y}-X$layout", | ||
| 785 | getResourceValue(layout, 6) | ||
| 786 | ) | ||
| 787 | .putFloat( | ||
| 788 | "${Settings.PREF_BUTTON_Y}-Y$layout", | ||
| 789 | getResourceValue(layout, 7) | ||
| 790 | ) | ||
| 791 | .putFloat( | ||
| 792 | "${Settings.PREF_BUTTON_ZL}-X$layout", | ||
| 793 | getResourceValue(layout, 8) | ||
| 794 | ) | ||
| 795 | .putFloat( | ||
| 796 | "${Settings.PREF_BUTTON_ZL}-Y$layout", | ||
| 797 | getResourceValue(layout, 9) | ||
| 798 | ) | ||
| 799 | .putFloat( | ||
| 800 | "${Settings.PREF_BUTTON_ZR}-X$layout", | ||
| 801 | getResourceValue(layout, 10) | ||
| 802 | ) | ||
| 803 | .putFloat( | ||
| 804 | "${Settings.PREF_BUTTON_ZR}-Y$layout", | ||
| 805 | getResourceValue(layout, 11) | ||
| 806 | ) | ||
| 807 | .putFloat( | ||
| 808 | "${Settings.PREF_BUTTON_DPAD}-X$layout", | ||
| 809 | getResourceValue(layout, 12) | ||
| 810 | ) | ||
| 811 | .putFloat( | ||
| 812 | "${Settings.PREF_BUTTON_DPAD}-Y$layout", | ||
| 813 | getResourceValue(layout, 13) | ||
| 814 | ) | ||
| 815 | .putFloat( | ||
| 816 | "${Settings.PREF_BUTTON_L}-X$layout", | ||
| 817 | getResourceValue(layout, 14) | ||
| 818 | ) | ||
| 819 | .putFloat( | ||
| 820 | "${Settings.PREF_BUTTON_L}-Y$layout", | ||
| 821 | getResourceValue(layout, 15) | ||
| 822 | ) | ||
| 823 | .putFloat( | ||
| 824 | "${Settings.PREF_BUTTON_R}-X$layout", | ||
| 825 | getResourceValue(layout, 16) | ||
| 826 | ) | ||
| 827 | .putFloat( | ||
| 828 | "${Settings.PREF_BUTTON_R}-Y$layout", | ||
| 829 | getResourceValue(layout, 17) | ||
| 830 | ) | ||
| 831 | .putFloat( | ||
| 832 | "${Settings.PREF_BUTTON_PLUS}-X$layout", | ||
| 833 | getResourceValue(layout, 18) | ||
| 834 | ) | ||
| 835 | .putFloat( | ||
| 836 | "${Settings.PREF_BUTTON_PLUS}-Y$layout", | ||
| 837 | getResourceValue(layout, 19) | ||
| 838 | ) | ||
| 839 | .putFloat( | ||
| 840 | "${Settings.PREF_BUTTON_MINUS}-X$layout", | ||
| 841 | getResourceValue(layout, 20) | ||
| 842 | ) | ||
| 843 | .putFloat( | ||
| 844 | "${Settings.PREF_BUTTON_MINUS}-Y$layout", | ||
| 845 | getResourceValue(layout, 21) | ||
| 846 | ) | ||
| 847 | .putFloat( | ||
| 848 | "${Settings.PREF_BUTTON_HOME}-X$layout", | ||
| 849 | getResourceValue(layout, 22) | ||
| 850 | ) | ||
| 851 | .putFloat( | ||
| 852 | "${Settings.PREF_BUTTON_HOME}-Y$layout", | ||
| 853 | getResourceValue(layout, 23) | ||
| 854 | ) | ||
| 855 | .putFloat( | ||
| 856 | "${Settings.PREF_BUTTON_SCREENSHOT}-X$layout", | ||
| 857 | getResourceValue(layout, 24) | ||
| 858 | ) | ||
| 859 | .putFloat( | ||
| 860 | "${Settings.PREF_BUTTON_SCREENSHOT}-Y$layout", | ||
| 861 | getResourceValue(layout, 25) | ||
| 862 | ) | ||
| 863 | .putFloat( | ||
| 864 | "${Settings.PREF_STICK_R}-X$layout", | ||
| 865 | getResourceValue(layout, 26) | ||
| 866 | ) | ||
| 867 | .putFloat( | ||
| 868 | "${Settings.PREF_STICK_R}-Y$layout", | ||
| 869 | getResourceValue(layout, 27) | ||
| 870 | ) | ||
| 871 | .putFloat( | ||
| 872 | "${Settings.PREF_STICK_L}-X$layout", | ||
| 873 | getResourceValue(layout, 28) | ||
| 874 | ) | ||
| 875 | .putFloat( | ||
| 876 | "${Settings.PREF_STICK_L}-Y$layout", | ||
| 877 | getResourceValue(layout, 29) | ||
| 878 | ) | ||
| 879 | .putFloat( | ||
| 880 | "${Settings.PREF_BUTTON_STICK_L}-X$layout", | ||
| 881 | getResourceValue(layout, 30) | ||
| 882 | ) | ||
| 883 | .putFloat( | ||
| 884 | "${Settings.PREF_BUTTON_STICK_L}-Y$layout", | ||
| 885 | getResourceValue(layout, 31) | ||
| 886 | ) | ||
| 887 | .putFloat( | ||
| 888 | "${Settings.PREF_BUTTON_STICK_R}-X$layout", | ||
| 889 | getResourceValue(layout, 32) | ||
| 890 | ) | ||
| 891 | .putFloat( | ||
| 892 | "${Settings.PREF_BUTTON_STICK_R}-Y$layout", | ||
| 893 | getResourceValue(layout, 33) | ||
| 894 | ) | ||
| 895 | .apply() | ||
| 896 | } | 688 | } |
| 897 | 689 | ||
| 898 | override fun isInEditMode(): Boolean { | 690 | override fun isInEditMode(): Boolean { |
| @@ -913,18 +705,6 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 913 | FOLDABLE_OVERLAY_VERSION | 705 | FOLDABLE_OVERLAY_VERSION |
| 914 | ) | 706 | ) |
| 915 | 707 | ||
| 916 | private val preferences: SharedPreferences = | ||
| 917 | PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||
| 918 | |||
| 919 | const val LANDSCAPE = "_Landscape" | ||
| 920 | const val PORTRAIT = "_Portrait" | ||
| 921 | const val FOLDABLE = "_Foldable" | ||
| 922 | val overlayLayouts = listOf( | ||
| 923 | LANDSCAPE, | ||
| 924 | PORTRAIT, | ||
| 925 | FOLDABLE | ||
| 926 | ) | ||
| 927 | |||
| 928 | /** | 708 | /** |
| 929 | * Resizes a [Bitmap] by a given scale factor | 709 | * Resizes a [Bitmap] by a given scale factor |
| 930 | * | 710 | * |
| @@ -1036,29 +816,19 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1036 | * In the input overlay configuration menu, | 816 | * In the input overlay configuration menu, |
| 1037 | * once a touch event begins and then ends (ie. Organizing the buttons to one's own liking for the overlay). | 817 | * once a touch event begins and then ends (ie. Organizing the buttons to one's own liking for the overlay). |
| 1038 | * the X and Y coordinates of the button at the END of its touch event | 818 | * the X and Y coordinates of the button at the END of its touch event |
| 1039 | * (when you remove your finger/stylus from the touchscreen) are then stored | 819 | * (when you remove your finger/stylus from the touchscreen) are then stored in a native . |
| 1040 | * within a SharedPreferences instance so that those values can be retrieved here. | ||
| 1041 | * | ||
| 1042 | * | ||
| 1043 | * This has a few benefits over the conventional way of storing the values | ||
| 1044 | * (ie. within the yuzu ini file). | ||
| 1045 | * | ||
| 1046 | * * No native calls | ||
| 1047 | * * Keeps Android-only values inside the Android environment | ||
| 1048 | * | ||
| 1049 | * | ||
| 1050 | * | 820 | * |
| 1051 | * Technically no modifications should need to be performed on the returned | 821 | * Technically no modifications should need to be performed on the returned |
| 1052 | * InputOverlayDrawableButton. Simply add it to the HashSet of overlay items and wait | 822 | * InputOverlayDrawableButton. Simply add it to the HashSet of overlay items and wait |
| 1053 | * for Android to call the onDraw method. | 823 | * for Android to call the onDraw method. |
| 1054 | * | 824 | * |
| 1055 | * @param context The current [Context]. | 825 | * @param context The current [Context]. |
| 1056 | * @param windowSize The size of the window to draw the overlay on. | 826 | * @param windowSize The size of the window to draw the overlay on. |
| 1057 | * @param defaultResId The resource ID of the [Drawable] to get the [Bitmap] of (Default State). | 827 | * @param defaultResId The resource ID of the [Drawable] to get the [Bitmap] of (Default State). |
| 1058 | * @param pressedResId The resource ID of the [Drawable] to get the [Bitmap] of (Pressed State). | 828 | * @param pressedResId The resource ID of the [Drawable] to get the [Bitmap] of (Pressed State). |
| 1059 | * @param buttonId Identifier for determining what type of button the initialized InputOverlayDrawableButton represents. | 829 | * @param buttonId Identifier for determining what type of button the initialized InputOverlayDrawableButton represents. |
| 1060 | * @param prefId Identifier for determining where a button appears on screen. | 830 | * @param overlayControlData Identifier for determining where a button appears on screen. |
| 1061 | * @param layout The current screen layout as determined by [LANDSCAPE], [PORTRAIT], or [FOLDABLE]. | 831 | * @param position The position on screen as represented by an x and y value between 0 and 1. |
| 1062 | * @return An [InputOverlayDrawableButton] with the correct drawing bounds set. | 832 | * @return An [InputOverlayDrawableButton] with the correct drawing bounds set. |
| 1063 | */ | 833 | */ |
| 1064 | private fun initializeOverlayButton( | 834 | private fun initializeOverlayButton( |
| @@ -1067,33 +837,30 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1067 | defaultResId: Int, | 837 | defaultResId: Int, |
| 1068 | pressedResId: Int, | 838 | pressedResId: Int, |
| 1069 | buttonId: Int, | 839 | buttonId: Int, |
| 1070 | prefId: String, | 840 | overlayControlData: OverlayControlData, |
| 1071 | layout: String | 841 | position: Pair<Double, Double> |
| 1072 | ): InputOverlayDrawableButton { | 842 | ): InputOverlayDrawableButton { |
| 1073 | // Resources handle for fetching the initial Drawable resource. | 843 | // Resources handle for fetching the initial Drawable resource. |
| 1074 | val res = context.resources | 844 | val res = context.resources |
| 1075 | 845 | ||
| 1076 | // SharedPreference to retrieve the X and Y coordinates for the InputOverlayDrawableButton. | ||
| 1077 | val sPrefs = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||
| 1078 | |||
| 1079 | // Decide scale based on button preference ID and user preference | 846 | // Decide scale based on button preference ID and user preference |
| 1080 | var scale: Float = when (prefId) { | 847 | var scale: Float = when (overlayControlData.id) { |
| 1081 | Settings.PREF_BUTTON_HOME, | 848 | OverlayControl.BUTTON_HOME.id, |
| 1082 | Settings.PREF_BUTTON_SCREENSHOT, | 849 | OverlayControl.BUTTON_CAPTURE.id, |
| 1083 | Settings.PREF_BUTTON_PLUS, | 850 | OverlayControl.BUTTON_PLUS.id, |
| 1084 | Settings.PREF_BUTTON_MINUS -> 0.07f | 851 | OverlayControl.BUTTON_MINUS.id -> 0.07f |
| 1085 | 852 | ||
| 1086 | Settings.PREF_BUTTON_L, | 853 | OverlayControl.BUTTON_L.id, |
| 1087 | Settings.PREF_BUTTON_R, | 854 | OverlayControl.BUTTON_R.id, |
| 1088 | Settings.PREF_BUTTON_ZL, | 855 | OverlayControl.BUTTON_ZL.id, |
| 1089 | Settings.PREF_BUTTON_ZR -> 0.26f | 856 | OverlayControl.BUTTON_ZR.id -> 0.26f |
| 1090 | 857 | ||
| 1091 | Settings.PREF_BUTTON_STICK_L, | 858 | OverlayControl.BUTTON_STICK_L.id, |
| 1092 | Settings.PREF_BUTTON_STICK_R -> 0.155f | 859 | OverlayControl.BUTTON_STICK_R.id -> 0.155f |
| 1093 | 860 | ||
| 1094 | else -> 0.11f | 861 | else -> 0.11f |
| 1095 | } | 862 | } |
| 1096 | scale *= (sPrefs.getInt(Settings.PREF_CONTROL_SCALE, 50) + 50).toFloat() | 863 | scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat() |
| 1097 | scale /= 100f | 864 | scale /= 100f |
| 1098 | 865 | ||
| 1099 | // Initialize the InputOverlayDrawableButton. | 866 | // Initialize the InputOverlayDrawableButton. |
| @@ -1104,7 +871,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1104 | defaultStateBitmap, | 871 | defaultStateBitmap, |
| 1105 | pressedStateBitmap, | 872 | pressedStateBitmap, |
| 1106 | buttonId, | 873 | buttonId, |
| 1107 | prefId | 874 | overlayControlData |
| 1108 | ) | 875 | ) |
| 1109 | 876 | ||
| 1110 | // Get the minimum and maximum coordinates of the screen where the button can be placed. | 877 | // Get the minimum and maximum coordinates of the screen where the button can be placed. |
| @@ -1113,12 +880,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1113 | 880 | ||
| 1114 | // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. | 881 | // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. |
| 1115 | // These were set in the input overlay configuration menu. | 882 | // These were set in the input overlay configuration menu. |
| 1116 | val xKey = "$prefId-X$layout" | 883 | val drawableX = (position.first * max.x + min.x).toInt() |
| 1117 | val yKey = "$prefId-Y$layout" | 884 | val drawableY = (position.second * max.y + min.y).toInt() |
| 1118 | val drawableXPercent = sPrefs.getFloat(xKey, 0f) | ||
| 1119 | val drawableYPercent = sPrefs.getFloat(yKey, 0f) | ||
| 1120 | val drawableX = (drawableXPercent * max.x + min.x).toInt() | ||
| 1121 | val drawableY = (drawableYPercent * max.y + min.y).toInt() | ||
| 1122 | val width = overlayDrawable.width | 885 | val width = overlayDrawable.width |
| 1123 | val height = overlayDrawable.height | 886 | val height = overlayDrawable.height |
| 1124 | 887 | ||
| @@ -1136,8 +899,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1136 | drawableX - (width / 2), | 899 | drawableX - (width / 2), |
| 1137 | drawableY - (height / 2) | 900 | drawableY - (height / 2) |
| 1138 | ) | 901 | ) |
| 1139 | val savedOpacity = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100) | 902 | overlayDrawable.setOpacity(IntSetting.OVERLAY_OPACITY.getInt() * 255 / 100) |
| 1140 | overlayDrawable.setOpacity(savedOpacity * 255 / 100) | ||
| 1141 | return overlayDrawable | 903 | return overlayDrawable |
| 1142 | } | 904 | } |
| 1143 | 905 | ||
| @@ -1149,7 +911,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1149 | * @param defaultResId The [Bitmap] resource ID of the default state. | 911 | * @param defaultResId The [Bitmap] resource ID of the default state. |
| 1150 | * @param pressedOneDirectionResId The [Bitmap] resource ID of the pressed state in one direction. | 912 | * @param pressedOneDirectionResId The [Bitmap] resource ID of the pressed state in one direction. |
| 1151 | * @param pressedTwoDirectionsResId The [Bitmap] resource ID of the pressed state in two directions. | 913 | * @param pressedTwoDirectionsResId The [Bitmap] resource ID of the pressed state in two directions. |
| 1152 | * @param layout The current screen layout as determined by [LANDSCAPE], [PORTRAIT], or [FOLDABLE]. | 914 | * @param position The position on screen as represented by an x and y value between 0 and 1. |
| 1153 | * @return The initialized [InputOverlayDrawableDpad] | 915 | * @return The initialized [InputOverlayDrawableDpad] |
| 1154 | */ | 916 | */ |
| 1155 | private fun initializeOverlayDpad( | 917 | private fun initializeOverlayDpad( |
| @@ -1158,17 +920,14 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1158 | defaultResId: Int, | 920 | defaultResId: Int, |
| 1159 | pressedOneDirectionResId: Int, | 921 | pressedOneDirectionResId: Int, |
| 1160 | pressedTwoDirectionsResId: Int, | 922 | pressedTwoDirectionsResId: Int, |
| 1161 | layout: String | 923 | position: Pair<Double, Double> |
| 1162 | ): InputOverlayDrawableDpad { | 924 | ): InputOverlayDrawableDpad { |
| 1163 | // Resources handle for fetching the initial Drawable resource. | 925 | // Resources handle for fetching the initial Drawable resource. |
| 1164 | val res = context.resources | 926 | val res = context.resources |
| 1165 | 927 | ||
| 1166 | // SharedPreference to retrieve the X and Y coordinates for the InputOverlayDrawableDpad. | ||
| 1167 | val sPrefs = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||
| 1168 | |||
| 1169 | // Decide scale based on button ID and user preference | 928 | // Decide scale based on button ID and user preference |
| 1170 | var scale = 0.25f | 929 | var scale = 0.25f |
| 1171 | scale *= (sPrefs.getInt(Settings.PREF_CONTROL_SCALE, 50) + 50).toFloat() | 930 | scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat() |
| 1172 | scale /= 100f | 931 | scale /= 100f |
| 1173 | 932 | ||
| 1174 | // Initialize the InputOverlayDrawableDpad. | 933 | // Initialize the InputOverlayDrawableDpad. |
| @@ -1195,10 +954,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1195 | 954 | ||
| 1196 | // The X and Y coordinates of the InputOverlayDrawableDpad on the InputOverlay. | 955 | // The X and Y coordinates of the InputOverlayDrawableDpad on the InputOverlay. |
| 1197 | // These were set in the input overlay configuration menu. | 956 | // These were set in the input overlay configuration menu. |
| 1198 | val drawableXPercent = sPrefs.getFloat("${Settings.PREF_BUTTON_DPAD}-X$layout", 0f) | 957 | val drawableX = (position.first * max.x + min.x).toInt() |
| 1199 | val drawableYPercent = sPrefs.getFloat("${Settings.PREF_BUTTON_DPAD}-Y$layout", 0f) | 958 | val drawableY = (position.second * max.y + min.y).toInt() |
| 1200 | val drawableX = (drawableXPercent * max.x + min.x).toInt() | ||
| 1201 | val drawableY = (drawableYPercent * max.y + min.y).toInt() | ||
| 1202 | val width = overlayDrawable.width | 959 | val width = overlayDrawable.width |
| 1203 | val height = overlayDrawable.height | 960 | val height = overlayDrawable.height |
| 1204 | 961 | ||
| @@ -1213,8 +970,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1213 | 970 | ||
| 1214 | // Need to set the image's position | 971 | // Need to set the image's position |
| 1215 | overlayDrawable.setPosition(drawableX - (width / 2), drawableY - (height / 2)) | 972 | overlayDrawable.setPosition(drawableX - (width / 2), drawableY - (height / 2)) |
| 1216 | val savedOpacity = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100) | 973 | overlayDrawable.setOpacity(IntSetting.OVERLAY_OPACITY.getInt() * 255 / 100) |
| 1217 | overlayDrawable.setOpacity(savedOpacity * 255 / 100) | ||
| 1218 | return overlayDrawable | 974 | return overlayDrawable |
| 1219 | } | 975 | } |
| 1220 | 976 | ||
| @@ -1227,9 +983,9 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1227 | * @param defaultResInner Resource ID for the default inner image of the joystick (the one you actually move around). | 983 | * @param defaultResInner Resource ID for the default inner image of the joystick (the one you actually move around). |
| 1228 | * @param pressedResInner Resource ID for the pressed inner image of the joystick. | 984 | * @param pressedResInner Resource ID for the pressed inner image of the joystick. |
| 1229 | * @param joystick Identifier for which joystick this is. | 985 | * @param joystick Identifier for which joystick this is. |
| 1230 | * @param button Identifier for which joystick button this is. | 986 | * @param buttonId Identifier for which joystick button this is. |
| 1231 | * @param prefId Identifier for determining where a button appears on screen. | 987 | * @param overlayControlData Identifier for determining where a button appears on screen. |
| 1232 | * @param layout The current screen layout as determined by [LANDSCAPE], [PORTRAIT], or [FOLDABLE]. | 988 | * @param position The position on screen as represented by an x and y value between 0 and 1. |
| 1233 | * @return The initialized [InputOverlayDrawableJoystick]. | 989 | * @return The initialized [InputOverlayDrawableJoystick]. |
| 1234 | */ | 990 | */ |
| 1235 | private fun initializeOverlayJoystick( | 991 | private fun initializeOverlayJoystick( |
| @@ -1239,19 +995,16 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1239 | defaultResInner: Int, | 995 | defaultResInner: Int, |
| 1240 | pressedResInner: Int, | 996 | pressedResInner: Int, |
| 1241 | joystick: Int, | 997 | joystick: Int, |
| 1242 | button: Int, | 998 | buttonId: Int, |
| 1243 | prefId: String, | 999 | overlayControlData: OverlayControlData, |
| 1244 | layout: String | 1000 | position: Pair<Double, Double> |
| 1245 | ): InputOverlayDrawableJoystick { | 1001 | ): InputOverlayDrawableJoystick { |
| 1246 | // Resources handle for fetching the initial Drawable resource. | 1002 | // Resources handle for fetching the initial Drawable resource. |
| 1247 | val res = context.resources | 1003 | val res = context.resources |
| 1248 | 1004 | ||
| 1249 | // SharedPreference to retrieve the X and Y coordinates for the InputOverlayDrawableJoystick. | ||
| 1250 | val sPrefs = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||
| 1251 | |||
| 1252 | // Decide scale based on user preference | 1005 | // Decide scale based on user preference |
| 1253 | var scale = 0.3f | 1006 | var scale = 0.3f |
| 1254 | scale *= (sPrefs.getInt(Settings.PREF_CONTROL_SCALE, 50) + 50).toFloat() | 1007 | scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat() |
| 1255 | scale /= 100f | 1008 | scale /= 100f |
| 1256 | 1009 | ||
| 1257 | // Initialize the InputOverlayDrawableJoystick. | 1010 | // Initialize the InputOverlayDrawableJoystick. |
| @@ -1265,10 +1018,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1265 | 1018 | ||
| 1266 | // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. | 1019 | // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. |
| 1267 | // These were set in the input overlay configuration menu. | 1020 | // These were set in the input overlay configuration menu. |
| 1268 | val drawableXPercent = sPrefs.getFloat("$prefId-X$layout", 0f) | 1021 | val drawableX = (position.first * max.x + min.x).toInt() |
| 1269 | val drawableYPercent = sPrefs.getFloat("$prefId-Y$layout", 0f) | 1022 | val drawableY = (position.second * max.y + min.y).toInt() |
| 1270 | val drawableX = (drawableXPercent * max.x + min.x).toInt() | ||
| 1271 | val drawableY = (drawableYPercent * max.y + min.y).toInt() | ||
| 1272 | val outerScale = 1.66f | 1023 | val outerScale = 1.66f |
| 1273 | 1024 | ||
| 1274 | // Now set the bounds for the InputOverlayDrawableJoystick. | 1025 | // Now set the bounds for the InputOverlayDrawableJoystick. |
| @@ -1292,14 +1043,13 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1292 | outerRect, | 1043 | outerRect, |
| 1293 | innerRect, | 1044 | innerRect, |
| 1294 | joystick, | 1045 | joystick, |
| 1295 | button, | 1046 | buttonId, |
| 1296 | prefId | 1047 | overlayControlData.id |
| 1297 | ) | 1048 | ) |
| 1298 | 1049 | ||
| 1299 | // Need to set the image's position | 1050 | // Need to set the image's position |
| 1300 | overlayDrawable.setPosition(drawableX, drawableY) | 1051 | overlayDrawable.setPosition(drawableX, drawableY) |
| 1301 | val savedOpacity = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100) | 1052 | overlayDrawable.setOpacity(IntSetting.OVERLAY_OPACITY.getInt() * 255 / 100) |
| 1302 | overlayDrawable.setOpacity(savedOpacity * 255 / 100) | ||
| 1303 | return overlayDrawable | 1053 | return overlayDrawable |
| 1304 | } | 1054 | } |
| 1305 | } | 1055 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableButton.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableButton.kt index 2c28dda88..b14a4f96e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableButton.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableButton.kt | |||
| @@ -10,6 +10,7 @@ import android.graphics.Rect | |||
| 10 | import android.graphics.drawable.BitmapDrawable | 10 | import android.graphics.drawable.BitmapDrawable |
| 11 | import android.view.MotionEvent | 11 | import android.view.MotionEvent |
| 12 | import org.yuzu.yuzu_emu.NativeLibrary.ButtonState | 12 | import org.yuzu.yuzu_emu.NativeLibrary.ButtonState |
| 13 | import org.yuzu.yuzu_emu.overlay.model.OverlayControlData | ||
| 13 | 14 | ||
| 14 | /** | 15 | /** |
| 15 | * Custom [BitmapDrawable] that is capable | 16 | * Custom [BitmapDrawable] that is capable |
| @@ -25,7 +26,7 @@ class InputOverlayDrawableButton( | |||
| 25 | defaultStateBitmap: Bitmap, | 26 | defaultStateBitmap: Bitmap, |
| 26 | pressedStateBitmap: Bitmap, | 27 | pressedStateBitmap: Bitmap, |
| 27 | val buttonId: Int, | 28 | val buttonId: Int, |
| 28 | val prefId: String | 29 | val overlayControlData: OverlayControlData |
| 29 | ) { | 30 | ) { |
| 30 | // The ID value what motion event is tracking | 31 | // The ID value what motion event is tracking |
| 31 | var trackId: Int | 32 | var trackId: Int |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt index 518b1e783..113bf7c24 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt | |||
| @@ -14,7 +14,7 @@ import kotlin.math.cos | |||
| 14 | import kotlin.math.sin | 14 | import kotlin.math.sin |
| 15 | import kotlin.math.sqrt | 15 | import kotlin.math.sqrt |
| 16 | import org.yuzu.yuzu_emu.NativeLibrary | 16 | import org.yuzu.yuzu_emu.NativeLibrary |
| 17 | import org.yuzu.yuzu_emu.utils.EmulationMenuSettings | 17 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting |
| 18 | 18 | ||
| 19 | /** | 19 | /** |
| 20 | * Custom [BitmapDrawable] that is capable | 20 | * Custom [BitmapDrawable] that is capable |
| @@ -125,7 +125,7 @@ class InputOverlayDrawableJoystick( | |||
| 125 | pressedState = true | 125 | pressedState = true |
| 126 | outerBitmap.alpha = 0 | 126 | outerBitmap.alpha = 0 |
| 127 | boundsBoxBitmap.alpha = opacity | 127 | boundsBoxBitmap.alpha = opacity |
| 128 | if (EmulationMenuSettings.joystickRelCenter) { | 128 | if (BooleanSetting.JOYSTICK_REL_CENTER.getBoolean()) { |
| 129 | virtBounds.offset( | 129 | virtBounds.offset( |
| 130 | xPosition - virtBounds.centerX(), | 130 | xPosition - virtBounds.centerX(), |
| 131 | yPosition - virtBounds.centerY() | 131 | yPosition - virtBounds.centerY() |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControl.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControl.kt new file mode 100644 index 000000000..a0eeadf4b --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControl.kt | |||
| @@ -0,0 +1,188 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.overlay.model | ||
| 5 | |||
| 6 | import androidx.annotation.IntegerRes | ||
| 7 | import org.yuzu.yuzu_emu.R | ||
| 8 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 9 | |||
| 10 | enum class OverlayControl( | ||
| 11 | val id: String, | ||
| 12 | val defaultVisibility: Boolean, | ||
| 13 | @IntegerRes val defaultLandscapePositionResources: Pair<Int, Int>, | ||
| 14 | @IntegerRes val defaultPortraitPositionResources: Pair<Int, Int>, | ||
| 15 | @IntegerRes val defaultFoldablePositionResources: Pair<Int, Int> | ||
| 16 | ) { | ||
| 17 | BUTTON_A( | ||
| 18 | "button_a", | ||
| 19 | true, | ||
| 20 | Pair(R.integer.BUTTON_A_X, R.integer.BUTTON_A_Y), | ||
| 21 | Pair(R.integer.BUTTON_A_X_PORTRAIT, R.integer.BUTTON_A_Y_PORTRAIT), | ||
| 22 | Pair(R.integer.BUTTON_A_X_FOLDABLE, R.integer.BUTTON_A_Y_FOLDABLE) | ||
| 23 | ), | ||
| 24 | BUTTON_B( | ||
| 25 | "button_b", | ||
| 26 | true, | ||
| 27 | Pair(R.integer.BUTTON_B_X, R.integer.BUTTON_B_Y), | ||
| 28 | Pair(R.integer.BUTTON_B_X_PORTRAIT, R.integer.BUTTON_B_Y_PORTRAIT), | ||
| 29 | Pair(R.integer.BUTTON_B_X_FOLDABLE, R.integer.BUTTON_B_Y_FOLDABLE) | ||
| 30 | ), | ||
| 31 | BUTTON_X( | ||
| 32 | "button_x", | ||
| 33 | true, | ||
| 34 | Pair(R.integer.BUTTON_X_X, R.integer.BUTTON_X_Y), | ||
| 35 | Pair(R.integer.BUTTON_X_X_PORTRAIT, R.integer.BUTTON_X_Y_PORTRAIT), | ||
| 36 | Pair(R.integer.BUTTON_X_X_FOLDABLE, R.integer.BUTTON_X_Y_FOLDABLE) | ||
| 37 | ), | ||
| 38 | BUTTON_Y( | ||
| 39 | "button_y", | ||
| 40 | true, | ||
| 41 | Pair(R.integer.BUTTON_Y_X, R.integer.BUTTON_Y_Y), | ||
| 42 | Pair(R.integer.BUTTON_Y_X_PORTRAIT, R.integer.BUTTON_Y_Y_PORTRAIT), | ||
| 43 | Pair(R.integer.BUTTON_Y_X_FOLDABLE, R.integer.BUTTON_Y_Y_FOLDABLE) | ||
| 44 | ), | ||
| 45 | BUTTON_PLUS( | ||
| 46 | "button_plus", | ||
| 47 | true, | ||
| 48 | Pair(R.integer.BUTTON_PLUS_X, R.integer.BUTTON_PLUS_Y), | ||
| 49 | Pair(R.integer.BUTTON_PLUS_X_PORTRAIT, R.integer.BUTTON_PLUS_Y_PORTRAIT), | ||
| 50 | Pair(R.integer.BUTTON_PLUS_X_FOLDABLE, R.integer.BUTTON_PLUS_Y_FOLDABLE) | ||
| 51 | ), | ||
| 52 | BUTTON_MINUS( | ||
| 53 | "button_minus", | ||
| 54 | true, | ||
| 55 | Pair(R.integer.BUTTON_MINUS_X, R.integer.BUTTON_MINUS_Y), | ||
| 56 | Pair(R.integer.BUTTON_MINUS_X_PORTRAIT, R.integer.BUTTON_MINUS_Y_PORTRAIT), | ||
| 57 | Pair(R.integer.BUTTON_MINUS_X_FOLDABLE, R.integer.BUTTON_MINUS_Y_FOLDABLE) | ||
| 58 | ), | ||
| 59 | BUTTON_HOME( | ||
| 60 | "button_home", | ||
| 61 | false, | ||
| 62 | Pair(R.integer.BUTTON_HOME_X, R.integer.BUTTON_HOME_Y), | ||
| 63 | Pair(R.integer.BUTTON_HOME_X_PORTRAIT, R.integer.BUTTON_HOME_Y_PORTRAIT), | ||
| 64 | Pair(R.integer.BUTTON_HOME_X_FOLDABLE, R.integer.BUTTON_HOME_Y_FOLDABLE) | ||
| 65 | ), | ||
| 66 | BUTTON_CAPTURE( | ||
| 67 | "button_capture", | ||
| 68 | false, | ||
| 69 | Pair(R.integer.BUTTON_CAPTURE_X, R.integer.BUTTON_CAPTURE_Y), | ||
| 70 | Pair(R.integer.BUTTON_CAPTURE_X_PORTRAIT, R.integer.BUTTON_CAPTURE_Y_PORTRAIT), | ||
| 71 | Pair(R.integer.BUTTON_CAPTURE_X_FOLDABLE, R.integer.BUTTON_CAPTURE_Y_FOLDABLE) | ||
| 72 | ), | ||
| 73 | BUTTON_L( | ||
| 74 | "button_l", | ||
| 75 | true, | ||
| 76 | Pair(R.integer.BUTTON_L_X, R.integer.BUTTON_L_Y), | ||
| 77 | Pair(R.integer.BUTTON_L_X_PORTRAIT, R.integer.BUTTON_L_Y_PORTRAIT), | ||
| 78 | Pair(R.integer.BUTTON_L_X_FOLDABLE, R.integer.BUTTON_L_Y_FOLDABLE) | ||
| 79 | ), | ||
| 80 | BUTTON_R( | ||
| 81 | "button_r", | ||
| 82 | true, | ||
| 83 | Pair(R.integer.BUTTON_R_X, R.integer.BUTTON_R_Y), | ||
| 84 | Pair(R.integer.BUTTON_R_X_PORTRAIT, R.integer.BUTTON_R_Y_PORTRAIT), | ||
| 85 | Pair(R.integer.BUTTON_R_X_FOLDABLE, R.integer.BUTTON_R_Y_FOLDABLE) | ||
| 86 | ), | ||
| 87 | BUTTON_ZL( | ||
| 88 | "button_zl", | ||
| 89 | true, | ||
| 90 | Pair(R.integer.BUTTON_ZL_X, R.integer.BUTTON_ZL_Y), | ||
| 91 | Pair(R.integer.BUTTON_ZL_X_PORTRAIT, R.integer.BUTTON_ZL_Y_PORTRAIT), | ||
| 92 | Pair(R.integer.BUTTON_ZL_X_FOLDABLE, R.integer.BUTTON_ZL_Y_FOLDABLE) | ||
| 93 | ), | ||
| 94 | BUTTON_ZR( | ||
| 95 | "button_zr", | ||
| 96 | true, | ||
| 97 | Pair(R.integer.BUTTON_ZR_X, R.integer.BUTTON_ZR_Y), | ||
| 98 | Pair(R.integer.BUTTON_ZR_X_PORTRAIT, R.integer.BUTTON_ZR_Y_PORTRAIT), | ||
| 99 | Pair(R.integer.BUTTON_ZR_X_FOLDABLE, R.integer.BUTTON_ZR_Y_FOLDABLE) | ||
| 100 | ), | ||
| 101 | BUTTON_STICK_L( | ||
| 102 | "button_stick_l", | ||
| 103 | true, | ||
| 104 | Pair(R.integer.BUTTON_STICK_L_X, R.integer.BUTTON_STICK_L_Y), | ||
| 105 | Pair(R.integer.BUTTON_STICK_L_X_PORTRAIT, R.integer.BUTTON_STICK_L_Y_PORTRAIT), | ||
| 106 | Pair(R.integer.BUTTON_STICK_L_X_FOLDABLE, R.integer.BUTTON_STICK_L_Y_FOLDABLE) | ||
| 107 | ), | ||
| 108 | BUTTON_STICK_R( | ||
| 109 | "button_stick_r", | ||
| 110 | true, | ||
| 111 | Pair(R.integer.BUTTON_STICK_R_X, R.integer.BUTTON_STICK_R_Y), | ||
| 112 | Pair(R.integer.BUTTON_STICK_R_X_PORTRAIT, R.integer.BUTTON_STICK_R_Y_PORTRAIT), | ||
| 113 | Pair(R.integer.BUTTON_STICK_R_X_FOLDABLE, R.integer.BUTTON_STICK_R_Y_FOLDABLE) | ||
| 114 | ), | ||
| 115 | STICK_L( | ||
| 116 | "stick_l", | ||
| 117 | true, | ||
| 118 | Pair(R.integer.STICK_L_X, R.integer.STICK_L_Y), | ||
| 119 | Pair(R.integer.STICK_L_X_PORTRAIT, R.integer.STICK_L_Y_PORTRAIT), | ||
| 120 | Pair(R.integer.STICK_L_X_FOLDABLE, R.integer.STICK_L_Y_FOLDABLE) | ||
| 121 | ), | ||
| 122 | STICK_R( | ||
| 123 | "stick_r", | ||
| 124 | true, | ||
| 125 | Pair(R.integer.STICK_R_X, R.integer.STICK_R_Y), | ||
| 126 | Pair(R.integer.STICK_R_X_PORTRAIT, R.integer.STICK_R_Y_PORTRAIT), | ||
| 127 | Pair(R.integer.STICK_R_X_FOLDABLE, R.integer.STICK_R_Y_FOLDABLE) | ||
| 128 | ), | ||
| 129 | COMBINED_DPAD( | ||
| 130 | "combined_dpad", | ||
| 131 | true, | ||
| 132 | Pair(R.integer.COMBINED_DPAD_X, R.integer.COMBINED_DPAD_Y), | ||
| 133 | Pair(R.integer.COMBINED_DPAD_X_PORTRAIT, R.integer.COMBINED_DPAD_Y_PORTRAIT), | ||
| 134 | Pair(R.integer.COMBINED_DPAD_X_FOLDABLE, R.integer.COMBINED_DPAD_Y_FOLDABLE) | ||
| 135 | ); | ||
| 136 | |||
| 137 | fun getDefaultPositionForLayout(layout: OverlayLayout): Pair<Double, Double> { | ||
| 138 | val rawResourcePair: Pair<Int, Int> | ||
| 139 | YuzuApplication.appContext.resources.apply { | ||
| 140 | rawResourcePair = when (layout) { | ||
| 141 | OverlayLayout.Landscape -> { | ||
| 142 | Pair( | ||
| 143 | getInteger(this@OverlayControl.defaultLandscapePositionResources.first), | ||
| 144 | getInteger(this@OverlayControl.defaultLandscapePositionResources.second) | ||
| 145 | ) | ||
| 146 | } | ||
| 147 | |||
| 148 | OverlayLayout.Portrait -> { | ||
| 149 | Pair( | ||
| 150 | getInteger(this@OverlayControl.defaultPortraitPositionResources.first), | ||
| 151 | getInteger(this@OverlayControl.defaultPortraitPositionResources.second) | ||
| 152 | ) | ||
| 153 | } | ||
| 154 | |||
| 155 | OverlayLayout.Foldable -> { | ||
| 156 | Pair( | ||
| 157 | getInteger(this@OverlayControl.defaultFoldablePositionResources.first), | ||
| 158 | getInteger(this@OverlayControl.defaultFoldablePositionResources.second) | ||
| 159 | ) | ||
| 160 | } | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | return Pair( | ||
| 165 | rawResourcePair.first.toDouble() / 1000, | ||
| 166 | rawResourcePair.second.toDouble() / 1000 | ||
| 167 | ) | ||
| 168 | } | ||
| 169 | |||
| 170 | fun toOverlayControlData(): OverlayControlData = | ||
| 171 | OverlayControlData( | ||
| 172 | id, | ||
| 173 | defaultVisibility, | ||
| 174 | getDefaultPositionForLayout(OverlayLayout.Landscape), | ||
| 175 | getDefaultPositionForLayout(OverlayLayout.Portrait), | ||
| 176 | getDefaultPositionForLayout(OverlayLayout.Foldable) | ||
| 177 | ) | ||
| 178 | |||
| 179 | companion object { | ||
| 180 | val map: HashMap<String, OverlayControl> by lazy { | ||
| 181 | val hashMap = hashMapOf<String, OverlayControl>() | ||
| 182 | entries.forEach { hashMap[it.id] = it } | ||
| 183 | hashMap | ||
| 184 | } | ||
| 185 | |||
| 186 | fun from(id: String): OverlayControl? = map[id] | ||
| 187 | } | ||
| 188 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControlData.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControlData.kt new file mode 100644 index 000000000..26cfeb1db --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControlData.kt | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.overlay.model | ||
| 5 | |||
| 6 | data class OverlayControlData( | ||
| 7 | val id: String, | ||
| 8 | var enabled: Boolean, | ||
| 9 | var landscapePosition: Pair<Double, Double>, | ||
| 10 | var portraitPosition: Pair<Double, Double>, | ||
| 11 | var foldablePosition: Pair<Double, Double> | ||
| 12 | ) { | ||
| 13 | fun positionFromLayout(layout: OverlayLayout): Pair<Double, Double> = | ||
| 14 | when (layout) { | ||
| 15 | OverlayLayout.Landscape -> landscapePosition | ||
| 16 | OverlayLayout.Portrait -> portraitPosition | ||
| 17 | OverlayLayout.Foldable -> foldablePosition | ||
| 18 | } | ||
| 19 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControlDefault.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControlDefault.kt new file mode 100644 index 000000000..6bd74c82f --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayControlDefault.kt | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.overlay.model | ||
| 5 | |||
| 6 | import androidx.annotation.IntegerRes | ||
| 7 | |||
| 8 | data class OverlayControlDefault( | ||
| 9 | val buttonId: String, | ||
| 10 | @IntegerRes val landscapePositionResource: Pair<Int, Int>, | ||
| 11 | @IntegerRes val portraitPositionResource: Pair<Int, Int>, | ||
| 12 | @IntegerRes val foldablePositionResource: Pair<Int, Int> | ||
| 13 | ) | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayLayout.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayLayout.kt new file mode 100644 index 000000000..d728164e5 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/model/OverlayLayout.kt | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.overlay.model | ||
| 5 | |||
| 6 | enum class OverlayLayout(val id: String) { | ||
| 7 | Landscape("Landscape"), | ||
| 8 | Portrait("Portrait"), | ||
| 9 | Foldable("Foldable") | ||
| 10 | } | ||
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 0197fd712..de0794a17 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 | |||
| @@ -3,9 +3,17 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.utils | 4 | package org.yuzu.yuzu_emu.utils |
| 5 | 5 | ||
| 6 | import androidx.preference.PreferenceManager | ||
| 6 | import java.io.IOException | 7 | import java.io.IOException |
| 7 | import org.yuzu.yuzu_emu.NativeLibrary | 8 | import org.yuzu.yuzu_emu.NativeLibrary |
| 8 | import org.yuzu.yuzu_emu.YuzuApplication | 9 | import org.yuzu.yuzu_emu.YuzuApplication |
| 10 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting | ||
| 11 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting | ||
| 12 | import org.yuzu.yuzu_emu.features.settings.model.Settings | ||
| 13 | import org.yuzu.yuzu_emu.overlay.model.OverlayControlData | ||
| 14 | import org.yuzu.yuzu_emu.overlay.model.OverlayControl | ||
| 15 | import org.yuzu.yuzu_emu.overlay.model.OverlayLayout | ||
| 16 | import org.yuzu.yuzu_emu.utils.PreferenceUtil.migratePreference | ||
| 9 | 17 | ||
| 10 | object DirectoryInitialization { | 18 | object DirectoryInitialization { |
| 11 | private var userPath: String? = null | 19 | private var userPath: String? = null |
| @@ -17,6 +25,7 @@ object DirectoryInitialization { | |||
| 17 | initializeInternalStorage() | 25 | initializeInternalStorage() |
| 18 | NativeLibrary.initializeSystem(false) | 26 | NativeLibrary.initializeSystem(false) |
| 19 | NativeConfig.initializeGlobalConfig() | 27 | NativeConfig.initializeGlobalConfig() |
| 28 | migrateSettings() | ||
| 20 | areDirectoriesReady = true | 29 | areDirectoriesReady = true |
| 21 | } | 30 | } |
| 22 | } | 31 | } |
| @@ -35,4 +44,170 @@ object DirectoryInitialization { | |||
| 35 | e.printStackTrace() | 44 | e.printStackTrace() |
| 36 | } | 45 | } |
| 37 | } | 46 | } |
| 47 | |||
| 48 | private fun migrateSettings() { | ||
| 49 | val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||
| 50 | var saveConfig = false | ||
| 51 | val theme = preferences.migratePreference<Int>(Settings.PREF_THEME) | ||
| 52 | if (theme != null) { | ||
| 53 | IntSetting.THEME.setInt(theme) | ||
| 54 | saveConfig = true | ||
| 55 | } | ||
| 56 | |||
| 57 | val themeMode = preferences.migratePreference<Int>(Settings.PREF_THEME_MODE) | ||
| 58 | if (themeMode != null) { | ||
| 59 | IntSetting.THEME_MODE.setInt(themeMode) | ||
| 60 | saveConfig = true | ||
| 61 | } | ||
| 62 | |||
| 63 | val blackBackgrounds = | ||
| 64 | preferences.migratePreference<Boolean>(Settings.PREF_BLACK_BACKGROUNDS) | ||
| 65 | if (blackBackgrounds != null) { | ||
| 66 | BooleanSetting.BLACK_BACKGROUNDS.setBoolean(blackBackgrounds) | ||
| 67 | saveConfig = true | ||
| 68 | } | ||
| 69 | |||
| 70 | val joystickRelCenter = | ||
| 71 | preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER) | ||
| 72 | if (joystickRelCenter != null) { | ||
| 73 | BooleanSetting.JOYSTICK_REL_CENTER.setBoolean(joystickRelCenter) | ||
| 74 | saveConfig = true | ||
| 75 | } | ||
| 76 | |||
| 77 | val dpadSlide = | ||
| 78 | preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_DPAD_SLIDE) | ||
| 79 | if (dpadSlide != null) { | ||
| 80 | BooleanSetting.DPAD_SLIDE.setBoolean(dpadSlide) | ||
| 81 | saveConfig = true | ||
| 82 | } | ||
| 83 | |||
| 84 | val hapticFeedback = | ||
| 85 | preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_HAPTICS) | ||
| 86 | if (hapticFeedback != null) { | ||
| 87 | BooleanSetting.HAPTIC_FEEDBACK.setBoolean(hapticFeedback) | ||
| 88 | saveConfig = true | ||
| 89 | } | ||
| 90 | |||
| 91 | val showPerformanceOverlay = | ||
| 92 | preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_SHOW_FPS) | ||
| 93 | if (showPerformanceOverlay != null) { | ||
| 94 | BooleanSetting.SHOW_PERFORMANCE_OVERLAY.setBoolean(showPerformanceOverlay) | ||
| 95 | saveConfig = true | ||
| 96 | } | ||
| 97 | |||
| 98 | val showInputOverlay = | ||
| 99 | preferences.migratePreference<Boolean>(Settings.PREF_MENU_SETTINGS_SHOW_OVERLAY) | ||
| 100 | if (showInputOverlay != null) { | ||
| 101 | BooleanSetting.SHOW_INPUT_OVERLAY.setBoolean(showInputOverlay) | ||
| 102 | saveConfig = true | ||
| 103 | } | ||
| 104 | |||
| 105 | val overlayOpacity = preferences.migratePreference<Int>(Settings.PREF_CONTROL_OPACITY) | ||
| 106 | if (overlayOpacity != null) { | ||
| 107 | IntSetting.OVERLAY_OPACITY.setInt(overlayOpacity) | ||
| 108 | saveConfig = true | ||
| 109 | } | ||
| 110 | |||
| 111 | val overlayScale = preferences.migratePreference<Int>(Settings.PREF_CONTROL_SCALE) | ||
| 112 | if (overlayScale != null) { | ||
| 113 | IntSetting.OVERLAY_SCALE.setInt(overlayScale) | ||
| 114 | saveConfig = true | ||
| 115 | } | ||
| 116 | |||
| 117 | var setOverlayData = false | ||
| 118 | val overlayControlData = NativeConfig.getOverlayControlData() | ||
| 119 | if (overlayControlData.isEmpty()) { | ||
| 120 | val overlayControlDataMap = | ||
| 121 | NativeConfig.getOverlayControlData().associateBy { it.id }.toMutableMap() | ||
| 122 | for (button in Settings.overlayPreferences) { | ||
| 123 | val buttonId = convertButtonId(button) | ||
| 124 | var buttonEnabled = preferences.migratePreference<Boolean>(button) | ||
| 125 | if (buttonEnabled == null) { | ||
| 126 | buttonEnabled = OverlayControl.map[buttonId]?.defaultVisibility == true | ||
| 127 | } | ||
| 128 | |||
| 129 | var landscapeXPosition = preferences.migratePreference<Float>( | ||
| 130 | "$button-X${Settings.PREF_LANDSCAPE_SUFFIX}" | ||
| 131 | )?.toDouble() | ||
| 132 | var landscapeYPosition = preferences.migratePreference<Float>( | ||
| 133 | "$button-Y${Settings.PREF_LANDSCAPE_SUFFIX}" | ||
| 134 | )?.toDouble() | ||
| 135 | if (landscapeXPosition == null || landscapeYPosition == null) { | ||
| 136 | val landscapePosition = OverlayControl.map[buttonId] | ||
| 137 | ?.getDefaultPositionForLayout(OverlayLayout.Landscape) ?: Pair(0.0, 0.0) | ||
| 138 | landscapeXPosition = landscapePosition.first | ||
| 139 | landscapeYPosition = landscapePosition.second | ||
| 140 | } | ||
| 141 | |||
| 142 | var portraitXPosition = preferences.migratePreference<Float>( | ||
| 143 | "$button-X${Settings.PREF_PORTRAIT_SUFFIX}" | ||
| 144 | )?.toDouble() | ||
| 145 | var portraitYPosition = preferences.migratePreference<Float>( | ||
| 146 | "$button-Y${Settings.PREF_PORTRAIT_SUFFIX}" | ||
| 147 | )?.toDouble() | ||
| 148 | if (portraitXPosition == null || portraitYPosition == null) { | ||
| 149 | val portraitPosition = OverlayControl.map[buttonId] | ||
| 150 | ?.getDefaultPositionForLayout(OverlayLayout.Portrait) ?: Pair(0.0, 0.0) | ||
| 151 | portraitXPosition = portraitPosition.first | ||
| 152 | portraitYPosition = portraitPosition.second | ||
| 153 | } | ||
| 154 | |||
| 155 | var foldableXPosition = preferences.migratePreference<Float>( | ||
| 156 | "$button-X${Settings.PREF_FOLDABLE_SUFFIX}" | ||
| 157 | )?.toDouble() | ||
| 158 | var foldableYPosition = preferences.migratePreference<Float>( | ||
| 159 | "$button-Y${Settings.PREF_FOLDABLE_SUFFIX}" | ||
| 160 | )?.toDouble() | ||
| 161 | if (foldableXPosition == null || foldableYPosition == null) { | ||
| 162 | val foldablePosition = OverlayControl.map[buttonId] | ||
| 163 | ?.getDefaultPositionForLayout(OverlayLayout.Foldable) ?: Pair(0.0, 0.0) | ||
| 164 | foldableXPosition = foldablePosition.first | ||
| 165 | foldableYPosition = foldablePosition.second | ||
| 166 | } | ||
| 167 | |||
| 168 | val controlData = OverlayControlData( | ||
| 169 | buttonId, | ||
| 170 | buttonEnabled, | ||
| 171 | Pair(landscapeXPosition, landscapeYPosition), | ||
| 172 | Pair(portraitXPosition, portraitYPosition), | ||
| 173 | Pair(foldableXPosition, foldableYPosition) | ||
| 174 | ) | ||
| 175 | overlayControlDataMap[buttonId] = controlData | ||
| 176 | setOverlayData = true | ||
| 177 | } | ||
| 178 | |||
| 179 | if (setOverlayData) { | ||
| 180 | NativeConfig.setOverlayControlData( | ||
| 181 | overlayControlDataMap.map { it.value }.toTypedArray() | ||
| 182 | ) | ||
| 183 | saveConfig = true | ||
| 184 | } | ||
| 185 | } | ||
| 186 | |||
| 187 | if (saveConfig) { | ||
| 188 | NativeConfig.saveGlobalConfig() | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | private fun convertButtonId(buttonId: String): String = | ||
| 193 | when (buttonId) { | ||
| 194 | Settings.PREF_BUTTON_A -> OverlayControl.BUTTON_A.id | ||
| 195 | Settings.PREF_BUTTON_B -> OverlayControl.BUTTON_B.id | ||
| 196 | Settings.PREF_BUTTON_X -> OverlayControl.BUTTON_X.id | ||
| 197 | Settings.PREF_BUTTON_Y -> OverlayControl.BUTTON_Y.id | ||
| 198 | Settings.PREF_BUTTON_L -> OverlayControl.BUTTON_L.id | ||
| 199 | Settings.PREF_BUTTON_R -> OverlayControl.BUTTON_R.id | ||
| 200 | Settings.PREF_BUTTON_ZL -> OverlayControl.BUTTON_ZL.id | ||
| 201 | Settings.PREF_BUTTON_ZR -> OverlayControl.BUTTON_ZR.id | ||
| 202 | Settings.PREF_BUTTON_PLUS -> OverlayControl.BUTTON_PLUS.id | ||
| 203 | Settings.PREF_BUTTON_MINUS -> OverlayControl.BUTTON_MINUS.id | ||
| 204 | Settings.PREF_BUTTON_DPAD -> OverlayControl.COMBINED_DPAD.id | ||
| 205 | Settings.PREF_STICK_L -> OverlayControl.STICK_L.id | ||
| 206 | Settings.PREF_STICK_R -> OverlayControl.STICK_R.id | ||
| 207 | Settings.PREF_BUTTON_HOME -> OverlayControl.BUTTON_HOME.id | ||
| 208 | Settings.PREF_BUTTON_SCREENSHOT -> OverlayControl.BUTTON_CAPTURE.id | ||
| 209 | Settings.PREF_BUTTON_STICK_L -> OverlayControl.BUTTON_STICK_L.id | ||
| 210 | Settings.PREF_BUTTON_STICK_R -> OverlayControl.BUTTON_STICK_R.id | ||
| 211 | else -> "" | ||
| 212 | } | ||
| 38 | } | 213 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/EmulationMenuSettings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/EmulationMenuSettings.kt deleted file mode 100644 index 7e8f058c1..000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/EmulationMenuSettings.kt +++ /dev/null | |||
| @@ -1,50 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.utils | ||
| 5 | |||
| 6 | import androidx.preference.PreferenceManager | ||
| 7 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 8 | import org.yuzu.yuzu_emu.features.settings.model.Settings | ||
| 9 | |||
| 10 | object EmulationMenuSettings { | ||
| 11 | private val preferences = | ||
| 12 | PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||
| 13 | |||
| 14 | var joystickRelCenter: Boolean | ||
| 15 | get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER, true) | ||
| 16 | set(value) { | ||
| 17 | preferences.edit() | ||
| 18 | .putBoolean(Settings.PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER, value) | ||
| 19 | .apply() | ||
| 20 | } | ||
| 21 | var dpadSlide: Boolean | ||
| 22 | get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_DPAD_SLIDE, true) | ||
| 23 | set(value) { | ||
| 24 | preferences.edit() | ||
| 25 | .putBoolean(Settings.PREF_MENU_SETTINGS_DPAD_SLIDE, value) | ||
| 26 | .apply() | ||
| 27 | } | ||
| 28 | var hapticFeedback: Boolean | ||
| 29 | get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_HAPTICS, false) | ||
| 30 | set(value) { | ||
| 31 | preferences.edit() | ||
| 32 | .putBoolean(Settings.PREF_MENU_SETTINGS_HAPTICS, value) | ||
| 33 | .apply() | ||
| 34 | } | ||
| 35 | |||
| 36 | var showFps: Boolean | ||
| 37 | get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_SHOW_FPS, false) | ||
| 38 | set(value) { | ||
| 39 | preferences.edit() | ||
| 40 | .putBoolean(Settings.PREF_MENU_SETTINGS_SHOW_FPS, value) | ||
| 41 | .apply() | ||
| 42 | } | ||
| 43 | var showOverlay: Boolean | ||
| 44 | get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_SHOW_OVERLAY, true) | ||
| 45 | set(value) { | ||
| 46 | preferences.edit() | ||
| 47 | .putBoolean(Settings.PREF_MENU_SETTINGS_SHOW_OVERLAY, value) | ||
| 48 | .apply() | ||
| 49 | } | ||
| 50 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt index 7512d5eed..a4c14b3a7 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | package org.yuzu.yuzu_emu.utils | 4 | package org.yuzu.yuzu_emu.utils |
| 5 | 5 | ||
| 6 | import org.yuzu.yuzu_emu.model.GameDir | 6 | import org.yuzu.yuzu_emu.model.GameDir |
| 7 | import org.yuzu.yuzu_emu.overlay.model.OverlayControlData | ||
| 7 | 8 | ||
| 8 | object NativeConfig { | 9 | object NativeConfig { |
| 9 | /** | 10 | /** |
| @@ -150,4 +151,21 @@ object NativeConfig { | |||
| 150 | */ | 151 | */ |
| 151 | @Synchronized | 152 | @Synchronized |
| 152 | external fun setDisabledAddons(programId: String, disabledAddons: Array<String>) | 153 | external fun setDisabledAddons(programId: String, disabledAddons: Array<String>) |
| 154 | |||
| 155 | /** | ||
| 156 | * Gets an array of [OverlayControlData] from settings | ||
| 157 | * | ||
| 158 | * @return An array of [OverlayControlData] | ||
| 159 | */ | ||
| 160 | @Synchronized | ||
| 161 | external fun getOverlayControlData(): Array<OverlayControlData> | ||
| 162 | |||
| 163 | /** | ||
| 164 | * Clears the AndroidSettings::values.overlay_control_data array and replaces its values | ||
| 165 | * with [overlayControlData] | ||
| 166 | * | ||
| 167 | * @param overlayControlData Replacement array of [OverlayControlData] | ||
| 168 | */ | ||
| 169 | @Synchronized | ||
| 170 | external fun setOverlayControlData(overlayControlData: Array<OverlayControlData>) | ||
| 153 | } | 171 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PreferenceUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PreferenceUtil.kt new file mode 100644 index 000000000..a233ba25c --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PreferenceUtil.kt | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.utils | ||
| 5 | |||
| 6 | import android.content.SharedPreferences | ||
| 7 | |||
| 8 | object PreferenceUtil { | ||
| 9 | /** | ||
| 10 | * Retrieves a shared preference value and then deletes the value in storage. | ||
| 11 | * @param key Associated key for the value in this preferences instance | ||
| 12 | * @return Typed value associated with [key]. Null if no such key exists. | ||
| 13 | */ | ||
| 14 | inline fun <reified T> SharedPreferences.migratePreference(key: String): T? { | ||
| 15 | if (!this.contains(key)) { | ||
| 16 | return null | ||
| 17 | } | ||
| 18 | |||
| 19 | val value: Any = when (T::class) { | ||
| 20 | String::class -> this.getString(key, "")!! | ||
| 21 | |||
| 22 | Boolean::class -> this.getBoolean(key, false) | ||
| 23 | |||
| 24 | Int::class -> this.getInt(key, 0) | ||
| 25 | |||
| 26 | Float::class -> this.getFloat(key, 0f) | ||
| 27 | |||
| 28 | Long::class -> this.getLong(key, 0) | ||
| 29 | |||
| 30 | else -> throw IllegalStateException("Tried to migrate preference with invalid type!") | ||
| 31 | } | ||
| 32 | deletePreference(key) | ||
| 33 | return value as T | ||
| 34 | } | ||
| 35 | |||
| 36 | fun SharedPreferences.deletePreference(key: String) = this.edit().remove(key).apply() | ||
| 37 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ThemeHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ThemeHelper.kt index f312e24cf..6f7f40e43 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ThemeHelper.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ThemeHelper.kt | |||
| @@ -5,38 +5,38 @@ package org.yuzu.yuzu_emu.utils | |||
| 5 | 5 | ||
| 6 | import android.content.res.Configuration | 6 | import android.content.res.Configuration |
| 7 | import android.graphics.Color | 7 | import android.graphics.Color |
| 8 | import android.os.Build | ||
| 8 | import androidx.annotation.ColorInt | 9 | import androidx.annotation.ColorInt |
| 9 | import androidx.appcompat.app.AppCompatActivity | 10 | import androidx.appcompat.app.AppCompatActivity |
| 10 | import androidx.appcompat.app.AppCompatDelegate | 11 | import androidx.appcompat.app.AppCompatDelegate |
| 11 | import androidx.core.view.WindowCompat | 12 | import androidx.core.view.WindowCompat |
| 12 | import androidx.core.view.WindowInsetsControllerCompat | 13 | import androidx.core.view.WindowInsetsControllerCompat |
| 13 | import androidx.preference.PreferenceManager | ||
| 14 | import kotlin.math.roundToInt | 14 | import kotlin.math.roundToInt |
| 15 | import org.yuzu.yuzu_emu.R | 15 | import org.yuzu.yuzu_emu.R |
| 16 | import org.yuzu.yuzu_emu.YuzuApplication | 16 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting |
| 17 | import org.yuzu.yuzu_emu.features.settings.model.Settings | 17 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting |
| 18 | import org.yuzu.yuzu_emu.ui.main.ThemeProvider | 18 | import org.yuzu.yuzu_emu.ui.main.ThemeProvider |
| 19 | 19 | ||
| 20 | object ThemeHelper { | 20 | object ThemeHelper { |
| 21 | const val SYSTEM_BAR_ALPHA = 0.9f | 21 | const val SYSTEM_BAR_ALPHA = 0.9f |
| 22 | 22 | ||
| 23 | private const val DEFAULT = 0 | ||
| 24 | private const val MATERIAL_YOU = 1 | ||
| 25 | |||
| 26 | fun setTheme(activity: AppCompatActivity) { | 23 | fun setTheme(activity: AppCompatActivity) { |
| 27 | val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||
| 28 | setThemeMode(activity) | 24 | setThemeMode(activity) |
| 29 | when (preferences.getInt(Settings.PREF_THEME, 0)) { | 25 | when (Theme.from(IntSetting.THEME.getInt())) { |
| 30 | DEFAULT -> activity.setTheme(R.style.Theme_Yuzu_Main) | 26 | Theme.Default -> activity.setTheme(R.style.Theme_Yuzu_Main) |
| 31 | MATERIAL_YOU -> activity.setTheme(R.style.Theme_Yuzu_Main_MaterialYou) | 27 | Theme.MaterialYou -> { |
| 28 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { | ||
| 29 | activity.setTheme(R.style.Theme_Yuzu_Main_MaterialYou) | ||
| 30 | } else { | ||
| 31 | activity.setTheme(R.style.Theme_Yuzu_Main) | ||
| 32 | } | ||
| 33 | } | ||
| 32 | } | 34 | } |
| 33 | 35 | ||
| 34 | // Using a specific night mode check because this could apply incorrectly when using the | 36 | // Using a specific night mode check because this could apply incorrectly when using the |
| 35 | // light app mode, dark system mode, and black backgrounds. Launching the settings activity | 37 | // light app mode, dark system mode, and black backgrounds. Launching the settings activity |
| 36 | // will then show light mode colors/navigation bars but with black backgrounds. | 38 | // will then show light mode colors/navigation bars but with black backgrounds. |
| 37 | if (preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false) && | 39 | if (BooleanSetting.BLACK_BACKGROUNDS.getBoolean() && isNightMode(activity)) { |
| 38 | isNightMode(activity) | ||
| 39 | ) { | ||
| 40 | activity.setTheme(R.style.ThemeOverlay_Yuzu_Dark) | 40 | activity.setTheme(R.style.ThemeOverlay_Yuzu_Dark) |
| 41 | } | 41 | } |
| 42 | } | 42 | } |
| @@ -60,8 +60,7 @@ object ThemeHelper { | |||
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | fun setThemeMode(activity: AppCompatActivity) { | 62 | fun setThemeMode(activity: AppCompatActivity) { |
| 63 | val themeMode = PreferenceManager.getDefaultSharedPreferences(activity.applicationContext) | 63 | val themeMode = IntSetting.THEME_MODE.getInt() |
| 64 | .getInt(Settings.PREF_THEME_MODE, AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) | ||
| 65 | activity.delegate.localNightMode = themeMode | 64 | activity.delegate.localNightMode = themeMode |
| 66 | val windowController = WindowCompat.getInsetsController( | 65 | val windowController = WindowCompat.getInsetsController( |
| 67 | activity.window, | 66 | activity.window, |
| @@ -95,3 +94,12 @@ object ThemeHelper { | |||
| 95 | windowController.isAppearanceLightNavigationBars = false | 94 | windowController.isAppearanceLightNavigationBars = false |
| 96 | } | 95 | } |
| 97 | } | 96 | } |
| 97 | |||
| 98 | enum class Theme(val int: Int) { | ||
| 99 | Default(0), | ||
| 100 | MaterialYou(1); | ||
| 101 | |||
| 102 | companion object { | ||
| 103 | fun from(int: Int): Theme = entries.firstOrNull { it.int == int } ?: Default | ||
| 104 | } | ||
| 105 | } | ||
diff --git a/src/android/app/src/main/jni/android_common/android_common.cpp b/src/android/app/src/main/jni/android_common/android_common.cpp index 52d8ecfeb..1e884ffdd 100644 --- a/src/android/app/src/main/jni/android_common/android_common.cpp +++ b/src/android/app/src/main/jni/android_common/android_common.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <jni.h> | 9 | #include <jni.h> |
| 10 | 10 | ||
| 11 | #include "common/string_util.h" | 11 | #include "common/string_util.h" |
| 12 | #include "jni/id_cache.h" | ||
| 12 | 13 | ||
| 13 | std::string GetJString(JNIEnv* env, jstring jstr) { | 14 | std::string GetJString(JNIEnv* env, jstring jstr) { |
| 14 | if (!jstr) { | 15 | if (!jstr) { |
| @@ -33,3 +34,11 @@ jstring ToJString(JNIEnv* env, std::string_view str) { | |||
| 33 | jstring ToJString(JNIEnv* env, std::u16string_view str) { | 34 | jstring ToJString(JNIEnv* env, std::u16string_view str) { |
| 34 | return ToJString(env, Common::UTF16ToUTF8(str)); | 35 | return ToJString(env, Common::UTF16ToUTF8(str)); |
| 35 | } | 36 | } |
| 37 | |||
| 38 | double GetJDouble(JNIEnv* env, jobject jdouble) { | ||
| 39 | return env->GetDoubleField(jdouble, IDCache::GetDoubleValueField()); | ||
| 40 | } | ||
| 41 | |||
| 42 | jobject ToJDouble(JNIEnv* env, double value) { | ||
| 43 | return env->NewObject(IDCache::GetDoubleClass(), IDCache::GetDoubleConstructor(), value); | ||
| 44 | } | ||
diff --git a/src/android/app/src/main/jni/android_common/android_common.h b/src/android/app/src/main/jni/android_common/android_common.h index ccb0c06f7..8eb803e1b 100644 --- a/src/android/app/src/main/jni/android_common/android_common.h +++ b/src/android/app/src/main/jni/android_common/android_common.h | |||
| @@ -10,3 +10,6 @@ | |||
| 10 | std::string GetJString(JNIEnv* env, jstring jstr); | 10 | std::string GetJString(JNIEnv* env, jstring jstr); |
| 11 | jstring ToJString(JNIEnv* env, std::string_view str); | 11 | jstring ToJString(JNIEnv* env, std::string_view str); |
| 12 | jstring ToJString(JNIEnv* env, std::u16string_view str); | 12 | jstring ToJString(JNIEnv* env, std::u16string_view str); |
| 13 | |||
| 14 | double GetJDouble(JNIEnv* env, jobject jdouble); | ||
| 15 | jobject ToJDouble(JNIEnv* env, double value); | ||
diff --git a/src/android/app/src/main/jni/android_config.cpp b/src/android/app/src/main/jni/android_config.cpp index 9c3a5a9b2..c86aa1c39 100644 --- a/src/android/app/src/main/jni/android_config.cpp +++ b/src/android/app/src/main/jni/android_config.cpp | |||
| @@ -35,6 +35,7 @@ void AndroidConfig::ReadAndroidValues() { | |||
| 35 | if (global) { | 35 | if (global) { |
| 36 | ReadAndroidUIValues(); | 36 | ReadAndroidUIValues(); |
| 37 | ReadUIValues(); | 37 | ReadUIValues(); |
| 38 | ReadOverlayValues(); | ||
| 38 | } | 39 | } |
| 39 | ReadDriverValues(); | 40 | ReadDriverValues(); |
| 40 | } | 41 | } |
| @@ -81,10 +82,42 @@ void AndroidConfig::ReadDriverValues() { | |||
| 81 | EndGroup(); | 82 | EndGroup(); |
| 82 | } | 83 | } |
| 83 | 84 | ||
| 85 | void AndroidConfig::ReadOverlayValues() { | ||
| 86 | BeginGroup(Settings::TranslateCategory(Settings::Category::Overlay)); | ||
| 87 | |||
| 88 | ReadCategory(Settings::Category::Overlay); | ||
| 89 | |||
| 90 | AndroidSettings::values.overlay_control_data.clear(); | ||
| 91 | const int control_data_size = BeginArray("control_data"); | ||
| 92 | for (int i = 0; i < control_data_size; ++i) { | ||
| 93 | SetArrayIndex(i); | ||
| 94 | AndroidSettings::OverlayControlData control_data; | ||
| 95 | control_data.id = ReadStringSetting(std::string("id")); | ||
| 96 | control_data.enabled = ReadBooleanSetting(std::string("enabled")); | ||
| 97 | control_data.landscape_position.first = | ||
| 98 | ReadDoubleSetting(std::string("landscape\\x_position")); | ||
| 99 | control_data.landscape_position.second = | ||
| 100 | ReadDoubleSetting(std::string("landscape\\y_position")); | ||
| 101 | control_data.portrait_position.first = | ||
| 102 | ReadDoubleSetting(std::string("portrait\\x_position")); | ||
| 103 | control_data.portrait_position.second = | ||
| 104 | ReadDoubleSetting(std::string("portrait\\y_position")); | ||
| 105 | control_data.foldable_position.first = | ||
| 106 | ReadDoubleSetting(std::string("foldable\\x_position")); | ||
| 107 | control_data.foldable_position.second = | ||
| 108 | ReadDoubleSetting(std::string("foldable\\y_position")); | ||
| 109 | AndroidSettings::values.overlay_control_data.push_back(control_data); | ||
| 110 | } | ||
| 111 | EndArray(); | ||
| 112 | |||
| 113 | EndGroup(); | ||
| 114 | } | ||
| 115 | |||
| 84 | void AndroidConfig::SaveAndroidValues() { | 116 | void AndroidConfig::SaveAndroidValues() { |
| 85 | if (global) { | 117 | if (global) { |
| 86 | SaveAndroidUIValues(); | 118 | SaveAndroidUIValues(); |
| 87 | SaveUIValues(); | 119 | SaveUIValues(); |
| 120 | SaveOverlayValues(); | ||
| 88 | } | 121 | } |
| 89 | SaveDriverValues(); | 122 | SaveDriverValues(); |
| 90 | 123 | ||
| @@ -114,8 +147,9 @@ void AndroidConfig::SavePathValues() { | |||
| 114 | for (size_t i = 0; i < AndroidSettings::values.game_dirs.size(); ++i) { | 147 | for (size_t i = 0; i < AndroidSettings::values.game_dirs.size(); ++i) { |
| 115 | SetArrayIndex(i); | 148 | SetArrayIndex(i); |
| 116 | const auto& game_dir = AndroidSettings::values.game_dirs[i]; | 149 | const auto& game_dir = AndroidSettings::values.game_dirs[i]; |
| 117 | WriteSetting(std::string("path"), game_dir.path); | 150 | WriteStringSetting(std::string("path"), game_dir.path); |
| 118 | WriteSetting(std::string("deep_scan"), game_dir.deep_scan, std::make_optional(false)); | 151 | WriteBooleanSetting(std::string("deep_scan"), game_dir.deep_scan, |
| 152 | std::make_optional(false)); | ||
| 119 | } | 153 | } |
| 120 | EndArray(); | 154 | EndArray(); |
| 121 | 155 | ||
| @@ -130,6 +164,35 @@ void AndroidConfig::SaveDriverValues() { | |||
| 130 | EndGroup(); | 164 | EndGroup(); |
| 131 | } | 165 | } |
| 132 | 166 | ||
| 167 | void AndroidConfig::SaveOverlayValues() { | ||
| 168 | BeginGroup(Settings::TranslateCategory(Settings::Category::Overlay)); | ||
| 169 | |||
| 170 | WriteCategory(Settings::Category::Overlay); | ||
| 171 | |||
| 172 | BeginArray("control_data"); | ||
| 173 | for (size_t i = 0; i < AndroidSettings::values.overlay_control_data.size(); ++i) { | ||
| 174 | SetArrayIndex(i); | ||
| 175 | const auto& control_data = AndroidSettings::values.overlay_control_data[i]; | ||
| 176 | WriteStringSetting(std::string("id"), control_data.id); | ||
| 177 | WriteBooleanSetting(std::string("enabled"), control_data.enabled); | ||
| 178 | WriteDoubleSetting(std::string("landscape\\x_position"), | ||
| 179 | control_data.landscape_position.first); | ||
| 180 | WriteDoubleSetting(std::string("landscape\\y_position"), | ||
| 181 | control_data.landscape_position.second); | ||
| 182 | WriteDoubleSetting(std::string("portrait\\x_position"), | ||
| 183 | control_data.portrait_position.first); | ||
| 184 | WriteDoubleSetting(std::string("portrait\\y_position"), | ||
| 185 | control_data.portrait_position.second); | ||
| 186 | WriteDoubleSetting(std::string("foldable\\x_position"), | ||
| 187 | control_data.foldable_position.first); | ||
| 188 | WriteDoubleSetting(std::string("foldable\\y_position"), | ||
| 189 | control_data.foldable_position.second); | ||
| 190 | } | ||
| 191 | EndArray(); | ||
| 192 | |||
| 193 | EndGroup(); | ||
| 194 | } | ||
| 195 | |||
| 133 | std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) { | 196 | std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) { |
| 134 | auto& map = Settings::values.linkage.by_category; | 197 | auto& map = Settings::values.linkage.by_category; |
| 135 | if (map.contains(category)) { | 198 | if (map.contains(category)) { |
diff --git a/src/android/app/src/main/jni/android_config.h b/src/android/app/src/main/jni/android_config.h index 2c12874e1..d83852de9 100644 --- a/src/android/app/src/main/jni/android_config.h +++ b/src/android/app/src/main/jni/android_config.h | |||
| @@ -18,6 +18,7 @@ protected: | |||
| 18 | void ReadAndroidValues(); | 18 | void ReadAndroidValues(); |
| 19 | void ReadAndroidUIValues(); | 19 | void ReadAndroidUIValues(); |
| 20 | void ReadDriverValues(); | 20 | void ReadDriverValues(); |
| 21 | void ReadOverlayValues(); | ||
| 21 | void ReadHidbusValues() override {} | 22 | void ReadHidbusValues() override {} |
| 22 | void ReadDebugControlValues() override {} | 23 | void ReadDebugControlValues() override {} |
| 23 | void ReadPathValues() override; | 24 | void ReadPathValues() override; |
| @@ -30,6 +31,7 @@ protected: | |||
| 30 | void SaveAndroidValues(); | 31 | void SaveAndroidValues(); |
| 31 | void SaveAndroidUIValues(); | 32 | void SaveAndroidUIValues(); |
| 32 | void SaveDriverValues(); | 33 | void SaveDriverValues(); |
| 34 | void SaveOverlayValues(); | ||
| 33 | void SaveHidbusValues() override {} | 35 | void SaveHidbusValues() override {} |
| 34 | void SaveDebugControlValues() override {} | 36 | void SaveDebugControlValues() override {} |
| 35 | void SavePathValues() override; | 37 | void SavePathValues() override; |
diff --git a/src/android/app/src/main/jni/android_settings.h b/src/android/app/src/main/jni/android_settings.h index 3733f5a3c..559ae83eb 100644 --- a/src/android/app/src/main/jni/android_settings.h +++ b/src/android/app/src/main/jni/android_settings.h | |||
| @@ -14,6 +14,14 @@ struct GameDir { | |||
| 14 | bool deep_scan = false; | 14 | bool deep_scan = false; |
| 15 | }; | 15 | }; |
| 16 | 16 | ||
| 17 | struct OverlayControlData { | ||
| 18 | std::string id; | ||
| 19 | bool enabled; | ||
| 20 | std::pair<double, double> landscape_position; | ||
| 21 | std::pair<double, double> portrait_position; | ||
| 22 | std::pair<double, double> foldable_position; | ||
| 23 | }; | ||
| 24 | |||
| 17 | struct Values { | 25 | struct Values { |
| 18 | Settings::Linkage linkage; | 26 | Settings::Linkage linkage; |
| 19 | 27 | ||
| @@ -33,6 +41,28 @@ struct Values { | |||
| 33 | 41 | ||
| 34 | Settings::SwitchableSetting<std::string, false> driver_path{linkage, "", "driver_path", | 42 | Settings::SwitchableSetting<std::string, false> driver_path{linkage, "", "driver_path", |
| 35 | Settings::Category::GpuDriver}; | 43 | Settings::Category::GpuDriver}; |
| 44 | |||
| 45 | Settings::Setting<s32> theme{linkage, 0, "theme", Settings::Category::Android}; | ||
| 46 | Settings::Setting<s32> theme_mode{linkage, -1, "theme_mode", Settings::Category::Android}; | ||
| 47 | Settings::Setting<bool> black_backgrounds{linkage, false, "black_backgrounds", | ||
| 48 | Settings::Category::Android}; | ||
| 49 | |||
| 50 | // Input/performance overlay settings | ||
| 51 | std::vector<OverlayControlData> overlay_control_data; | ||
| 52 | Settings::Setting<s32> overlay_scale{linkage, 50, "control_scale", Settings::Category::Overlay}; | ||
| 53 | Settings::Setting<s32> overlay_opacity{linkage, 100, "control_opacity", | ||
| 54 | Settings::Category::Overlay}; | ||
| 55 | |||
| 56 | Settings::Setting<bool> joystick_rel_center{linkage, true, "joystick_rel_center", | ||
| 57 | Settings::Category::Overlay}; | ||
| 58 | Settings::Setting<bool> dpad_slide{linkage, true, "dpad_slide", Settings::Category::Overlay}; | ||
| 59 | Settings::Setting<bool> haptic_feedback{linkage, true, "haptic_feedback", | ||
| 60 | Settings::Category::Overlay}; | ||
| 61 | Settings::Setting<bool> show_performance_overlay{linkage, true, "show_performance_overlay", | ||
| 62 | Settings::Category::Overlay}; | ||
| 63 | Settings::Setting<bool> show_input_overlay{linkage, true, "show_input_overlay", | ||
| 64 | Settings::Category::Overlay}; | ||
| 65 | Settings::Setting<bool> touchscreen{linkage, true, "touchscreen", Settings::Category::Overlay}; | ||
| 36 | }; | 66 | }; |
| 37 | 67 | ||
| 38 | extern Values values; | 68 | extern Values values; |
diff --git a/src/android/app/src/main/jni/id_cache.cpp b/src/android/app/src/main/jni/id_cache.cpp index e7a86d3fd..c79ad7d76 100644 --- a/src/android/app/src/main/jni/id_cache.cpp +++ b/src/android/app/src/main/jni/id_cache.cpp | |||
| @@ -35,6 +35,18 @@ static jmethodID s_pair_constructor; | |||
| 35 | static jfieldID s_pair_first_field; | 35 | static jfieldID s_pair_first_field; |
| 36 | static jfieldID s_pair_second_field; | 36 | static jfieldID s_pair_second_field; |
| 37 | 37 | ||
| 38 | static jclass s_overlay_control_data_class; | ||
| 39 | static jmethodID s_overlay_control_data_constructor; | ||
| 40 | static jfieldID s_overlay_control_data_id_field; | ||
| 41 | static jfieldID s_overlay_control_data_enabled_field; | ||
| 42 | static jfieldID s_overlay_control_data_landscape_position_field; | ||
| 43 | static jfieldID s_overlay_control_data_portrait_position_field; | ||
| 44 | static jfieldID s_overlay_control_data_foldable_position_field; | ||
| 45 | |||
| 46 | static jclass s_double_class; | ||
| 47 | static jmethodID s_double_constructor; | ||
| 48 | static jfieldID s_double_value_field; | ||
| 49 | |||
| 38 | static constexpr jint JNI_VERSION = JNI_VERSION_1_6; | 50 | static constexpr jint JNI_VERSION = JNI_VERSION_1_6; |
| 39 | 51 | ||
| 40 | namespace IDCache { | 52 | namespace IDCache { |
| @@ -146,6 +158,46 @@ jfieldID GetPairSecondField() { | |||
| 146 | return s_pair_second_field; | 158 | return s_pair_second_field; |
| 147 | } | 159 | } |
| 148 | 160 | ||
| 161 | jclass GetOverlayControlDataClass() { | ||
| 162 | return s_overlay_control_data_class; | ||
| 163 | } | ||
| 164 | |||
| 165 | jmethodID GetOverlayControlDataConstructor() { | ||
| 166 | return s_overlay_control_data_constructor; | ||
| 167 | } | ||
| 168 | |||
| 169 | jfieldID GetOverlayControlDataIdField() { | ||
| 170 | return s_overlay_control_data_id_field; | ||
| 171 | } | ||
| 172 | |||
| 173 | jfieldID GetOverlayControlDataEnabledField() { | ||
| 174 | return s_overlay_control_data_enabled_field; | ||
| 175 | } | ||
| 176 | |||
| 177 | jfieldID GetOverlayControlDataLandscapePositionField() { | ||
| 178 | return s_overlay_control_data_landscape_position_field; | ||
| 179 | } | ||
| 180 | |||
| 181 | jfieldID GetOverlayControlDataPortraitPositionField() { | ||
| 182 | return s_overlay_control_data_portrait_position_field; | ||
| 183 | } | ||
| 184 | |||
| 185 | jfieldID GetOverlayControlDataFoldablePositionField() { | ||
| 186 | return s_overlay_control_data_foldable_position_field; | ||
| 187 | } | ||
| 188 | |||
| 189 | jclass GetDoubleClass() { | ||
| 190 | return s_double_class; | ||
| 191 | } | ||
| 192 | |||
| 193 | jmethodID GetDoubleConstructor() { | ||
| 194 | return s_double_constructor; | ||
| 195 | } | ||
| 196 | |||
| 197 | jfieldID GetDoubleValueField() { | ||
| 198 | return s_double_value_field; | ||
| 199 | } | ||
| 200 | |||
| 149 | } // namespace IDCache | 201 | } // namespace IDCache |
| 150 | 202 | ||
| 151 | #ifdef __cplusplus | 203 | #ifdef __cplusplus |
| @@ -207,6 +259,31 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { | |||
| 207 | s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;"); | 259 | s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;"); |
| 208 | env->DeleteLocalRef(pair_class); | 260 | env->DeleteLocalRef(pair_class); |
| 209 | 261 | ||
| 262 | const jclass overlay_control_data_class = | ||
| 263 | env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData"); | ||
| 264 | s_overlay_control_data_class = | ||
| 265 | reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class)); | ||
| 266 | s_overlay_control_data_constructor = | ||
| 267 | env->GetMethodID(overlay_control_data_class, "<init>", | ||
| 268 | "(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;)V"); | ||
| 269 | s_overlay_control_data_id_field = | ||
| 270 | env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;"); | ||
| 271 | s_overlay_control_data_enabled_field = | ||
| 272 | env->GetFieldID(overlay_control_data_class, "enabled", "Z"); | ||
| 273 | s_overlay_control_data_landscape_position_field = | ||
| 274 | env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;"); | ||
| 275 | s_overlay_control_data_portrait_position_field = | ||
| 276 | env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;"); | ||
| 277 | s_overlay_control_data_foldable_position_field = | ||
| 278 | env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;"); | ||
| 279 | env->DeleteLocalRef(overlay_control_data_class); | ||
| 280 | |||
| 281 | const jclass double_class = env->FindClass("java/lang/Double"); | ||
| 282 | s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class)); | ||
| 283 | s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V"); | ||
| 284 | s_double_value_field = env->GetFieldID(double_class, "value", "D"); | ||
| 285 | env->DeleteLocalRef(double_class); | ||
| 286 | |||
| 210 | // Initialize Android Storage | 287 | // Initialize Android Storage |
| 211 | Common::FS::Android::RegisterCallbacks(env, s_native_library_class); | 288 | Common::FS::Android::RegisterCallbacks(env, s_native_library_class); |
| 212 | 289 | ||
| @@ -231,6 +308,8 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) { | |||
| 231 | env->DeleteGlobalRef(s_game_class); | 308 | env->DeleteGlobalRef(s_game_class); |
| 232 | env->DeleteGlobalRef(s_string_class); | 309 | env->DeleteGlobalRef(s_string_class); |
| 233 | env->DeleteGlobalRef(s_pair_class); | 310 | env->DeleteGlobalRef(s_pair_class); |
| 311 | env->DeleteGlobalRef(s_overlay_control_data_class); | ||
| 312 | env->DeleteGlobalRef(s_double_class); | ||
| 234 | 313 | ||
| 235 | // UnInitialize applets | 314 | // UnInitialize applets |
| 236 | SoftwareKeyboard::CleanupJNI(env); | 315 | 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 24030be42..784d1412f 100644 --- a/src/android/app/src/main/jni/id_cache.h +++ b/src/android/app/src/main/jni/id_cache.h | |||
| @@ -35,4 +35,16 @@ jmethodID GetPairConstructor(); | |||
| 35 | jfieldID GetPairFirstField(); | 35 | jfieldID GetPairFirstField(); |
| 36 | jfieldID GetPairSecondField(); | 36 | jfieldID GetPairSecondField(); |
| 37 | 37 | ||
| 38 | jclass GetOverlayControlDataClass(); | ||
| 39 | jmethodID GetOverlayControlDataConstructor(); | ||
| 40 | jfieldID GetOverlayControlDataIdField(); | ||
| 41 | jfieldID GetOverlayControlDataEnabledField(); | ||
| 42 | jfieldID GetOverlayControlDataLandscapePositionField(); | ||
| 43 | jfieldID GetOverlayControlDataPortraitPositionField(); | ||
| 44 | jfieldID GetOverlayControlDataFoldablePositionField(); | ||
| 45 | |||
| 46 | jclass GetDoubleClass(); | ||
| 47 | jmethodID GetDoubleConstructor(); | ||
| 48 | jfieldID GetDoubleValueField(); | ||
| 49 | |||
| 38 | } // namespace IDCache | 50 | } // namespace IDCache |
diff --git a/src/android/app/src/main/jni/native_config.cpp b/src/android/app/src/main/jni/native_config.cpp index 324d9e9cd..535902483 100644 --- a/src/android/app/src/main/jni/native_config.cpp +++ b/src/android/app/src/main/jni/native_config.cpp | |||
| @@ -344,4 +344,74 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setDisabledAddons(JNIEnv* env, j | |||
| 344 | Settings::values.disabled_addons[program_id] = disabled_addons; | 344 | Settings::values.disabled_addons[program_id] = disabled_addons; |
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getOverlayControlData(JNIEnv* env, | ||
| 348 | jobject obj) { | ||
| 349 | jobjectArray joverlayControlDataArray = | ||
| 350 | env->NewObjectArray(AndroidSettings::values.overlay_control_data.size(), | ||
| 351 | IDCache::GetOverlayControlDataClass(), nullptr); | ||
| 352 | for (size_t i = 0; i < AndroidSettings::values.overlay_control_data.size(); ++i) { | ||
| 353 | const auto& control_data = AndroidSettings::values.overlay_control_data[i]; | ||
| 354 | jobject jlandscapePosition = | ||
| 355 | env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(), | ||
| 356 | ToJDouble(env, control_data.landscape_position.first), | ||
| 357 | ToJDouble(env, control_data.landscape_position.second)); | ||
| 358 | jobject jportraitPosition = | ||
| 359 | env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(), | ||
| 360 | ToJDouble(env, control_data.portrait_position.first), | ||
| 361 | ToJDouble(env, control_data.portrait_position.second)); | ||
| 362 | jobject jfoldablePosition = | ||
| 363 | env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(), | ||
| 364 | ToJDouble(env, control_data.foldable_position.first), | ||
| 365 | ToJDouble(env, control_data.foldable_position.second)); | ||
| 366 | |||
| 367 | jobject jcontrolData = env->NewObject( | ||
| 368 | IDCache::GetOverlayControlDataClass(), IDCache::GetOverlayControlDataConstructor(), | ||
| 369 | ToJString(env, control_data.id), control_data.enabled, jlandscapePosition, | ||
| 370 | jportraitPosition, jfoldablePosition); | ||
| 371 | env->SetObjectArrayElement(joverlayControlDataArray, i, jcontrolData); | ||
| 372 | } | ||
| 373 | return joverlayControlDataArray; | ||
| 374 | } | ||
| 375 | |||
| 376 | void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setOverlayControlData( | ||
| 377 | JNIEnv* env, jobject obj, jobjectArray joverlayControlDataArray) { | ||
| 378 | AndroidSettings::values.overlay_control_data.clear(); | ||
| 379 | int size = env->GetArrayLength(joverlayControlDataArray); | ||
| 380 | |||
| 381 | if (size == 0) { | ||
| 382 | return; | ||
| 383 | } | ||
| 384 | |||
| 385 | for (int i = 0; i < size; ++i) { | ||
| 386 | jobject joverlayControlData = env->GetObjectArrayElement(joverlayControlDataArray, i); | ||
| 387 | jstring jidString = static_cast<jstring>( | ||
| 388 | env->GetObjectField(joverlayControlData, IDCache::GetOverlayControlDataIdField())); | ||
| 389 | bool enabled = static_cast<bool>(env->GetBooleanField( | ||
| 390 | joverlayControlData, IDCache::GetOverlayControlDataEnabledField())); | ||
| 391 | |||
| 392 | jobject jlandscapePosition = env->GetObjectField( | ||
| 393 | joverlayControlData, IDCache::GetOverlayControlDataLandscapePositionField()); | ||
| 394 | std::pair<double, double> landscape_position = std::make_pair( | ||
| 395 | GetJDouble(env, env->GetObjectField(jlandscapePosition, IDCache::GetPairFirstField())), | ||
| 396 | GetJDouble(env, | ||
| 397 | env->GetObjectField(jlandscapePosition, IDCache::GetPairSecondField()))); | ||
| 398 | |||
| 399 | jobject jportraitPosition = env->GetObjectField( | ||
| 400 | joverlayControlData, IDCache::GetOverlayControlDataPortraitPositionField()); | ||
| 401 | std::pair<double, double> portrait_position = std::make_pair( | ||
| 402 | GetJDouble(env, env->GetObjectField(jportraitPosition, IDCache::GetPairFirstField())), | ||
| 403 | GetJDouble(env, env->GetObjectField(jportraitPosition, IDCache::GetPairSecondField()))); | ||
| 404 | |||
| 405 | jobject jfoldablePosition = env->GetObjectField( | ||
| 406 | joverlayControlData, IDCache::GetOverlayControlDataFoldablePositionField()); | ||
| 407 | std::pair<double, double> foldable_position = std::make_pair( | ||
| 408 | GetJDouble(env, env->GetObjectField(jfoldablePosition, IDCache::GetPairFirstField())), | ||
| 409 | GetJDouble(env, env->GetObjectField(jfoldablePosition, IDCache::GetPairSecondField()))); | ||
| 410 | |||
| 411 | AndroidSettings::values.overlay_control_data.push_back(AndroidSettings::OverlayControlData{ | ||
| 412 | GetJString(env, jidString), enabled, landscape_position, portrait_position, | ||
| 413 | foldable_position}); | ||
| 414 | } | ||
| 415 | } | ||
| 416 | |||
| 347 | } // extern "C" | 417 | } // extern "C" |
diff --git a/src/android/app/src/main/res/menu/menu_overlay_options.xml b/src/android/app/src/main/res/menu/menu_overlay_options.xml index 4885b4f6f..363781652 100644 --- a/src/android/app/src/main/res/menu/menu_overlay_options.xml +++ b/src/android/app/src/main/res/menu/menu_overlay_options.xml | |||
| @@ -39,6 +39,11 @@ | |||
| 39 | android:checkable="true" /> | 39 | android:checkable="true" /> |
| 40 | 40 | ||
| 41 | <item | 41 | <item |
| 42 | android:id="@+id/menu_touchscreen" | ||
| 43 | android:title="@string/touchscreen" | ||
| 44 | android:checkable="true" /> | ||
| 45 | |||
| 46 | <item | ||
| 42 | android:id="@+id/menu_reset_overlay" | 47 | android:id="@+id/menu_reset_overlay" |
| 43 | android:title="@string/emulation_touch_overlay_reset" /> | 48 | android:title="@string/emulation_touch_overlay_reset" /> |
| 44 | 49 | ||
diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index c882a8e62..45d57c3ea 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml | |||
| @@ -212,19 +212,19 @@ | |||
| 212 | <item>B</item> | 212 | <item>B</item> |
| 213 | <item>X</item> | 213 | <item>X</item> |
| 214 | <item>Y</item> | 214 | <item>Y</item> |
| 215 | <item>+</item> | ||
| 216 | <item>-</item> | ||
| 217 | <item>@string/gamepad_home</item> | ||
| 218 | <item>@string/gamepad_screenshot</item> | ||
| 215 | <item>L</item> | 219 | <item>L</item> |
| 216 | <item>R</item> | 220 | <item>R</item> |
| 217 | <item>ZL</item> | 221 | <item>ZL</item> |
| 218 | <item>ZR</item> | 222 | <item>ZR</item> |
| 219 | <item>+</item> | ||
| 220 | <item>-</item> | ||
| 221 | <item>@string/gamepad_d_pad</item> | ||
| 222 | <item>@string/gamepad_left_stick</item> | 223 | <item>@string/gamepad_left_stick</item> |
| 223 | <item>@string/gamepad_right_stick</item> | 224 | <item>@string/gamepad_right_stick</item> |
| 224 | <item>L3</item> | 225 | <item>L3</item> |
| 225 | <item>R3</item> | 226 | <item>R3</item> |
| 226 | <item>@string/gamepad_home</item> | 227 | <item>@string/gamepad_d_pad</item> |
| 227 | <item>@string/gamepad_screenshot</item> | ||
| 228 | </string-array> | 228 | </string-array> |
| 229 | 229 | ||
| 230 | <string-array name="themeEntries"> | 230 | <string-array name="themeEntries"> |
diff --git a/src/android/app/src/main/res/values/integers.xml b/src/android/app/src/main/res/values/integers.xml index dc527965c..1c6f5db93 100644 --- a/src/android/app/src/main/res/values/integers.xml +++ b/src/android/app/src/main/res/values/integers.xml | |||
| @@ -3,111 +3,111 @@ | |||
| 3 | <integer name="grid_columns">1</integer> | 3 | <integer name="grid_columns">1</integer> |
| 4 | 4 | ||
| 5 | <!-- Default SWITCH landscape layout --> | 5 | <!-- Default SWITCH landscape layout --> |
| 6 | <integer name="SWITCH_BUTTON_A_X">760</integer> | 6 | <integer name="BUTTON_A_X">760</integer> |
| 7 | <integer name="SWITCH_BUTTON_A_Y">790</integer> | 7 | <integer name="BUTTON_A_Y">790</integer> |
| 8 | <integer name="SWITCH_BUTTON_B_X">710</integer> | 8 | <integer name="BUTTON_B_X">710</integer> |
| 9 | <integer name="SWITCH_BUTTON_B_Y">900</integer> | 9 | <integer name="BUTTON_B_Y">900</integer> |
| 10 | <integer name="SWITCH_BUTTON_X_X">710</integer> | 10 | <integer name="BUTTON_X_X">710</integer> |
| 11 | <integer name="SWITCH_BUTTON_X_Y">680</integer> | 11 | <integer name="BUTTON_X_Y">680</integer> |
| 12 | <integer name="SWITCH_BUTTON_Y_X">660</integer> | 12 | <integer name="BUTTON_Y_X">660</integer> |
| 13 | <integer name="SWITCH_BUTTON_Y_Y">790</integer> | 13 | <integer name="BUTTON_Y_Y">790</integer> |
| 14 | <integer name="SWITCH_STICK_L_X">100</integer> | 14 | <integer name="BUTTON_PLUS_X">540</integer> |
| 15 | <integer name="SWITCH_STICK_L_Y">670</integer> | 15 | <integer name="BUTTON_PLUS_Y">950</integer> |
| 16 | <integer name="SWITCH_STICK_R_X">900</integer> | 16 | <integer name="BUTTON_MINUS_X">460</integer> |
| 17 | <integer name="SWITCH_STICK_R_Y">670</integer> | 17 | <integer name="BUTTON_MINUS_Y">950</integer> |
| 18 | <integer name="SWITCH_TRIGGER_L_X">70</integer> | 18 | <integer name="BUTTON_HOME_X">600</integer> |
| 19 | <integer name="SWITCH_TRIGGER_L_Y">220</integer> | 19 | <integer name="BUTTON_HOME_Y">950</integer> |
| 20 | <integer name="SWITCH_TRIGGER_R_X">930</integer> | 20 | <integer name="BUTTON_CAPTURE_X">400</integer> |
| 21 | <integer name="SWITCH_TRIGGER_R_Y">220</integer> | 21 | <integer name="BUTTON_CAPTURE_Y">950</integer> |
| 22 | <integer name="SWITCH_TRIGGER_ZL_X">70</integer> | 22 | <integer name="BUTTON_L_X">70</integer> |
| 23 | <integer name="SWITCH_TRIGGER_ZL_Y">90</integer> | 23 | <integer name="BUTTON_L_Y">220</integer> |
| 24 | <integer name="SWITCH_TRIGGER_ZR_X">930</integer> | 24 | <integer name="BUTTON_R_X">930</integer> |
| 25 | <integer name="SWITCH_TRIGGER_ZR_Y">90</integer> | 25 | <integer name="BUTTON_R_Y">220</integer> |
| 26 | <integer name="SWITCH_BUTTON_MINUS_X">460</integer> | 26 | <integer name="BUTTON_ZL_X">70</integer> |
| 27 | <integer name="SWITCH_BUTTON_MINUS_Y">950</integer> | 27 | <integer name="BUTTON_ZL_Y">90</integer> |
| 28 | <integer name="SWITCH_BUTTON_PLUS_X">540</integer> | 28 | <integer name="BUTTON_ZR_X">930</integer> |
| 29 | <integer name="SWITCH_BUTTON_PLUS_Y">950</integer> | 29 | <integer name="BUTTON_ZR_Y">90</integer> |
| 30 | <integer name="SWITCH_BUTTON_HOME_X">600</integer> | 30 | <integer name="BUTTON_STICK_L_X">870</integer> |
| 31 | <integer name="SWITCH_BUTTON_HOME_Y">950</integer> | 31 | <integer name="BUTTON_STICK_L_Y">400</integer> |
| 32 | <integer name="SWITCH_BUTTON_CAPTURE_X">400</integer> | 32 | <integer name="BUTTON_STICK_R_X">960</integer> |
| 33 | <integer name="SWITCH_BUTTON_CAPTURE_Y">950</integer> | 33 | <integer name="BUTTON_STICK_R_Y">430</integer> |
| 34 | <integer name="SWITCH_BUTTON_DPAD_X">260</integer> | 34 | <integer name="STICK_L_X">100</integer> |
| 35 | <integer name="SWITCH_BUTTON_DPAD_Y">790</integer> | 35 | <integer name="STICK_L_Y">670</integer> |
| 36 | <integer name="SWITCH_BUTTON_STICK_L_X">870</integer> | 36 | <integer name="STICK_R_X">900</integer> |
| 37 | <integer name="SWITCH_BUTTON_STICK_L_Y">400</integer> | 37 | <integer name="STICK_R_Y">670</integer> |
| 38 | <integer name="SWITCH_BUTTON_STICK_R_X">960</integer> | 38 | <integer name="COMBINED_DPAD_X">260</integer> |
| 39 | <integer name="SWITCH_BUTTON_STICK_R_Y">430</integer> | 39 | <integer name="COMBINED_DPAD_Y">790</integer> |
| 40 | 40 | ||
| 41 | <!-- Default SWITCH portrait layout --> | 41 | <!-- Default SWITCH portrait layout --> |
| 42 | <integer name="SWITCH_BUTTON_A_X_PORTRAIT">840</integer> | 42 | <integer name="BUTTON_A_X_PORTRAIT">840</integer> |
| 43 | <integer name="SWITCH_BUTTON_A_Y_PORTRAIT">840</integer> | 43 | <integer name="BUTTON_A_Y_PORTRAIT">840</integer> |
| 44 | <integer name="SWITCH_BUTTON_B_X_PORTRAIT">740</integer> | 44 | <integer name="BUTTON_B_X_PORTRAIT">740</integer> |
| 45 | <integer name="SWITCH_BUTTON_B_Y_PORTRAIT">880</integer> | 45 | <integer name="BUTTON_B_Y_PORTRAIT">880</integer> |
| 46 | <integer name="SWITCH_BUTTON_X_X_PORTRAIT">740</integer> | 46 | <integer name="BUTTON_X_X_PORTRAIT">740</integer> |
| 47 | <integer name="SWITCH_BUTTON_X_Y_PORTRAIT">800</integer> | 47 | <integer name="BUTTON_X_Y_PORTRAIT">800</integer> |
| 48 | <integer name="SWITCH_BUTTON_Y_X_PORTRAIT">640</integer> | 48 | <integer name="BUTTON_Y_X_PORTRAIT">640</integer> |
| 49 | <integer name="SWITCH_BUTTON_Y_Y_PORTRAIT">840</integer> | 49 | <integer name="BUTTON_Y_Y_PORTRAIT">840</integer> |
| 50 | <integer name="SWITCH_STICK_L_X_PORTRAIT">180</integer> | 50 | <integer name="BUTTON_PLUS_Y_PORTRAIT">950</integer> |
| 51 | <integer name="SWITCH_STICK_L_Y_PORTRAIT">660</integer> | 51 | <integer name="BUTTON_MINUS_X_PORTRAIT">440</integer> |
| 52 | <integer name="SWITCH_STICK_R_X_PORTRAIT">820</integer> | 52 | <integer name="BUTTON_MINUS_Y_PORTRAIT">950</integer> |
| 53 | <integer name="SWITCH_STICK_R_Y_PORTRAIT">660</integer> | 53 | <integer name="BUTTON_HOME_X_PORTRAIT">680</integer> |
| 54 | <integer name="SWITCH_TRIGGER_L_X_PORTRAIT">140</integer> | 54 | <integer name="BUTTON_HOME_Y_PORTRAIT">950</integer> |
| 55 | <integer name="SWITCH_TRIGGER_L_Y_PORTRAIT">260</integer> | 55 | <integer name="BUTTON_CAPTURE_X_PORTRAIT">320</integer> |
| 56 | <integer name="SWITCH_TRIGGER_R_X_PORTRAIT">860</integer> | 56 | <integer name="BUTTON_CAPTURE_Y_PORTRAIT">950</integer> |
| 57 | <integer name="SWITCH_TRIGGER_R_Y_PORTRAIT">260</integer> | 57 | <integer name="BUTTON_L_X_PORTRAIT">140</integer> |
| 58 | <integer name="SWITCH_TRIGGER_ZL_X_PORTRAIT">140</integer> | 58 | <integer name="BUTTON_L_Y_PORTRAIT">260</integer> |
| 59 | <integer name="SWITCH_TRIGGER_ZL_Y_PORTRAIT">200</integer> | 59 | <integer name="BUTTON_R_X_PORTRAIT">860</integer> |
| 60 | <integer name="SWITCH_TRIGGER_ZR_X_PORTRAIT">860</integer> | 60 | <integer name="BUTTON_R_Y_PORTRAIT">260</integer> |
| 61 | <integer name="SWITCH_TRIGGER_ZR_Y_PORTRAIT">200</integer> | 61 | <integer name="BUTTON_ZL_X_PORTRAIT">140</integer> |
| 62 | <integer name="SWITCH_BUTTON_MINUS_X_PORTRAIT">440</integer> | 62 | <integer name="BUTTON_ZL_Y_PORTRAIT">200</integer> |
| 63 | <integer name="SWITCH_BUTTON_MINUS_Y_PORTRAIT">950</integer> | 63 | <integer name="BUTTON_ZR_X_PORTRAIT">860</integer> |
| 64 | <integer name="SWITCH_BUTTON_PLUS_X_PORTRAIT">560</integer> | 64 | <integer name="BUTTON_ZR_Y_PORTRAIT">200</integer> |
| 65 | <integer name="SWITCH_BUTTON_PLUS_Y_PORTRAIT">950</integer> | 65 | <integer name="BUTTON_PLUS_X_PORTRAIT">560</integer> |
| 66 | <integer name="SWITCH_BUTTON_HOME_X_PORTRAIT">680</integer> | 66 | <integer name="BUTTON_STICK_L_X_PORTRAIT">730</integer> |
| 67 | <integer name="SWITCH_BUTTON_HOME_Y_PORTRAIT">950</integer> | 67 | <integer name="BUTTON_STICK_L_Y_PORTRAIT">510</integer> |
| 68 | <integer name="SWITCH_BUTTON_CAPTURE_X_PORTRAIT">320</integer> | 68 | <integer name="BUTTON_STICK_R_X_PORTRAIT">900</integer> |
| 69 | <integer name="SWITCH_BUTTON_CAPTURE_Y_PORTRAIT">950</integer> | 69 | <integer name="BUTTON_STICK_R_Y_PORTRAIT">540</integer> |
| 70 | <integer name="SWITCH_BUTTON_DPAD_X_PORTRAIT">240</integer> | 70 | <integer name="STICK_L_X_PORTRAIT">180</integer> |
| 71 | <integer name="SWITCH_BUTTON_DPAD_Y_PORTRAIT">840</integer> | 71 | <integer name="STICK_L_Y_PORTRAIT">660</integer> |
| 72 | <integer name="SWITCH_BUTTON_STICK_L_X_PORTRAIT">730</integer> | 72 | <integer name="STICK_R_X_PORTRAIT">820</integer> |
| 73 | <integer name="SWITCH_BUTTON_STICK_L_Y_PORTRAIT">510</integer> | 73 | <integer name="STICK_R_Y_PORTRAIT">660</integer> |
| 74 | <integer name="SWITCH_BUTTON_STICK_R_X_PORTRAIT">900</integer> | 74 | <integer name="COMBINED_DPAD_X_PORTRAIT">240</integer> |
| 75 | <integer name="SWITCH_BUTTON_STICK_R_Y_PORTRAIT">540</integer> | 75 | <integer name="COMBINED_DPAD_Y_PORTRAIT">840</integer> |
| 76 | 76 | ||
| 77 | <!-- Default SWITCH foldable layout --> | 77 | <!-- Default SWITCH foldable layout --> |
| 78 | <integer name="SWITCH_BUTTON_A_X_FOLDABLE">840</integer> | 78 | <integer name="BUTTON_A_X_FOLDABLE">840</integer> |
| 79 | <integer name="SWITCH_BUTTON_A_Y_FOLDABLE">390</integer> | 79 | <integer name="BUTTON_A_Y_FOLDABLE">390</integer> |
| 80 | <integer name="SWITCH_BUTTON_B_X_FOLDABLE">740</integer> | 80 | <integer name="BUTTON_B_X_FOLDABLE">740</integer> |
| 81 | <integer name="SWITCH_BUTTON_B_Y_FOLDABLE">430</integer> | 81 | <integer name="BUTTON_B_Y_FOLDABLE">430</integer> |
| 82 | <integer name="SWITCH_BUTTON_X_X_FOLDABLE">740</integer> | 82 | <integer name="BUTTON_X_X_FOLDABLE">740</integer> |
| 83 | <integer name="SWITCH_BUTTON_X_Y_FOLDABLE">350</integer> | 83 | <integer name="BUTTON_X_Y_FOLDABLE">350</integer> |
| 84 | <integer name="SWITCH_BUTTON_Y_X_FOLDABLE">640</integer> | 84 | <integer name="BUTTON_Y_X_FOLDABLE">640</integer> |
| 85 | <integer name="SWITCH_BUTTON_Y_Y_FOLDABLE">390</integer> | 85 | <integer name="BUTTON_Y_Y_FOLDABLE">390</integer> |
| 86 | <integer name="SWITCH_STICK_L_X_FOLDABLE">180</integer> | 86 | <integer name="BUTTON_PLUS_X_FOLDABLE">560</integer> |
| 87 | <integer name="SWITCH_STICK_L_Y_FOLDABLE">250</integer> | 87 | <integer name="BUTTON_PLUS_Y_FOLDABLE">470</integer> |
| 88 | <integer name="SWITCH_STICK_R_X_FOLDABLE">820</integer> | 88 | <integer name="BUTTON_MINUS_X_FOLDABLE">440</integer> |
| 89 | <integer name="SWITCH_STICK_R_Y_FOLDABLE">250</integer> | 89 | <integer name="BUTTON_MINUS_Y_FOLDABLE">470</integer> |
| 90 | <integer name="SWITCH_TRIGGER_L_X_FOLDABLE">140</integer> | 90 | <integer name="BUTTON_HOME_X_FOLDABLE">680</integer> |
| 91 | <integer name="SWITCH_TRIGGER_L_Y_FOLDABLE">130</integer> | 91 | <integer name="BUTTON_HOME_Y_FOLDABLE">470</integer> |
| 92 | <integer name="SWITCH_TRIGGER_R_X_FOLDABLE">860</integer> | 92 | <integer name="BUTTON_CAPTURE_X_FOLDABLE">320</integer> |
| 93 | <integer name="SWITCH_TRIGGER_R_Y_FOLDABLE">130</integer> | 93 | <integer name="BUTTON_CAPTURE_Y_FOLDABLE">470</integer> |
| 94 | <integer name="SWITCH_TRIGGER_ZL_X_FOLDABLE">140</integer> | 94 | <integer name="BUTTON_L_X_FOLDABLE">140</integer> |
| 95 | <integer name="SWITCH_TRIGGER_ZL_Y_FOLDABLE">70</integer> | 95 | <integer name="BUTTON_L_Y_FOLDABLE">130</integer> |
| 96 | <integer name="SWITCH_TRIGGER_ZR_X_FOLDABLE">860</integer> | 96 | <integer name="BUTTON_R_X_FOLDABLE">860</integer> |
| 97 | <integer name="SWITCH_TRIGGER_ZR_Y_FOLDABLE">70</integer> | 97 | <integer name="BUTTON_R_Y_FOLDABLE">130</integer> |
| 98 | <integer name="SWITCH_BUTTON_MINUS_X_FOLDABLE">440</integer> | 98 | <integer name="BUTTON_ZL_X_FOLDABLE">140</integer> |
| 99 | <integer name="SWITCH_BUTTON_MINUS_Y_FOLDABLE">470</integer> | 99 | <integer name="BUTTON_ZL_Y_FOLDABLE">70</integer> |
| 100 | <integer name="SWITCH_BUTTON_PLUS_X_FOLDABLE">560</integer> | 100 | <integer name="BUTTON_ZR_X_FOLDABLE">860</integer> |
| 101 | <integer name="SWITCH_BUTTON_PLUS_Y_FOLDABLE">470</integer> | 101 | <integer name="BUTTON_ZR_Y_FOLDABLE">70</integer> |
| 102 | <integer name="SWITCH_BUTTON_HOME_X_FOLDABLE">680</integer> | 102 | <integer name="BUTTON_STICK_L_X_FOLDABLE">550</integer> |
| 103 | <integer name="SWITCH_BUTTON_HOME_Y_FOLDABLE">470</integer> | 103 | <integer name="BUTTON_STICK_L_Y_FOLDABLE">210</integer> |
| 104 | <integer name="SWITCH_BUTTON_CAPTURE_X_FOLDABLE">320</integer> | 104 | <integer name="BUTTON_STICK_R_X_FOLDABLE">550</integer> |
| 105 | <integer name="SWITCH_BUTTON_CAPTURE_Y_FOLDABLE">470</integer> | 105 | <integer name="BUTTON_STICK_R_Y_FOLDABLE">280</integer> |
| 106 | <integer name="SWITCH_BUTTON_DPAD_X_FOLDABLE">240</integer> | 106 | <integer name="STICK_L_X_FOLDABLE">180</integer> |
| 107 | <integer name="SWITCH_BUTTON_DPAD_Y_FOLDABLE">390</integer> | 107 | <integer name="STICK_L_Y_FOLDABLE">250</integer> |
| 108 | <integer name="SWITCH_BUTTON_STICK_L_X_FOLDABLE">550</integer> | 108 | <integer name="STICK_R_X_FOLDABLE">820</integer> |
| 109 | <integer name="SWITCH_BUTTON_STICK_L_Y_FOLDABLE">210</integer> | 109 | <integer name="STICK_R_Y_FOLDABLE">250</integer> |
| 110 | <integer name="SWITCH_BUTTON_STICK_R_X_FOLDABLE">550</integer> | 110 | <integer name="COMBINED_DPAD_X_FOLDABLE">240</integer> |
| 111 | <integer name="SWITCH_BUTTON_STICK_R_Y_FOLDABLE">280</integer> | 111 | <integer name="COMBINED_DPAD_Y_FOLDABLE">390</integer> |
| 112 | 112 | ||
| 113 | </resources> | 113 | </resources> |
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 4d5c268fe..1bedcb1ef 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml | |||
| @@ -366,6 +366,7 @@ | |||
| 366 | <string name="emulation_pause">Pause emulation</string> | 366 | <string name="emulation_pause">Pause emulation</string> |
| 367 | <string name="emulation_unpause">Unpause emulation</string> | 367 | <string name="emulation_unpause">Unpause emulation</string> |
| 368 | <string name="emulation_input_overlay">Overlay options</string> | 368 | <string name="emulation_input_overlay">Overlay options</string> |
| 369 | <string name="touchscreen">Touchscreen</string> | ||
| 369 | 370 | ||
| 370 | <string name="load_settings">Loading settings…</string> | 371 | <string name="load_settings">Loading settings…</string> |
| 371 | 372 | ||
diff --git a/src/android/build.gradle.kts b/src/android/build.gradle.kts index 51e559321..b77906ed6 100644 --- a/src/android/build.gradle.kts +++ b/src/android/build.gradle.kts | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | plugins { | 5 | plugins { |
| 6 | id("com.android.application") version "8.1.2" apply false | 6 | id("com.android.application") version "8.1.2" apply false |
| 7 | id("com.android.library") version "8.1.2" apply false | 7 | id("com.android.library") version "8.1.2" apply false |
| 8 | id("org.jetbrains.kotlin.android") version "1.8.21" apply false | 8 | id("org.jetbrains.kotlin.android") version "1.9.20" apply false |
| 9 | } | 9 | } |
| 10 | 10 | ||
| 11 | tasks.register("clean").configure { | 11 | tasks.register("clean").configure { |
diff --git a/src/audio_core/device/device_session.cpp b/src/audio_core/device/device_session.cpp index c41d9d1ea..ee42ae529 100644 --- a/src/audio_core/device/device_session.cpp +++ b/src/audio_core/device/device_session.cpp | |||
| @@ -18,9 +18,7 @@ constexpr auto INCREMENT_TIME{5ms}; | |||
| 18 | DeviceSession::DeviceSession(Core::System& system_) | 18 | DeviceSession::DeviceSession(Core::System& system_) |
| 19 | : system{system_}, thread_event{Core::Timing::CreateEvent( | 19 | : system{system_}, thread_event{Core::Timing::CreateEvent( |
| 20 | "AudioOutSampleTick", | 20 | "AudioOutSampleTick", |
| 21 | [this](std::uintptr_t, s64 time, std::chrono::nanoseconds) { | 21 | [this](s64 time, std::chrono::nanoseconds) { return ThreadFunc(); })} {} |
| 22 | return ThreadFunc(); | ||
| 23 | })} {} | ||
| 24 | 22 | ||
| 25 | DeviceSession::~DeviceSession() { | 23 | DeviceSession::~DeviceSession() { |
| 26 | Finalize(); | 24 | Finalize(); |
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index b58a7073f..8c57d47c6 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -64,6 +64,8 @@ add_library(common STATIC | |||
| 64 | fs/path_util.cpp | 64 | fs/path_util.cpp |
| 65 | fs/path_util.h | 65 | fs/path_util.h |
| 66 | hash.h | 66 | hash.h |
| 67 | heap_tracker.cpp | ||
| 68 | heap_tracker.h | ||
| 67 | hex_util.cpp | 69 | hex_util.cpp |
| 68 | hex_util.h | 70 | hex_util.h |
| 69 | host_memory.cpp | 71 | host_memory.cpp |
diff --git a/src/common/heap_tracker.cpp b/src/common/heap_tracker.cpp new file mode 100644 index 000000000..683208795 --- /dev/null +++ b/src/common/heap_tracker.cpp | |||
| @@ -0,0 +1,281 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <fstream> | ||
| 5 | #include <vector> | ||
| 6 | |||
| 7 | #include "common/heap_tracker.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | |||
| 10 | namespace Common { | ||
| 11 | |||
| 12 | namespace { | ||
| 13 | |||
| 14 | s64 GetMaxPermissibleResidentMapCount() { | ||
| 15 | // Default value. | ||
| 16 | s64 value = 65530; | ||
| 17 | |||
| 18 | // Try to read how many mappings we can make. | ||
| 19 | std::ifstream s("/proc/sys/vm/max_map_count"); | ||
| 20 | s >> value; | ||
| 21 | |||
| 22 | // Print, for debug. | ||
| 23 | LOG_INFO(HW_Memory, "Current maximum map count: {}", value); | ||
| 24 | |||
| 25 | // Allow 20000 maps for other code and to account for split inaccuracy. | ||
| 26 | return std::max<s64>(value - 20000, 0); | ||
| 27 | } | ||
| 28 | |||
| 29 | } // namespace | ||
| 30 | |||
| 31 | HeapTracker::HeapTracker(Common::HostMemory& buffer) | ||
| 32 | : m_buffer(buffer), m_max_resident_map_count(GetMaxPermissibleResidentMapCount()) {} | ||
| 33 | HeapTracker::~HeapTracker() = default; | ||
| 34 | |||
| 35 | void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length, | ||
| 36 | MemoryPermission perm, bool is_separate_heap) { | ||
| 37 | // When mapping other memory, map pages immediately. | ||
| 38 | if (!is_separate_heap) { | ||
| 39 | m_buffer.Map(virtual_offset, host_offset, length, perm, false); | ||
| 40 | return; | ||
| 41 | } | ||
| 42 | |||
| 43 | { | ||
| 44 | // We are mapping part of a separate heap. | ||
| 45 | std::scoped_lock lk{m_lock}; | ||
| 46 | |||
| 47 | auto* const map = new SeparateHeapMap{ | ||
| 48 | .vaddr = virtual_offset, | ||
| 49 | .paddr = host_offset, | ||
| 50 | .size = length, | ||
| 51 | .tick = m_tick++, | ||
| 52 | .perm = perm, | ||
| 53 | .is_resident = false, | ||
| 54 | }; | ||
| 55 | |||
| 56 | // Insert into mappings. | ||
| 57 | m_map_count++; | ||
| 58 | m_mappings.insert(*map); | ||
| 59 | } | ||
| 60 | |||
| 61 | // Finally, map. | ||
| 62 | this->DeferredMapSeparateHeap(virtual_offset); | ||
| 63 | } | ||
| 64 | |||
| 65 | void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_heap) { | ||
| 66 | // If this is a separate heap... | ||
| 67 | if (is_separate_heap) { | ||
| 68 | std::scoped_lock lk{m_lock}; | ||
| 69 | |||
| 70 | const SeparateHeapMap key{ | ||
| 71 | .vaddr = virtual_offset, | ||
| 72 | }; | ||
| 73 | |||
| 74 | // Split at the boundaries of the region we are removing. | ||
| 75 | this->SplitHeapMapLocked(virtual_offset); | ||
| 76 | this->SplitHeapMapLocked(virtual_offset + size); | ||
| 77 | |||
| 78 | // Erase all mappings in range. | ||
| 79 | auto it = m_mappings.find(key); | ||
| 80 | while (it != m_mappings.end() && it->vaddr < virtual_offset + size) { | ||
| 81 | // Get underlying item. | ||
| 82 | auto* const item = std::addressof(*it); | ||
| 83 | |||
| 84 | // If resident, erase from resident map. | ||
| 85 | if (item->is_resident) { | ||
| 86 | ASSERT(--m_resident_map_count >= 0); | ||
| 87 | m_resident_mappings.erase(m_resident_mappings.iterator_to(*item)); | ||
| 88 | } | ||
| 89 | |||
| 90 | // Erase from map. | ||
| 91 | ASSERT(--m_map_count >= 0); | ||
| 92 | it = m_mappings.erase(it); | ||
| 93 | |||
| 94 | // Free the item. | ||
| 95 | delete item; | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | // Unmap pages. | ||
| 100 | m_buffer.Unmap(virtual_offset, size, false); | ||
| 101 | } | ||
| 102 | |||
| 103 | void HeapTracker::Protect(size_t virtual_offset, size_t size, MemoryPermission perm) { | ||
| 104 | // Ensure no rebuild occurs while reprotecting. | ||
| 105 | std::shared_lock lk{m_rebuild_lock}; | ||
| 106 | |||
| 107 | // Split at the boundaries of the region we are reprotecting. | ||
| 108 | this->SplitHeapMap(virtual_offset, size); | ||
| 109 | |||
| 110 | // Declare tracking variables. | ||
| 111 | const VAddr end = virtual_offset + size; | ||
| 112 | VAddr cur = virtual_offset; | ||
| 113 | |||
| 114 | while (cur < end) { | ||
| 115 | VAddr next = cur; | ||
| 116 | bool should_protect = false; | ||
| 117 | |||
| 118 | { | ||
| 119 | std::scoped_lock lk2{m_lock}; | ||
| 120 | |||
| 121 | const SeparateHeapMap key{ | ||
| 122 | .vaddr = next, | ||
| 123 | }; | ||
| 124 | |||
| 125 | // Try to get the next mapping corresponding to this address. | ||
| 126 | const auto it = m_mappings.nfind(key); | ||
| 127 | |||
| 128 | if (it == m_mappings.end()) { | ||
| 129 | // There are no separate heap mappings remaining. | ||
| 130 | next = end; | ||
| 131 | should_protect = true; | ||
| 132 | } else if (it->vaddr == cur) { | ||
| 133 | // We are in range. | ||
| 134 | // Update permission bits. | ||
| 135 | it->perm = perm; | ||
| 136 | |||
| 137 | // Determine next address and whether we should protect. | ||
| 138 | next = cur + it->size; | ||
| 139 | should_protect = it->is_resident; | ||
| 140 | } else /* if (it->vaddr > cur) */ { | ||
| 141 | // We weren't in range, but there is a block coming up that will be. | ||
| 142 | next = it->vaddr; | ||
| 143 | should_protect = true; | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | // Clamp to end. | ||
| 148 | next = std::min(next, end); | ||
| 149 | |||
| 150 | // Reprotect, if we need to. | ||
| 151 | if (should_protect) { | ||
| 152 | m_buffer.Protect(cur, next - cur, perm); | ||
| 153 | } | ||
| 154 | |||
| 155 | // Advance. | ||
| 156 | cur = next; | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | bool HeapTracker::DeferredMapSeparateHeap(u8* fault_address) { | ||
| 161 | if (m_buffer.IsInVirtualRange(fault_address)) { | ||
| 162 | return this->DeferredMapSeparateHeap(fault_address - m_buffer.VirtualBasePointer()); | ||
| 163 | } | ||
| 164 | |||
| 165 | return false; | ||
| 166 | } | ||
| 167 | |||
| 168 | bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) { | ||
| 169 | bool rebuild_required = false; | ||
| 170 | |||
| 171 | { | ||
| 172 | std::scoped_lock lk{m_lock}; | ||
| 173 | |||
| 174 | // Check to ensure this was a non-resident separate heap mapping. | ||
| 175 | const auto it = this->GetNearestHeapMapLocked(virtual_offset); | ||
| 176 | if (it == m_mappings.end() || it->is_resident) { | ||
| 177 | return false; | ||
| 178 | } | ||
| 179 | |||
| 180 | // Update tick before possible rebuild. | ||
| 181 | it->tick = m_tick++; | ||
| 182 | |||
| 183 | // Check if we need to rebuild. | ||
| 184 | if (m_resident_map_count > m_max_resident_map_count) { | ||
| 185 | rebuild_required = true; | ||
| 186 | } | ||
| 187 | |||
| 188 | // Map the area. | ||
| 189 | m_buffer.Map(it->vaddr, it->paddr, it->size, it->perm, false); | ||
| 190 | |||
| 191 | // This map is now resident. | ||
| 192 | it->is_resident = true; | ||
| 193 | m_resident_map_count++; | ||
| 194 | m_resident_mappings.insert(*it); | ||
| 195 | } | ||
| 196 | |||
| 197 | if (rebuild_required) { | ||
| 198 | // A rebuild was required, so perform it now. | ||
| 199 | this->RebuildSeparateHeapAddressSpace(); | ||
| 200 | } | ||
| 201 | |||
| 202 | return true; | ||
| 203 | } | ||
| 204 | |||
| 205 | void HeapTracker::RebuildSeparateHeapAddressSpace() { | ||
| 206 | std::scoped_lock lk{m_rebuild_lock, m_lock}; | ||
| 207 | |||
| 208 | ASSERT(!m_resident_mappings.empty()); | ||
| 209 | |||
| 210 | // Dump half of the mappings. | ||
| 211 | // | ||
| 212 | // Despite being worse in theory, this has proven to be better in practice than more | ||
| 213 | // regularly dumping a smaller amount, because it significantly reduces average case | ||
| 214 | // lock contention. | ||
| 215 | const size_t desired_count = std::min(m_resident_map_count, m_max_resident_map_count) / 2; | ||
| 216 | const size_t evict_count = m_resident_map_count - desired_count; | ||
| 217 | auto it = m_resident_mappings.begin(); | ||
| 218 | |||
| 219 | for (size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) { | ||
| 220 | // Unmark and unmap. | ||
| 221 | it->is_resident = false; | ||
| 222 | m_buffer.Unmap(it->vaddr, it->size, false); | ||
| 223 | |||
| 224 | // Advance. | ||
| 225 | ASSERT(--m_resident_map_count >= 0); | ||
| 226 | it = m_resident_mappings.erase(it); | ||
| 227 | } | ||
| 228 | } | ||
| 229 | |||
| 230 | void HeapTracker::SplitHeapMap(VAddr offset, size_t size) { | ||
| 231 | std::scoped_lock lk{m_lock}; | ||
| 232 | |||
| 233 | this->SplitHeapMapLocked(offset); | ||
| 234 | this->SplitHeapMapLocked(offset + size); | ||
| 235 | } | ||
| 236 | |||
| 237 | void HeapTracker::SplitHeapMapLocked(VAddr offset) { | ||
| 238 | const auto it = this->GetNearestHeapMapLocked(offset); | ||
| 239 | if (it == m_mappings.end() || it->vaddr == offset) { | ||
| 240 | // Not contained or no split required. | ||
| 241 | return; | ||
| 242 | } | ||
| 243 | |||
| 244 | // Cache the original values. | ||
| 245 | auto* const left = std::addressof(*it); | ||
| 246 | const size_t orig_size = left->size; | ||
| 247 | |||
| 248 | // Adjust the left map. | ||
| 249 | const size_t left_size = offset - left->vaddr; | ||
| 250 | left->size = left_size; | ||
| 251 | |||
| 252 | // Create the new right map. | ||
| 253 | auto* const right = new SeparateHeapMap{ | ||
| 254 | .vaddr = left->vaddr + left_size, | ||
| 255 | .paddr = left->paddr + left_size, | ||
| 256 | .size = orig_size - left_size, | ||
| 257 | .tick = left->tick, | ||
| 258 | .perm = left->perm, | ||
| 259 | .is_resident = left->is_resident, | ||
| 260 | }; | ||
| 261 | |||
| 262 | // Insert the new right map. | ||
| 263 | m_map_count++; | ||
| 264 | m_mappings.insert(*right); | ||
| 265 | |||
| 266 | // If resident, also insert into resident map. | ||
| 267 | if (right->is_resident) { | ||
| 268 | m_resident_map_count++; | ||
| 269 | m_resident_mappings.insert(*right); | ||
| 270 | } | ||
| 271 | } | ||
| 272 | |||
| 273 | HeapTracker::AddrTree::iterator HeapTracker::GetNearestHeapMapLocked(VAddr offset) { | ||
| 274 | const SeparateHeapMap key{ | ||
| 275 | .vaddr = offset, | ||
| 276 | }; | ||
| 277 | |||
| 278 | return m_mappings.find(key); | ||
| 279 | } | ||
| 280 | |||
| 281 | } // namespace Common | ||
diff --git a/src/common/heap_tracker.h b/src/common/heap_tracker.h new file mode 100644 index 000000000..ee5b0bf43 --- /dev/null +++ b/src/common/heap_tracker.h | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <atomic> | ||
| 7 | #include <mutex> | ||
| 8 | #include <set> | ||
| 9 | #include <shared_mutex> | ||
| 10 | |||
| 11 | #include "common/host_memory.h" | ||
| 12 | #include "common/intrusive_red_black_tree.h" | ||
| 13 | |||
| 14 | namespace Common { | ||
| 15 | |||
| 16 | struct SeparateHeapMap { | ||
| 17 | Common::IntrusiveRedBlackTreeNode addr_node{}; | ||
| 18 | Common::IntrusiveRedBlackTreeNode tick_node{}; | ||
| 19 | VAddr vaddr{}; | ||
| 20 | PAddr paddr{}; | ||
| 21 | size_t size{}; | ||
| 22 | size_t tick{}; | ||
| 23 | MemoryPermission perm{}; | ||
| 24 | bool is_resident{}; | ||
| 25 | }; | ||
| 26 | |||
| 27 | struct SeparateHeapMapAddrComparator { | ||
| 28 | static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) { | ||
| 29 | if (lhs.vaddr < rhs.vaddr) { | ||
| 30 | return -1; | ||
| 31 | } else if (lhs.vaddr <= (rhs.vaddr + rhs.size - 1)) { | ||
| 32 | return 0; | ||
| 33 | } else { | ||
| 34 | return 1; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | }; | ||
| 38 | |||
| 39 | struct SeparateHeapMapTickComparator { | ||
| 40 | static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) { | ||
| 41 | if (lhs.tick < rhs.tick) { | ||
| 42 | return -1; | ||
| 43 | } else if (lhs.tick > rhs.tick) { | ||
| 44 | return 1; | ||
| 45 | } else { | ||
| 46 | return SeparateHeapMapAddrComparator::Compare(lhs, rhs); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | }; | ||
| 50 | |||
| 51 | class HeapTracker { | ||
| 52 | public: | ||
| 53 | explicit HeapTracker(Common::HostMemory& buffer); | ||
| 54 | ~HeapTracker(); | ||
| 55 | |||
| 56 | void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm, | ||
| 57 | bool is_separate_heap); | ||
| 58 | void Unmap(size_t virtual_offset, size_t size, bool is_separate_heap); | ||
| 59 | void Protect(size_t virtual_offset, size_t length, MemoryPermission perm); | ||
| 60 | u8* VirtualBasePointer() { | ||
| 61 | return m_buffer.VirtualBasePointer(); | ||
| 62 | } | ||
| 63 | |||
| 64 | bool DeferredMapSeparateHeap(u8* fault_address); | ||
| 65 | bool DeferredMapSeparateHeap(size_t virtual_offset); | ||
| 66 | |||
| 67 | private: | ||
| 68 | using AddrTreeTraits = | ||
| 69 | Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::addr_node>; | ||
| 70 | using AddrTree = AddrTreeTraits::TreeType<SeparateHeapMapAddrComparator>; | ||
| 71 | |||
| 72 | using TickTreeTraits = | ||
| 73 | Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::tick_node>; | ||
| 74 | using TickTree = TickTreeTraits::TreeType<SeparateHeapMapTickComparator>; | ||
| 75 | |||
| 76 | AddrTree m_mappings{}; | ||
| 77 | TickTree m_resident_mappings{}; | ||
| 78 | |||
| 79 | private: | ||
| 80 | void SplitHeapMap(VAddr offset, size_t size); | ||
| 81 | void SplitHeapMapLocked(VAddr offset); | ||
| 82 | |||
| 83 | AddrTree::iterator GetNearestHeapMapLocked(VAddr offset); | ||
| 84 | |||
| 85 | void RebuildSeparateHeapAddressSpace(); | ||
| 86 | |||
| 87 | private: | ||
| 88 | Common::HostMemory& m_buffer; | ||
| 89 | const s64 m_max_resident_map_count; | ||
| 90 | |||
| 91 | std::shared_mutex m_rebuild_lock{}; | ||
| 92 | std::mutex m_lock{}; | ||
| 93 | s64 m_map_count{}; | ||
| 94 | s64 m_resident_map_count{}; | ||
| 95 | size_t m_tick{}; | ||
| 96 | }; | ||
| 97 | |||
| 98 | } // namespace Common | ||
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index e540375b8..860c39e6a 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp | |||
| @@ -679,7 +679,7 @@ HostMemory::HostMemory(HostMemory&&) noexcept = default; | |||
| 679 | HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default; | 679 | HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default; |
| 680 | 680 | ||
| 681 | void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length, | 681 | void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length, |
| 682 | MemoryPermission perms) { | 682 | MemoryPermission perms, bool separate_heap) { |
| 683 | ASSERT(virtual_offset % PageAlignment == 0); | 683 | ASSERT(virtual_offset % PageAlignment == 0); |
| 684 | ASSERT(host_offset % PageAlignment == 0); | 684 | ASSERT(host_offset % PageAlignment == 0); |
| 685 | ASSERT(length % PageAlignment == 0); | 685 | ASSERT(length % PageAlignment == 0); |
| @@ -691,7 +691,7 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length, | |||
| 691 | impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms); | 691 | impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms); |
| 692 | } | 692 | } |
| 693 | 693 | ||
| 694 | void HostMemory::Unmap(size_t virtual_offset, size_t length) { | 694 | void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) { |
| 695 | ASSERT(virtual_offset % PageAlignment == 0); | 695 | ASSERT(virtual_offset % PageAlignment == 0); |
| 696 | ASSERT(length % PageAlignment == 0); | 696 | ASSERT(length % PageAlignment == 0); |
| 697 | ASSERT(virtual_offset + length <= virtual_size); | 697 | ASSERT(virtual_offset + length <= virtual_size); |
| @@ -701,14 +701,16 @@ void HostMemory::Unmap(size_t virtual_offset, size_t length) { | |||
| 701 | impl->Unmap(virtual_offset + virtual_base_offset, length); | 701 | impl->Unmap(virtual_offset + virtual_base_offset, length); |
| 702 | } | 702 | } |
| 703 | 703 | ||
| 704 | void HostMemory::Protect(size_t virtual_offset, size_t length, bool read, bool write, | 704 | void HostMemory::Protect(size_t virtual_offset, size_t length, MemoryPermission perm) { |
| 705 | bool execute) { | ||
| 706 | ASSERT(virtual_offset % PageAlignment == 0); | 705 | ASSERT(virtual_offset % PageAlignment == 0); |
| 707 | ASSERT(length % PageAlignment == 0); | 706 | ASSERT(length % PageAlignment == 0); |
| 708 | ASSERT(virtual_offset + length <= virtual_size); | 707 | ASSERT(virtual_offset + length <= virtual_size); |
| 709 | if (length == 0 || !virtual_base || !impl) { | 708 | if (length == 0 || !virtual_base || !impl) { |
| 710 | return; | 709 | return; |
| 711 | } | 710 | } |
| 711 | const bool read = True(perm & MemoryPermission::Read); | ||
| 712 | const bool write = True(perm & MemoryPermission::Write); | ||
| 713 | const bool execute = True(perm & MemoryPermission::Execute); | ||
| 712 | impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute); | 714 | impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute); |
| 713 | } | 715 | } |
| 714 | 716 | ||
diff --git a/src/common/host_memory.h b/src/common/host_memory.h index 747c5850c..72fbb05af 100644 --- a/src/common/host_memory.h +++ b/src/common/host_memory.h | |||
| @@ -40,11 +40,12 @@ public: | |||
| 40 | HostMemory(HostMemory&& other) noexcept; | 40 | HostMemory(HostMemory&& other) noexcept; |
| 41 | HostMemory& operator=(HostMemory&& other) noexcept; | 41 | HostMemory& operator=(HostMemory&& other) noexcept; |
| 42 | 42 | ||
| 43 | void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms); | 43 | void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms, |
| 44 | bool separate_heap); | ||
| 44 | 45 | ||
| 45 | void Unmap(size_t virtual_offset, size_t length); | 46 | void Unmap(size_t virtual_offset, size_t length, bool separate_heap); |
| 46 | 47 | ||
| 47 | void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute = false); | 48 | void Protect(size_t virtual_offset, size_t length, MemoryPermission perms); |
| 48 | 49 | ||
| 49 | void EnableDirectMappedAddress(); | 50 | void EnableDirectMappedAddress(); |
| 50 | 51 | ||
| @@ -64,6 +65,10 @@ public: | |||
| 64 | return virtual_base; | 65 | return virtual_base; |
| 65 | } | 66 | } |
| 66 | 67 | ||
| 68 | bool IsInVirtualRange(void* address) const noexcept { | ||
| 69 | return address >= virtual_base && address < virtual_base + virtual_size; | ||
| 70 | } | ||
| 71 | |||
| 67 | private: | 72 | private: |
| 68 | size_t backing_size{}; | 73 | size_t backing_size{}; |
| 69 | size_t virtual_size{}; | 74 | size_t virtual_size{}; |
diff --git a/src/common/settings.cpp b/src/common/settings.cpp index ea52bbfa6..07709d4e5 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp | |||
| @@ -199,6 +199,8 @@ const char* TranslateCategory(Category category) { | |||
| 199 | case Category::CpuDebug: | 199 | case Category::CpuDebug: |
| 200 | case Category::CpuUnsafe: | 200 | case Category::CpuUnsafe: |
| 201 | return "Cpu"; | 201 | return "Cpu"; |
| 202 | case Category::Overlay: | ||
| 203 | return "Overlay"; | ||
| 202 | case Category::Renderer: | 204 | case Category::Renderer: |
| 203 | case Category::RendererAdvanced: | 205 | case Category::RendererAdvanced: |
| 204 | case Category::RendererDebug: | 206 | case Category::RendererDebug: |
diff --git a/src/common/settings_common.h b/src/common/settings_common.h index c82e17495..1a290ad77 100644 --- a/src/common/settings_common.h +++ b/src/common/settings_common.h | |||
| @@ -18,6 +18,7 @@ enum class Category : u32 { | |||
| 18 | Cpu, | 18 | Cpu, |
| 19 | CpuDebug, | 19 | CpuDebug, |
| 20 | CpuUnsafe, | 20 | CpuUnsafe, |
| 21 | Overlay, | ||
| 21 | Renderer, | 22 | Renderer, |
| 22 | RendererAdvanced, | 23 | RendererAdvanced, |
| 23 | RendererDebug, | 24 | RendererDebug, |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 96ab39cb8..dfba79267 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -553,17 +553,26 @@ add_library(core STATIC | |||
| 553 | hle/service/hid/controllers/types/keyboard_types.h | 553 | hle/service/hid/controllers/types/keyboard_types.h |
| 554 | hle/service/hid/controllers/types/mouse_types.h | 554 | hle/service/hid/controllers/types/mouse_types.h |
| 555 | hle/service/hid/controllers/types/npad_types.h | 555 | hle/service/hid/controllers/types/npad_types.h |
| 556 | hle/service/hid/controllers/types/shared_memory_format.h | ||
| 556 | hle/service/hid/controllers/types/touch_types.h | 557 | hle/service/hid/controllers/types/touch_types.h |
| 557 | hle/service/hid/controllers/applet_resource.cpp | 558 | hle/service/hid/controllers/applet_resource.cpp |
| 558 | hle/service/hid/controllers/applet_resource.h | 559 | hle/service/hid/controllers/applet_resource.h |
| 560 | hle/service/hid/controllers/capture_button.cpp | ||
| 561 | hle/service/hid/controllers/capture_button.h | ||
| 559 | hle/service/hid/controllers/console_six_axis.cpp | 562 | hle/service/hid/controllers/console_six_axis.cpp |
| 560 | hle/service/hid/controllers/console_six_axis.h | 563 | hle/service/hid/controllers/console_six_axis.h |
| 561 | hle/service/hid/controllers/controller_base.cpp | 564 | hle/service/hid/controllers/controller_base.cpp |
| 562 | hle/service/hid/controllers/controller_base.h | 565 | hle/service/hid/controllers/controller_base.h |
| 566 | hle/service/hid/controllers/debug_mouse.cpp | ||
| 567 | hle/service/hid/controllers/debug_mouse.h | ||
| 563 | hle/service/hid/controllers/debug_pad.cpp | 568 | hle/service/hid/controllers/debug_pad.cpp |
| 564 | hle/service/hid/controllers/debug_pad.h | 569 | hle/service/hid/controllers/debug_pad.h |
| 570 | hle/service/hid/controllers/digitizer.cpp | ||
| 571 | hle/service/hid/controllers/digitizer.h | ||
| 565 | hle/service/hid/controllers/gesture.cpp | 572 | hle/service/hid/controllers/gesture.cpp |
| 566 | hle/service/hid/controllers/gesture.h | 573 | hle/service/hid/controllers/gesture.h |
| 574 | hle/service/hid/controllers/home_button.cpp | ||
| 575 | hle/service/hid/controllers/home_button.h | ||
| 567 | hle/service/hid/controllers/keyboard.cpp | 576 | hle/service/hid/controllers/keyboard.cpp |
| 568 | hle/service/hid/controllers/keyboard.h | 577 | hle/service/hid/controllers/keyboard.h |
| 569 | hle/service/hid/controllers/mouse.cpp | 578 | hle/service/hid/controllers/mouse.cpp |
| @@ -574,15 +583,16 @@ add_library(core STATIC | |||
| 574 | hle/service/hid/controllers/palma.h | 583 | hle/service/hid/controllers/palma.h |
| 575 | hle/service/hid/controllers/seven_six_axis.cpp | 584 | hle/service/hid/controllers/seven_six_axis.cpp |
| 576 | hle/service/hid/controllers/seven_six_axis.h | 585 | hle/service/hid/controllers/seven_six_axis.h |
| 577 | hle/service/hid/controllers/shared_memory_format.h | ||
| 578 | hle/service/hid/controllers/shared_memory_holder.cpp | 586 | hle/service/hid/controllers/shared_memory_holder.cpp |
| 579 | hle/service/hid/controllers/shared_memory_holder.h | 587 | hle/service/hid/controllers/shared_memory_holder.h |
| 580 | hle/service/hid/controllers/six_axis.cpp | 588 | hle/service/hid/controllers/six_axis.cpp |
| 581 | hle/service/hid/controllers/six_axis.h | 589 | hle/service/hid/controllers/six_axis.h |
| 582 | hle/service/hid/controllers/stubbed.cpp | 590 | hle/service/hid/controllers/sleep_button.cpp |
| 583 | hle/service/hid/controllers/stubbed.h | 591 | hle/service/hid/controllers/sleep_button.h |
| 584 | hle/service/hid/controllers/touchscreen.cpp | 592 | hle/service/hid/controllers/touchscreen.cpp |
| 585 | hle/service/hid/controllers/touchscreen.h | 593 | hle/service/hid/controllers/touchscreen.h |
| 594 | hle/service/hid/controllers/unique_pad.cpp | ||
| 595 | hle/service/hid/controllers/unique_pad.h | ||
| 586 | hle/service/hid/hidbus/hidbus_base.cpp | 596 | hle/service/hid/hidbus/hidbus_base.cpp |
| 587 | hle/service/hid/hidbus/hidbus_base.h | 597 | hle/service/hid/hidbus/hidbus_base.h |
| 588 | hle/service/hid/hidbus/ringcon.cpp | 598 | hle/service/hid/hidbus/ringcon.cpp |
| @@ -978,6 +988,7 @@ endif() | |||
| 978 | 988 | ||
| 979 | if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) | 989 | if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) |
| 980 | target_sources(core PRIVATE | 990 | target_sources(core PRIVATE |
| 991 | arm/dynarmic/arm_dynarmic.cpp | ||
| 981 | arm/dynarmic/arm_dynarmic.h | 992 | arm/dynarmic/arm_dynarmic.h |
| 982 | arm/dynarmic/arm_dynarmic_64.cpp | 993 | arm/dynarmic/arm_dynarmic_64.cpp |
| 983 | arm/dynarmic/arm_dynarmic_64.h | 994 | arm/dynarmic/arm_dynarmic_64.h |
| @@ -987,6 +998,8 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) | |||
| 987 | arm/dynarmic/dynarmic_cp15.h | 998 | arm/dynarmic/dynarmic_cp15.h |
| 988 | arm/dynarmic/dynarmic_exclusive_monitor.cpp | 999 | arm/dynarmic/dynarmic_exclusive_monitor.cpp |
| 989 | arm/dynarmic/dynarmic_exclusive_monitor.h | 1000 | arm/dynarmic/dynarmic_exclusive_monitor.h |
| 1001 | hle/service/jit/jit_code_memory.cpp | ||
| 1002 | hle/service/jit/jit_code_memory.h | ||
| 990 | hle/service/jit/jit_context.cpp | 1003 | hle/service/jit/jit_context.cpp |
| 991 | hle/service/jit/jit_context.h | 1004 | hle/service/jit/jit_context.h |
| 992 | hle/service/jit/jit.cpp | 1005 | hle/service/jit/jit.cpp |
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp new file mode 100644 index 000000000..e6e9fc45b --- /dev/null +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #ifdef __linux__ | ||
| 5 | |||
| 6 | #include "common/signal_chain.h" | ||
| 7 | |||
| 8 | #include "core/arm/dynarmic/arm_dynarmic.h" | ||
| 9 | #include "core/hle/kernel/k_process.h" | ||
| 10 | #include "core/memory.h" | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | |||
| 14 | namespace { | ||
| 15 | |||
| 16 | thread_local Core::Memory::Memory* g_current_memory{}; | ||
| 17 | std::once_flag g_registered{}; | ||
| 18 | struct sigaction g_old_segv {}; | ||
| 19 | |||
| 20 | void HandleSigSegv(int sig, siginfo_t* info, void* ctx) { | ||
| 21 | if (g_current_memory && g_current_memory->InvalidateSeparateHeap(info->si_addr)) { | ||
| 22 | return; | ||
| 23 | } | ||
| 24 | |||
| 25 | return g_old_segv.sa_sigaction(sig, info, ctx); | ||
| 26 | } | ||
| 27 | |||
| 28 | } // namespace | ||
| 29 | |||
| 30 | ScopedJitExecution::ScopedJitExecution(Kernel::KProcess* process) { | ||
| 31 | g_current_memory = std::addressof(process->GetMemory()); | ||
| 32 | } | ||
| 33 | |||
| 34 | ScopedJitExecution::~ScopedJitExecution() { | ||
| 35 | g_current_memory = nullptr; | ||
| 36 | } | ||
| 37 | |||
| 38 | void ScopedJitExecution::RegisterHandler() { | ||
| 39 | std::call_once(g_registered, [] { | ||
| 40 | struct sigaction sa {}; | ||
| 41 | sa.sa_sigaction = &HandleSigSegv; | ||
| 42 | sa.sa_flags = SA_SIGINFO | SA_ONSTACK; | ||
| 43 | Common::SigAction(SIGSEGV, std::addressof(sa), std::addressof(g_old_segv)); | ||
| 44 | }); | ||
| 45 | } | ||
| 46 | |||
| 47 | } // namespace Core | ||
| 48 | |||
| 49 | #endif | ||
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index eef7c3116..53dd18815 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h | |||
| @@ -26,4 +26,24 @@ constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) { | |||
| 26 | return static_cast<HaltReason>(hr); | 26 | return static_cast<HaltReason>(hr); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | #ifdef __linux__ | ||
| 30 | |||
| 31 | class ScopedJitExecution { | ||
| 32 | public: | ||
| 33 | explicit ScopedJitExecution(Kernel::KProcess* process); | ||
| 34 | ~ScopedJitExecution(); | ||
| 35 | static void RegisterHandler(); | ||
| 36 | }; | ||
| 37 | |||
| 38 | #else | ||
| 39 | |||
| 40 | class ScopedJitExecution { | ||
| 41 | public: | ||
| 42 | explicit ScopedJitExecution(Kernel::KProcess* process) {} | ||
| 43 | ~ScopedJitExecution() {} | ||
| 44 | static void RegisterHandler() {} | ||
| 45 | }; | ||
| 46 | |||
| 47 | #endif | ||
| 48 | |||
| 29 | } // namespace Core | 49 | } // namespace Core |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index c78cfd528..36478f722 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp | |||
| @@ -331,11 +331,15 @@ bool ArmDynarmic32::IsInThumbMode() const { | |||
| 331 | } | 331 | } |
| 332 | 332 | ||
| 333 | HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) { | 333 | HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) { |
| 334 | ScopedJitExecution sj(thread->GetOwnerProcess()); | ||
| 335 | |||
| 334 | m_jit->ClearExclusiveState(); | 336 | m_jit->ClearExclusiveState(); |
| 335 | return TranslateHaltReason(m_jit->Run()); | 337 | return TranslateHaltReason(m_jit->Run()); |
| 336 | } | 338 | } |
| 337 | 339 | ||
| 338 | HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) { | 340 | HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) { |
| 341 | ScopedJitExecution sj(thread->GetOwnerProcess()); | ||
| 342 | |||
| 339 | m_jit->ClearExclusiveState(); | 343 | m_jit->ClearExclusiveState(); |
| 340 | return TranslateHaltReason(m_jit->Step()); | 344 | return TranslateHaltReason(m_jit->Step()); |
| 341 | } | 345 | } |
| @@ -377,6 +381,7 @@ ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProc | |||
| 377 | m_cp15(std::make_shared<DynarmicCP15>(*this)), m_core_index{core_index} { | 381 | m_cp15(std::make_shared<DynarmicCP15>(*this)), m_core_index{core_index} { |
| 378 | auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl(); | 382 | auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl(); |
| 379 | m_jit = MakeJit(&page_table_impl); | 383 | m_jit = MakeJit(&page_table_impl); |
| 384 | ScopedJitExecution::RegisterHandler(); | ||
| 380 | } | 385 | } |
| 381 | 386 | ||
| 382 | ArmDynarmic32::~ArmDynarmic32() = default; | 387 | ArmDynarmic32::~ArmDynarmic32() = default; |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index f351b13d9..c811c8ad5 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp | |||
| @@ -362,11 +362,15 @@ std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* pa | |||
| 362 | } | 362 | } |
| 363 | 363 | ||
| 364 | HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) { | 364 | HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) { |
| 365 | ScopedJitExecution sj(thread->GetOwnerProcess()); | ||
| 366 | |||
| 365 | m_jit->ClearExclusiveState(); | 367 | m_jit->ClearExclusiveState(); |
| 366 | return TranslateHaltReason(m_jit->Run()); | 368 | return TranslateHaltReason(m_jit->Run()); |
| 367 | } | 369 | } |
| 368 | 370 | ||
| 369 | HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) { | 371 | HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) { |
| 372 | ScopedJitExecution sj(thread->GetOwnerProcess()); | ||
| 373 | |||
| 370 | m_jit->ClearExclusiveState(); | 374 | m_jit->ClearExclusiveState(); |
| 371 | return TranslateHaltReason(m_jit->Step()); | 375 | return TranslateHaltReason(m_jit->Step()); |
| 372 | } | 376 | } |
| @@ -406,6 +410,7 @@ ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProc | |||
| 406 | auto& page_table = process->GetPageTable().GetBasePageTable(); | 410 | auto& page_table = process->GetPageTable().GetBasePageTable(); |
| 407 | auto& page_table_impl = page_table.GetImpl(); | 411 | auto& page_table_impl = page_table.GetImpl(); |
| 408 | m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth()); | 412 | m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth()); |
| 413 | ScopedJitExecution::RegisterHandler(); | ||
| 409 | } | 414 | } |
| 410 | 415 | ||
| 411 | ArmDynarmic64::~ArmDynarmic64() = default; | 416 | ArmDynarmic64::~ArmDynarmic64() = default; |
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index d6b5abc68..fc536413b 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp | |||
| @@ -29,7 +29,6 @@ std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callbac | |||
| 29 | struct CoreTiming::Event { | 29 | struct CoreTiming::Event { |
| 30 | s64 time; | 30 | s64 time; |
| 31 | u64 fifo_order; | 31 | u64 fifo_order; |
| 32 | std::uintptr_t user_data; | ||
| 33 | std::weak_ptr<EventType> type; | 32 | std::weak_ptr<EventType> type; |
| 34 | s64 reschedule_time; | 33 | s64 reschedule_time; |
| 35 | heap_t::handle_type handle{}; | 34 | heap_t::handle_type handle{}; |
| @@ -67,17 +66,15 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) { | |||
| 67 | event_fifo_id = 0; | 66 | event_fifo_id = 0; |
| 68 | shutting_down = false; | 67 | shutting_down = false; |
| 69 | cpu_ticks = 0; | 68 | cpu_ticks = 0; |
| 70 | const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds) | ||
| 71 | -> std::optional<std::chrono::nanoseconds> { return std::nullopt; }; | ||
| 72 | ev_lost = CreateEvent("_lost_event", empty_timed_callback); | ||
| 73 | if (is_multicore) { | 69 | if (is_multicore) { |
| 74 | timer_thread = std::make_unique<std::jthread>(ThreadEntry, std::ref(*this)); | 70 | timer_thread = std::make_unique<std::jthread>(ThreadEntry, std::ref(*this)); |
| 75 | } | 71 | } |
| 76 | } | 72 | } |
| 77 | 73 | ||
| 78 | void CoreTiming::ClearPendingEvents() { | 74 | void CoreTiming::ClearPendingEvents() { |
| 79 | std::scoped_lock lock{basic_lock}; | 75 | std::scoped_lock lock{advance_lock, basic_lock}; |
| 80 | event_queue.clear(); | 76 | event_queue.clear(); |
| 77 | event.Set(); | ||
| 81 | } | 78 | } |
| 82 | 79 | ||
| 83 | void CoreTiming::Pause(bool is_paused) { | 80 | void CoreTiming::Pause(bool is_paused) { |
| @@ -119,14 +116,12 @@ bool CoreTiming::HasPendingEvents() const { | |||
| 119 | } | 116 | } |
| 120 | 117 | ||
| 121 | void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future, | 118 | void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future, |
| 122 | const std::shared_ptr<EventType>& event_type, | 119 | const std::shared_ptr<EventType>& event_type, bool absolute_time) { |
| 123 | std::uintptr_t user_data, bool absolute_time) { | ||
| 124 | { | 120 | { |
| 125 | std::scoped_lock scope{basic_lock}; | 121 | std::scoped_lock scope{basic_lock}; |
| 126 | const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future}; | 122 | const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future}; |
| 127 | 123 | ||
| 128 | auto h{event_queue.emplace( | 124 | auto h{event_queue.emplace(Event{next_time.count(), event_fifo_id++, event_type, 0})}; |
| 129 | Event{next_time.count(), event_fifo_id++, user_data, event_type, 0})}; | ||
| 130 | (*h).handle = h; | 125 | (*h).handle = h; |
| 131 | } | 126 | } |
| 132 | 127 | ||
| @@ -136,13 +131,13 @@ void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future, | |||
| 136 | void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time, | 131 | void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time, |
| 137 | std::chrono::nanoseconds resched_time, | 132 | std::chrono::nanoseconds resched_time, |
| 138 | const std::shared_ptr<EventType>& event_type, | 133 | const std::shared_ptr<EventType>& event_type, |
| 139 | std::uintptr_t user_data, bool absolute_time) { | 134 | bool absolute_time) { |
| 140 | { | 135 | { |
| 141 | std::scoped_lock scope{basic_lock}; | 136 | std::scoped_lock scope{basic_lock}; |
| 142 | const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time}; | 137 | const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time}; |
| 143 | 138 | ||
| 144 | auto h{event_queue.emplace(Event{next_time.count(), event_fifo_id++, user_data, event_type, | 139 | auto h{event_queue.emplace( |
| 145 | resched_time.count()})}; | 140 | Event{next_time.count(), event_fifo_id++, event_type, resched_time.count()})}; |
| 146 | (*h).handle = h; | 141 | (*h).handle = h; |
| 147 | } | 142 | } |
| 148 | 143 | ||
| @@ -150,14 +145,14 @@ void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time, | |||
| 150 | } | 145 | } |
| 151 | 146 | ||
| 152 | void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, | 147 | void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, |
| 153 | std::uintptr_t user_data, bool wait) { | 148 | UnscheduleEventType type) { |
| 154 | { | 149 | { |
| 155 | std::scoped_lock lk{basic_lock}; | 150 | std::scoped_lock lk{basic_lock}; |
| 156 | 151 | ||
| 157 | std::vector<heap_t::handle_type> to_remove; | 152 | std::vector<heap_t::handle_type> to_remove; |
| 158 | for (auto itr = event_queue.begin(); itr != event_queue.end(); itr++) { | 153 | for (auto itr = event_queue.begin(); itr != event_queue.end(); itr++) { |
| 159 | const Event& e = *itr; | 154 | const Event& e = *itr; |
| 160 | if (e.type.lock().get() == event_type.get() && e.user_data == user_data) { | 155 | if (e.type.lock().get() == event_type.get()) { |
| 161 | to_remove.push_back(itr->handle); | 156 | to_remove.push_back(itr->handle); |
| 162 | } | 157 | } |
| 163 | } | 158 | } |
| @@ -165,10 +160,12 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, | |||
| 165 | for (auto h : to_remove) { | 160 | for (auto h : to_remove) { |
| 166 | event_queue.erase(h); | 161 | event_queue.erase(h); |
| 167 | } | 162 | } |
| 163 | |||
| 164 | event_type->sequence_number++; | ||
| 168 | } | 165 | } |
| 169 | 166 | ||
| 170 | // Force any in-progress events to finish | 167 | // Force any in-progress events to finish |
| 171 | if (wait) { | 168 | if (type == UnscheduleEventType::Wait) { |
| 172 | std::scoped_lock lk{advance_lock}; | 169 | std::scoped_lock lk{advance_lock}; |
| 173 | } | 170 | } |
| 174 | } | 171 | } |
| @@ -208,28 +205,31 @@ std::optional<s64> CoreTiming::Advance() { | |||
| 208 | const Event& evt = event_queue.top(); | 205 | const Event& evt = event_queue.top(); |
| 209 | 206 | ||
| 210 | if (const auto event_type{evt.type.lock()}) { | 207 | if (const auto event_type{evt.type.lock()}) { |
| 211 | if (evt.reschedule_time == 0) { | 208 | const auto evt_time = evt.time; |
| 212 | const auto evt_user_data = evt.user_data; | 209 | const auto evt_sequence_num = event_type->sequence_number; |
| 213 | const auto evt_time = evt.time; | ||
| 214 | 210 | ||
| 211 | if (evt.reschedule_time == 0) { | ||
| 215 | event_queue.pop(); | 212 | event_queue.pop(); |
| 216 | 213 | ||
| 217 | basic_lock.unlock(); | 214 | basic_lock.unlock(); |
| 218 | 215 | ||
| 219 | event_type->callback( | 216 | event_type->callback( |
| 220 | evt_user_data, evt_time, | 217 | evt_time, std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt_time}); |
| 221 | std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt_time}); | ||
| 222 | 218 | ||
| 223 | basic_lock.lock(); | 219 | basic_lock.lock(); |
| 224 | } else { | 220 | } else { |
| 225 | basic_lock.unlock(); | 221 | basic_lock.unlock(); |
| 226 | 222 | ||
| 227 | const auto new_schedule_time{event_type->callback( | 223 | const auto new_schedule_time{event_type->callback( |
| 228 | evt.user_data, evt.time, | 224 | evt_time, std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt_time})}; |
| 229 | std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt.time})}; | ||
| 230 | 225 | ||
| 231 | basic_lock.lock(); | 226 | basic_lock.lock(); |
| 232 | 227 | ||
| 228 | if (evt_sequence_num != event_type->sequence_number) { | ||
| 229 | // Heap handle is invalidated after external modification. | ||
| 230 | continue; | ||
| 231 | } | ||
| 232 | |||
| 233 | const auto next_schedule_time{new_schedule_time.has_value() | 233 | const auto next_schedule_time{new_schedule_time.has_value() |
| 234 | ? new_schedule_time.value().count() | 234 | ? new_schedule_time.value().count() |
| 235 | : evt.reschedule_time}; | 235 | : evt.reschedule_time}; |
| @@ -241,8 +241,8 @@ std::optional<s64> CoreTiming::Advance() { | |||
| 241 | next_time = pause_end_time + next_schedule_time; | 241 | next_time = pause_end_time + next_schedule_time; |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | event_queue.update(evt.handle, Event{next_time, event_fifo_id++, evt.user_data, | 244 | event_queue.update(evt.handle, Event{next_time, event_fifo_id++, evt.type, |
| 245 | evt.type, next_schedule_time, evt.handle}); | 245 | next_schedule_time, evt.handle}); |
| 246 | } | 246 | } |
| 247 | } | 247 | } |
| 248 | 248 | ||
diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 21548f0a9..7e4dff7f3 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h | |||
| @@ -22,17 +22,25 @@ namespace Core::Timing { | |||
| 22 | 22 | ||
| 23 | /// A callback that may be scheduled for a particular core timing event. | 23 | /// A callback that may be scheduled for a particular core timing event. |
| 24 | using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>( | 24 | using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>( |
| 25 | std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)>; | 25 | s64 time, std::chrono::nanoseconds ns_late)>; |
| 26 | 26 | ||
| 27 | /// Contains the characteristics of a particular event. | 27 | /// Contains the characteristics of a particular event. |
| 28 | struct EventType { | 28 | struct EventType { |
| 29 | explicit EventType(TimedCallback&& callback_, std::string&& name_) | 29 | explicit EventType(TimedCallback&& callback_, std::string&& name_) |
| 30 | : callback{std::move(callback_)}, name{std::move(name_)} {} | 30 | : callback{std::move(callback_)}, name{std::move(name_)}, sequence_number{0} {} |
| 31 | 31 | ||
| 32 | /// The event's callback function. | 32 | /// The event's callback function. |
| 33 | TimedCallback callback; | 33 | TimedCallback callback; |
| 34 | /// A pointer to the name of the event. | 34 | /// A pointer to the name of the event. |
| 35 | const std::string name; | 35 | const std::string name; |
| 36 | /// A monotonic sequence number, incremented when this event is | ||
| 37 | /// changed externally. | ||
| 38 | size_t sequence_number; | ||
| 39 | }; | ||
| 40 | |||
| 41 | enum class UnscheduleEventType { | ||
| 42 | Wait, | ||
| 43 | NoWait, | ||
| 36 | }; | 44 | }; |
| 37 | 45 | ||
| 38 | /** | 46 | /** |
| @@ -89,23 +97,17 @@ public: | |||
| 89 | 97 | ||
| 90 | /// Schedules an event in core timing | 98 | /// Schedules an event in core timing |
| 91 | void ScheduleEvent(std::chrono::nanoseconds ns_into_future, | 99 | void ScheduleEvent(std::chrono::nanoseconds ns_into_future, |
| 92 | const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0, | 100 | const std::shared_ptr<EventType>& event_type, bool absolute_time = false); |
| 93 | bool absolute_time = false); | ||
| 94 | 101 | ||
| 95 | /// Schedules an event which will automatically re-schedule itself with the given time, until | 102 | /// Schedules an event which will automatically re-schedule itself with the given time, until |
| 96 | /// unscheduled | 103 | /// unscheduled |
| 97 | void ScheduleLoopingEvent(std::chrono::nanoseconds start_time, | 104 | void ScheduleLoopingEvent(std::chrono::nanoseconds start_time, |
| 98 | std::chrono::nanoseconds resched_time, | 105 | std::chrono::nanoseconds resched_time, |
| 99 | const std::shared_ptr<EventType>& event_type, | 106 | const std::shared_ptr<EventType>& event_type, |
| 100 | std::uintptr_t user_data = 0, bool absolute_time = false); | 107 | bool absolute_time = false); |
| 101 | 108 | ||
| 102 | void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data, | 109 | void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, |
| 103 | bool wait = true); | 110 | UnscheduleEventType type = UnscheduleEventType::Wait); |
| 104 | |||
| 105 | void UnscheduleEventWithoutWait(const std::shared_ptr<EventType>& event_type, | ||
| 106 | std::uintptr_t user_data) { | ||
| 107 | UnscheduleEvent(event_type, user_data, false); | ||
| 108 | } | ||
| 109 | 111 | ||
| 110 | void AddTicks(u64 ticks_to_add); | 112 | void AddTicks(u64 ticks_to_add); |
| 111 | 113 | ||
| @@ -158,7 +160,6 @@ private: | |||
| 158 | heap_t event_queue; | 160 | heap_t event_queue; |
| 159 | u64 event_fifo_id = 0; | 161 | u64 event_fifo_id = 0; |
| 160 | 162 | ||
| 161 | std::shared_ptr<EventType> ev_lost; | ||
| 162 | Common::Event event{}; | 163 | Common::Event event{}; |
| 163 | Common::Event pause_event{}; | 164 | Common::Event pause_event{}; |
| 164 | mutable std::mutex basic_lock; | 165 | mutable std::mutex basic_lock; |
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp index 7be1322cc..31033634c 100644 --- a/src/core/file_sys/ips_layer.cpp +++ b/src/core/file_sys/ips_layer.cpp | |||
| @@ -73,6 +73,9 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) { | |||
| 73 | return nullptr; | 73 | return nullptr; |
| 74 | 74 | ||
| 75 | auto in_data = in->ReadAllBytes(); | 75 | auto in_data = in->ReadAllBytes(); |
| 76 | if (in_data.size() == 0) { | ||
| 77 | return nullptr; | ||
| 78 | } | ||
| 76 | 79 | ||
| 77 | std::vector<u8> temp(type == IPSFileType::IPS ? 3 : 4); | 80 | std::vector<u8> temp(type == IPSFileType::IPS ? 3 : 4); |
| 78 | u64 offset = 5; // After header | 81 | u64 offset = 5; // After header |
| @@ -88,6 +91,10 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) { | |||
| 88 | else | 91 | else |
| 89 | real_offset = (temp[0] << 16) | (temp[1] << 8) | temp[2]; | 92 | real_offset = (temp[0] << 16) | (temp[1] << 8) | temp[2]; |
| 90 | 93 | ||
| 94 | if (real_offset > in_data.size()) { | ||
| 95 | return nullptr; | ||
| 96 | } | ||
| 97 | |||
| 91 | u16 data_size{}; | 98 | u16 data_size{}; |
| 92 | if (ips->ReadObject(&data_size, offset) != sizeof(u16)) | 99 | if (ips->ReadObject(&data_size, offset) != sizeof(u16)) |
| 93 | return nullptr; | 100 | return nullptr; |
diff --git a/src/core/hle/kernel/k_hardware_timer.cpp b/src/core/hle/kernel/k_hardware_timer.cpp index 8e2e40307..4e947dd6b 100644 --- a/src/core/hle/kernel/k_hardware_timer.cpp +++ b/src/core/hle/kernel/k_hardware_timer.cpp | |||
| @@ -10,15 +10,15 @@ namespace Kernel { | |||
| 10 | 10 | ||
| 11 | void KHardwareTimer::Initialize() { | 11 | void KHardwareTimer::Initialize() { |
| 12 | // Create the timing callback to register with CoreTiming. | 12 | // Create the timing callback to register with CoreTiming. |
| 13 | m_event_type = Core::Timing::CreateEvent( | 13 | m_event_type = Core::Timing::CreateEvent("KHardwareTimer::Callback", |
| 14 | "KHardwareTimer::Callback", [](std::uintptr_t timer_handle, s64, std::chrono::nanoseconds) { | 14 | [this](s64, std::chrono::nanoseconds) { |
| 15 | reinterpret_cast<KHardwareTimer*>(timer_handle)->DoTask(); | 15 | this->DoTask(); |
| 16 | return std::nullopt; | 16 | return std::nullopt; |
| 17 | }); | 17 | }); |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | void KHardwareTimer::Finalize() { | 20 | void KHardwareTimer::Finalize() { |
| 21 | m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, reinterpret_cast<uintptr_t>(this)); | 21 | m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type); |
| 22 | m_wakeup_time = std::numeric_limits<s64>::max(); | 22 | m_wakeup_time = std::numeric_limits<s64>::max(); |
| 23 | m_event_type.reset(); | 23 | m_event_type.reset(); |
| 24 | } | 24 | } |
| @@ -57,13 +57,12 @@ void KHardwareTimer::EnableInterrupt(s64 wakeup_time) { | |||
| 57 | 57 | ||
| 58 | m_wakeup_time = wakeup_time; | 58 | m_wakeup_time = wakeup_time; |
| 59 | m_kernel.System().CoreTiming().ScheduleEvent(std::chrono::nanoseconds{m_wakeup_time}, | 59 | m_kernel.System().CoreTiming().ScheduleEvent(std::chrono::nanoseconds{m_wakeup_time}, |
| 60 | m_event_type, reinterpret_cast<uintptr_t>(this), | 60 | m_event_type, true); |
| 61 | true); | ||
| 62 | } | 61 | } |
| 63 | 62 | ||
| 64 | void KHardwareTimer::DisableInterrupt() { | 63 | void KHardwareTimer::DisableInterrupt() { |
| 65 | m_kernel.System().CoreTiming().UnscheduleEventWithoutWait(m_event_type, | 64 | m_kernel.System().CoreTiming().UnscheduleEvent(m_event_type, |
| 66 | reinterpret_cast<uintptr_t>(this)); | 65 | Core::Timing::UnscheduleEventType::NoWait); |
| 67 | m_wakeup_time = std::numeric_limits<s64>::max(); | 66 | m_wakeup_time = std::numeric_limits<s64>::max(); |
| 68 | } | 67 | } |
| 69 | 68 | ||
diff --git a/src/core/hle/kernel/k_page_table_base.cpp b/src/core/hle/kernel/k_page_table_base.cpp index 423289145..8c1549559 100644 --- a/src/core/hle/kernel/k_page_table_base.cpp +++ b/src/core/hle/kernel/k_page_table_base.cpp | |||
| @@ -434,7 +434,7 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool | |||
| 434 | void KPageTableBase::Finalize() { | 434 | void KPageTableBase::Finalize() { |
| 435 | auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) { | 435 | auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) { |
| 436 | if (Settings::IsFastmemEnabled()) { | 436 | if (Settings::IsFastmemEnabled()) { |
| 437 | m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size); | 437 | m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false); |
| 438 | } | 438 | } |
| 439 | }; | 439 | }; |
| 440 | 440 | ||
| @@ -5243,7 +5243,7 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) { | |||
| 5243 | // Unmap. | 5243 | // Unmap. |
| 5244 | R_ASSERT(this->Operate(updater.GetPageList(), cur_address, | 5244 | R_ASSERT(this->Operate(updater.GetPageList(), cur_address, |
| 5245 | cur_pages, 0, false, unmap_properties, | 5245 | cur_pages, 0, false, unmap_properties, |
| 5246 | OperationType::Unmap, true)); | 5246 | OperationType::UnmapPhysical, true)); |
| 5247 | } | 5247 | } |
| 5248 | 5248 | ||
| 5249 | // Check if we're done. | 5249 | // Check if we're done. |
| @@ -5326,7 +5326,7 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) { | |||
| 5326 | // Map the papges. | 5326 | // Map the papges. |
| 5327 | R_TRY(this->Operate(updater.GetPageList(), cur_address, map_pages, | 5327 | R_TRY(this->Operate(updater.GetPageList(), cur_address, map_pages, |
| 5328 | cur_pg, map_properties, | 5328 | cur_pg, map_properties, |
| 5329 | OperationType::MapFirstGroup, false)); | 5329 | OperationType::MapFirstGroupPhysical, false)); |
| 5330 | } | 5330 | } |
| 5331 | } | 5331 | } |
| 5332 | 5332 | ||
| @@ -5480,7 +5480,7 @@ Result KPageTableBase::UnmapPhysicalMemory(KProcessAddress address, size_t size) | |||
| 5480 | 5480 | ||
| 5481 | // Unmap. | 5481 | // Unmap. |
| 5482 | R_ASSERT(this->Operate(updater.GetPageList(), cur_address, cur_pages, 0, false, | 5482 | R_ASSERT(this->Operate(updater.GetPageList(), cur_address, cur_pages, 0, false, |
| 5483 | unmap_properties, OperationType::Unmap, false)); | 5483 | unmap_properties, OperationType::UnmapPhysical, false)); |
| 5484 | } | 5484 | } |
| 5485 | 5485 | ||
| 5486 | // Check if we're done. | 5486 | // Check if we're done. |
| @@ -5655,7 +5655,10 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a | |||
| 5655 | // or free them to the page list, and so it goes unused (along with page properties). | 5655 | // or free them to the page list, and so it goes unused (along with page properties). |
| 5656 | 5656 | ||
| 5657 | switch (operation) { | 5657 | switch (operation) { |
| 5658 | case OperationType::Unmap: { | 5658 | case OperationType::Unmap: |
| 5659 | case OperationType::UnmapPhysical: { | ||
| 5660 | const bool separate_heap = operation == OperationType::UnmapPhysical; | ||
| 5661 | |||
| 5659 | // Ensure that any pages we track are closed on exit. | 5662 | // Ensure that any pages we track are closed on exit. |
| 5660 | KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager()); | 5663 | KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager()); |
| 5661 | SCOPE_EXIT({ pages_to_close.CloseAndReset(); }); | 5664 | SCOPE_EXIT({ pages_to_close.CloseAndReset(); }); |
| @@ -5664,7 +5667,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a | |||
| 5664 | this->MakePageGroup(pages_to_close, virt_addr, num_pages); | 5667 | this->MakePageGroup(pages_to_close, virt_addr, num_pages); |
| 5665 | 5668 | ||
| 5666 | // Unmap. | 5669 | // Unmap. |
| 5667 | m_memory->UnmapRegion(*m_impl, virt_addr, num_pages * PageSize); | 5670 | m_memory->UnmapRegion(*m_impl, virt_addr, num_pages * PageSize, separate_heap); |
| 5668 | 5671 | ||
| 5669 | R_SUCCEED(); | 5672 | R_SUCCEED(); |
| 5670 | } | 5673 | } |
| @@ -5672,7 +5675,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a | |||
| 5672 | ASSERT(virt_addr != 0); | 5675 | ASSERT(virt_addr != 0); |
| 5673 | ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize)); | 5676 | ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize)); |
| 5674 | m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr, | 5677 | m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr, |
| 5675 | ConvertToMemoryPermission(properties.perm)); | 5678 | ConvertToMemoryPermission(properties.perm), false); |
| 5676 | 5679 | ||
| 5677 | // Open references to pages, if we should. | 5680 | // Open references to pages, if we should. |
| 5678 | if (this->IsHeapPhysicalAddress(phys_addr)) { | 5681 | if (this->IsHeapPhysicalAddress(phys_addr)) { |
| @@ -5711,16 +5714,19 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a | |||
| 5711 | 5714 | ||
| 5712 | switch (operation) { | 5715 | switch (operation) { |
| 5713 | case OperationType::MapGroup: | 5716 | case OperationType::MapGroup: |
| 5714 | case OperationType::MapFirstGroup: { | 5717 | case OperationType::MapFirstGroup: |
| 5718 | case OperationType::MapFirstGroupPhysical: { | ||
| 5719 | const bool separate_heap = operation == OperationType::MapFirstGroupPhysical; | ||
| 5720 | |||
| 5715 | // We want to maintain a new reference to every page in the group. | 5721 | // We want to maintain a new reference to every page in the group. |
| 5716 | KScopedPageGroup spg(page_group, operation != OperationType::MapFirstGroup); | 5722 | KScopedPageGroup spg(page_group, operation == OperationType::MapGroup); |
| 5717 | 5723 | ||
| 5718 | for (const auto& node : page_group) { | 5724 | for (const auto& node : page_group) { |
| 5719 | const size_t size{node.GetNumPages() * PageSize}; | 5725 | const size_t size{node.GetNumPages() * PageSize}; |
| 5720 | 5726 | ||
| 5721 | // Map the pages. | 5727 | // Map the pages. |
| 5722 | m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress(), | 5728 | m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress(), |
| 5723 | ConvertToMemoryPermission(properties.perm)); | 5729 | ConvertToMemoryPermission(properties.perm), separate_heap); |
| 5724 | 5730 | ||
| 5725 | virt_addr += size; | 5731 | virt_addr += size; |
| 5726 | } | 5732 | } |
diff --git a/src/core/hle/kernel/k_page_table_base.h b/src/core/hle/kernel/k_page_table_base.h index 556d230b3..077cafc96 100644 --- a/src/core/hle/kernel/k_page_table_base.h +++ b/src/core/hle/kernel/k_page_table_base.h | |||
| @@ -104,6 +104,9 @@ protected: | |||
| 104 | ChangePermissionsAndRefresh = 5, | 104 | ChangePermissionsAndRefresh = 5, |
| 105 | ChangePermissionsAndRefreshAndFlush = 6, | 105 | ChangePermissionsAndRefreshAndFlush = 6, |
| 106 | Separate = 7, | 106 | Separate = 7, |
| 107 | |||
| 108 | MapFirstGroupPhysical = 65000, | ||
| 109 | UnmapPhysical = 65001, | ||
| 107 | }; | 110 | }; |
| 108 | 111 | ||
| 109 | static constexpr size_t MaxPhysicalMapAlignment = 1_GiB; | 112 | static constexpr size_t MaxPhysicalMapAlignment = 1_GiB; |
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index d6869c228..068e71dff 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -1237,8 +1237,10 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) { | |||
| 1237 | auto& buffer = m_kernel.System().DeviceMemory().buffer; | 1237 | auto& buffer = m_kernel.System().DeviceMemory().buffer; |
| 1238 | const auto& code = code_set.CodeSegment(); | 1238 | const auto& code = code_set.CodeSegment(); |
| 1239 | const auto& patch = code_set.PatchSegment(); | 1239 | const auto& patch = code_set.PatchSegment(); |
| 1240 | buffer.Protect(GetInteger(base_addr + code.addr), code.size, true, true, true); | 1240 | buffer.Protect(GetInteger(base_addr + code.addr), code.size, |
| 1241 | buffer.Protect(GetInteger(base_addr + patch.addr), patch.size, true, true, true); | 1241 | Common::MemoryPermission::Read | Common::MemoryPermission::Execute); |
| 1242 | buffer.Protect(GetInteger(base_addr + patch.addr), patch.size, | ||
| 1243 | Common::MemoryPermission::Read | Common::MemoryPermission::Execute); | ||
| 1242 | ReprotectSegment(code_set.PatchSegment(), Svc::MemoryPermission::None); | 1244 | ReprotectSegment(code_set.PatchSegment(), Svc::MemoryPermission::None); |
| 1243 | } | 1245 | } |
| 1244 | #endif | 1246 | #endif |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index c14d2d2f3..1030f0c12 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -238,7 +238,7 @@ struct KernelCore::Impl { | |||
| 238 | void InitializePreemption(KernelCore& kernel) { | 238 | void InitializePreemption(KernelCore& kernel) { |
| 239 | preemption_event = Core::Timing::CreateEvent( | 239 | preemption_event = Core::Timing::CreateEvent( |
| 240 | "PreemptionCallback", | 240 | "PreemptionCallback", |
| 241 | [this, &kernel](std::uintptr_t, s64 time, | 241 | [this, &kernel](s64 time, |
| 242 | std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> { | 242 | std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> { |
| 243 | { | 243 | { |
| 244 | KScopedSchedulerLock lock(kernel); | 244 | KScopedSchedulerLock lock(kernel); |
diff --git a/src/core/hle/service/hid/controllers/applet_resource.cpp b/src/core/hle/service/hid/controllers/applet_resource.cpp index c8e74c764..b4ff663c2 100644 --- a/src/core/hle/service/hid/controllers/applet_resource.cpp +++ b/src/core/hle/service/hid/controllers/applet_resource.cpp | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | #include "core/core.h" | 4 | #include "core/core.h" |
| 5 | #include "core/hle/kernel/k_shared_memory.h" | 5 | #include "core/hle/kernel/k_shared_memory.h" |
| 6 | #include "core/hle/service/hid/controllers/applet_resource.h" | 6 | #include "core/hle/service/hid/controllers/applet_resource.h" |
| 7 | #include "core/hle/service/hid/controllers/shared_memory_format.h" | 7 | #include "core/hle/service/hid/controllers/types/shared_memory_format.h" |
| 8 | #include "core/hle/service/hid/errors.h" | 8 | #include "core/hle/service/hid/errors.h" |
| 9 | 9 | ||
| 10 | namespace Service::HID { | 10 | namespace Service::HID { |
| @@ -164,6 +164,22 @@ Result AppletResource::GetSharedMemoryFormat(SharedMemoryFormat** out_shared_mem | |||
| 164 | return ResultSuccess; | 164 | return ResultSuccess; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | AruidData* AppletResource::GetAruidData(u64 aruid) { | ||
| 168 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 169 | if (aruid_index == AruidIndexMax) { | ||
| 170 | return nullptr; | ||
| 171 | } | ||
| 172 | return &data[aruid_index]; | ||
| 173 | } | ||
| 174 | |||
| 175 | AruidData* AppletResource::GetAruidDataByIndex(std::size_t aruid_index) { | ||
| 176 | return &data[aruid_index]; | ||
| 177 | } | ||
| 178 | |||
| 179 | bool AppletResource::IsVibrationAruidActive(u64 aruid) const { | ||
| 180 | return aruid == 0 || aruid == active_vibration_aruid; | ||
| 181 | } | ||
| 182 | |||
| 167 | u64 AppletResource::GetIndexFromAruid(u64 aruid) { | 183 | u64 AppletResource::GetIndexFromAruid(u64 aruid) { |
| 168 | for (std::size_t i = 0; i < AruidIndexMax; i++) { | 184 | for (std::size_t i = 0; i < AruidIndexMax; i++) { |
| 169 | if (registration_list.flag[i] == RegistrationStatus::Initialized && | 185 | if (registration_list.flag[i] == RegistrationStatus::Initialized && |
diff --git a/src/core/hle/service/hid/controllers/applet_resource.h b/src/core/hle/service/hid/controllers/applet_resource.h index e7991f93a..52cc4cf42 100644 --- a/src/core/hle/service/hid/controllers/applet_resource.h +++ b/src/core/hle/service/hid/controllers/applet_resource.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <array> | 6 | #include <array> |
| 7 | #include <mutex> | ||
| 7 | 8 | ||
| 8 | #include "common/bit_field.h" | 9 | #include "common/bit_field.h" |
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| @@ -20,6 +21,59 @@ class KSharedMemory; | |||
| 20 | 21 | ||
| 21 | namespace Service::HID { | 22 | namespace Service::HID { |
| 22 | struct SharedMemoryFormat; | 23 | struct SharedMemoryFormat; |
| 24 | class AppletResource; | ||
| 25 | class NPadResource; | ||
| 26 | |||
| 27 | static constexpr std::size_t AruidIndexMax = 0x20; | ||
| 28 | |||
| 29 | enum class RegistrationStatus : u32 { | ||
| 30 | None, | ||
| 31 | Initialized, | ||
| 32 | PendingDelete, | ||
| 33 | }; | ||
| 34 | |||
| 35 | struct DataStatusFlag { | ||
| 36 | union { | ||
| 37 | u32 raw{}; | ||
| 38 | |||
| 39 | BitField<0, 1, u32> is_initialized; | ||
| 40 | BitField<1, 1, u32> is_assigned; | ||
| 41 | BitField<16, 1, u32> enable_pad_input; | ||
| 42 | BitField<17, 1, u32> enable_six_axis_sensor; | ||
| 43 | BitField<18, 1, u32> bit_18; | ||
| 44 | BitField<19, 1, u32> is_palma_connectable; | ||
| 45 | BitField<20, 1, u32> enable_palma_boost_mode; | ||
| 46 | BitField<21, 1, u32> enable_touchscreen; | ||
| 47 | }; | ||
| 48 | }; | ||
| 49 | |||
| 50 | struct AruidRegisterList { | ||
| 51 | std::array<RegistrationStatus, AruidIndexMax> flag{}; | ||
| 52 | std::array<u64, AruidIndexMax> aruid{}; | ||
| 53 | }; | ||
| 54 | static_assert(sizeof(AruidRegisterList) == 0x180, "AruidRegisterList is an invalid size"); | ||
| 55 | |||
| 56 | struct AruidData { | ||
| 57 | DataStatusFlag flag{}; | ||
| 58 | u64 aruid{}; | ||
| 59 | SharedMemoryFormat* shared_memory_format{nullptr}; | ||
| 60 | }; | ||
| 61 | |||
| 62 | struct HandheldConfig { | ||
| 63 | bool is_handheld_hid_enabled; | ||
| 64 | bool is_force_handheld; | ||
| 65 | bool is_joycon_rail_enabled; | ||
| 66 | bool is_force_handheld_style_vibration; | ||
| 67 | }; | ||
| 68 | static_assert(sizeof(HandheldConfig) == 0x4, "HandheldConfig is an invalid size"); | ||
| 69 | |||
| 70 | struct AppletResourceHolder { | ||
| 71 | std::shared_ptr<AppletResource> applet_resource{nullptr}; | ||
| 72 | std::recursive_mutex* shared_mutex{nullptr}; | ||
| 73 | NPadResource* shared_npad_resource{nullptr}; | ||
| 74 | std::shared_ptr<HandheldConfig> handheld_config{nullptr}; | ||
| 75 | long* handle_1; | ||
| 76 | }; | ||
| 23 | 77 | ||
| 24 | class AppletResource { | 78 | class AppletResource { |
| 25 | public: | 79 | public: |
| @@ -36,6 +90,10 @@ public: | |||
| 36 | u64 GetActiveAruid(); | 90 | u64 GetActiveAruid(); |
| 37 | Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid); | 91 | Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid); |
| 38 | Result GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, u64 aruid); | 92 | Result GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, u64 aruid); |
| 93 | AruidData* GetAruidData(u64 aruid); | ||
| 94 | AruidData* GetAruidDataByIndex(std::size_t aruid_index); | ||
| 95 | |||
| 96 | bool IsVibrationAruidActive(u64 aruid) const; | ||
| 39 | 97 | ||
| 40 | u64 GetIndexFromAruid(u64 aruid); | 98 | u64 GetIndexFromAruid(u64 aruid); |
| 41 | 99 | ||
| @@ -52,46 +110,12 @@ public: | |||
| 52 | Result UnregisterCoreAppletResource(); | 110 | Result UnregisterCoreAppletResource(); |
| 53 | 111 | ||
| 54 | private: | 112 | private: |
| 55 | static constexpr std::size_t AruidIndexMax = 0x20; | ||
| 56 | |||
| 57 | enum RegistrationStatus : u32 { | ||
| 58 | None, | ||
| 59 | Initialized, | ||
| 60 | PendingDelete, | ||
| 61 | }; | ||
| 62 | |||
| 63 | struct DataStatusFlag { | ||
| 64 | union { | ||
| 65 | u32 raw{}; | ||
| 66 | |||
| 67 | BitField<0, 1, u32> is_initialized; | ||
| 68 | BitField<1, 1, u32> is_assigned; | ||
| 69 | BitField<16, 1, u32> enable_pad_input; | ||
| 70 | BitField<17, 1, u32> enable_six_axis_sensor; | ||
| 71 | BitField<18, 1, u32> bit_18; | ||
| 72 | BitField<19, 1, u32> is_palma_connectable; | ||
| 73 | BitField<20, 1, u32> enable_palma_boost_mode; | ||
| 74 | BitField<21, 1, u32> enable_touchscreen; | ||
| 75 | }; | ||
| 76 | }; | ||
| 77 | |||
| 78 | struct AruidRegisterList { | ||
| 79 | std::array<RegistrationStatus, AruidIndexMax> flag{}; | ||
| 80 | std::array<u64, AruidIndexMax> aruid{}; | ||
| 81 | }; | ||
| 82 | static_assert(sizeof(AruidRegisterList) == 0x180, "AruidRegisterList is an invalid size"); | ||
| 83 | |||
| 84 | struct AruidData { | ||
| 85 | DataStatusFlag flag{}; | ||
| 86 | u64 aruid{}; | ||
| 87 | SharedMemoryFormat* shared_memory_format{nullptr}; | ||
| 88 | }; | ||
| 89 | |||
| 90 | u64 active_aruid{}; | 113 | u64 active_aruid{}; |
| 91 | AruidRegisterList registration_list{}; | 114 | AruidRegisterList registration_list{}; |
| 92 | std::array<AruidData, AruidIndexMax> data{}; | 115 | std::array<AruidData, AruidIndexMax> data{}; |
| 93 | std::array<SharedMemoryHolder, AruidIndexMax> shared_memory_holder{}; | 116 | std::array<SharedMemoryHolder, AruidIndexMax> shared_memory_holder{}; |
| 94 | s32 ref_counter{}; | 117 | s32 ref_counter{}; |
| 118 | u64 active_vibration_aruid; | ||
| 95 | 119 | ||
| 96 | Core::System& system; | 120 | Core::System& system; |
| 97 | }; | 121 | }; |
diff --git a/src/core/hle/service/hid/controllers/capture_button.cpp b/src/core/hle/service/hid/controllers/capture_button.cpp new file mode 100644 index 000000000..8b486fcb5 --- /dev/null +++ b/src/core/hle/service/hid/controllers/capture_button.cpp | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core_timing.h" | ||
| 5 | #include "core/hle/service/hid/controllers/applet_resource.h" | ||
| 6 | #include "core/hle/service/hid/controllers/capture_button.h" | ||
| 7 | #include "core/hle/service/hid/controllers/types/shared_memory_format.h" | ||
| 8 | |||
| 9 | namespace Service::HID { | ||
| 10 | |||
| 11 | CaptureButton::CaptureButton(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} | ||
| 12 | |||
| 13 | CaptureButton::~CaptureButton() = default; | ||
| 14 | |||
| 15 | void CaptureButton::OnInit() {} | ||
| 16 | |||
| 17 | void CaptureButton::OnRelease() {} | ||
| 18 | |||
| 19 | void CaptureButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | ||
| 20 | if (!smart_update) { | ||
| 21 | return; | ||
| 22 | } | ||
| 23 | |||
| 24 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 25 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 26 | |||
| 27 | if (data == nullptr) { | ||
| 28 | return; | ||
| 29 | } | ||
| 30 | |||
| 31 | auto& header = data->shared_memory_format->capture_button.header; | ||
| 32 | header.timestamp = core_timing.GetGlobalTimeNs().count(); | ||
| 33 | header.total_entry_count = 17; | ||
| 34 | header.entry_count = 0; | ||
| 35 | header.last_entry_index = 0; | ||
| 36 | } | ||
| 37 | |||
| 38 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/capture_button.h index d2052fb17..dcc4715c5 100644 --- a/src/core/hle/service/hid/controllers/stubbed.h +++ b/src/core/hle/service/hid/controllers/capture_button.h | |||
| @@ -6,12 +6,11 @@ | |||
| 6 | #include "core/hle/service/hid/controllers/controller_base.h" | 6 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 7 | 7 | ||
| 8 | namespace Service::HID { | 8 | namespace Service::HID { |
| 9 | struct CommonHeader; | ||
| 10 | 9 | ||
| 11 | class Controller_Stubbed final : public ControllerBase { | 10 | class CaptureButton final : public ControllerBase { |
| 12 | public: | 11 | public: |
| 13 | explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, CommonHeader& ring_lifo_header); | 12 | explicit CaptureButton(Core::HID::HIDCore& hid_core_); |
| 14 | ~Controller_Stubbed() override; | 13 | ~CaptureButton() override; |
| 15 | 14 | ||
| 16 | // Called when the controller is initialized | 15 | // Called when the controller is initialized |
| 17 | void OnInit() override; | 16 | void OnInit() override; |
| @@ -23,7 +22,6 @@ public: | |||
| 23 | void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; | 22 | void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; |
| 24 | 23 | ||
| 25 | private: | 24 | private: |
| 26 | CommonHeader& header; | ||
| 27 | bool smart_update{}; | 25 | bool smart_update{}; |
| 28 | }; | 26 | }; |
| 29 | } // namespace Service::HID | 27 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/console_six_axis.cpp b/src/core/hle/service/hid/controllers/console_six_axis.cpp index 3961d2b5f..8eba2c292 100644 --- a/src/core/hle/service/hid/controllers/console_six_axis.cpp +++ b/src/core/hle/service/hid/controllers/console_six_axis.cpp | |||
| @@ -5,13 +5,11 @@ | |||
| 5 | #include "core/hid/emulated_console.h" | 5 | #include "core/hid/emulated_console.h" |
| 6 | #include "core/hid/hid_core.h" | 6 | #include "core/hid/hid_core.h" |
| 7 | #include "core/hle/service/hid/controllers/console_six_axis.h" | 7 | #include "core/hle/service/hid/controllers/console_six_axis.h" |
| 8 | #include "core/hle/service/hid/controllers/shared_memory_format.h" | 8 | #include "core/hle/service/hid/controllers/types/shared_memory_format.h" |
| 9 | 9 | ||
| 10 | namespace Service::HID { | 10 | namespace Service::HID { |
| 11 | 11 | ||
| 12 | ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_, | 12 | ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} { |
| 13 | ConsoleSixAxisSensorSharedMemoryFormat& console_shared_memory) | ||
| 14 | : ControllerBase{hid_core_}, shared_memory{console_shared_memory} { | ||
| 15 | console = hid_core.GetEmulatedConsole(); | 13 | console = hid_core.GetEmulatedConsole(); |
| 16 | } | 14 | } |
| 17 | 15 | ||
| @@ -22,6 +20,15 @@ void ConsoleSixAxis::OnInit() {} | |||
| 22 | void ConsoleSixAxis::OnRelease() {} | 20 | void ConsoleSixAxis::OnRelease() {} |
| 23 | 21 | ||
| 24 | void ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | 22 | void ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { |
| 23 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 24 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 25 | |||
| 26 | if (data == nullptr) { | ||
| 27 | return; | ||
| 28 | } | ||
| 29 | |||
| 30 | ConsoleSixAxisSensorSharedMemoryFormat& shared_memory = data->shared_memory_format->console; | ||
| 31 | |||
| 25 | if (!IsControllerActivated()) { | 32 | if (!IsControllerActivated()) { |
| 26 | return; | 33 | return; |
| 27 | } | 34 | } |
diff --git a/src/core/hle/service/hid/controllers/console_six_axis.h b/src/core/hle/service/hid/controllers/console_six_axis.h index 3d1c9ce23..e3351f83c 100644 --- a/src/core/hle/service/hid/controllers/console_six_axis.h +++ b/src/core/hle/service/hid/controllers/console_six_axis.h | |||
| @@ -10,12 +10,9 @@ class EmulatedConsole; | |||
| 10 | } // namespace Core::HID | 10 | } // namespace Core::HID |
| 11 | 11 | ||
| 12 | namespace Service::HID { | 12 | namespace Service::HID { |
| 13 | struct ConsoleSixAxisSensorSharedMemoryFormat; | ||
| 14 | |||
| 15 | class ConsoleSixAxis final : public ControllerBase { | 13 | class ConsoleSixAxis final : public ControllerBase { |
| 16 | public: | 14 | public: |
| 17 | explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_, | 15 | explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_); |
| 18 | ConsoleSixAxisSensorSharedMemoryFormat& console_shared_memory); | ||
| 19 | ~ConsoleSixAxis() override; | 16 | ~ConsoleSixAxis() override; |
| 20 | 17 | ||
| 21 | // Called when the controller is initialized | 18 | // Called when the controller is initialized |
| @@ -28,7 +25,6 @@ public: | |||
| 28 | void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; | 25 | void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; |
| 29 | 26 | ||
| 30 | private: | 27 | private: |
| 31 | ConsoleSixAxisSensorSharedMemoryFormat& shared_memory; | ||
| 32 | Core::HID::EmulatedConsole* console = nullptr; | 28 | Core::HID::EmulatedConsole* console = nullptr; |
| 33 | }; | 29 | }; |
| 34 | } // namespace Service::HID | 30 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/controller_base.cpp b/src/core/hle/service/hid/controllers/controller_base.cpp index 0bcd87062..2083ccfad 100644 --- a/src/core/hle/service/hid/controllers/controller_base.cpp +++ b/src/core/hle/service/hid/controllers/controller_base.cpp | |||
| @@ -31,4 +31,9 @@ void ControllerBase::DeactivateController() { | |||
| 31 | bool ControllerBase::IsControllerActivated() const { | 31 | bool ControllerBase::IsControllerActivated() const { |
| 32 | return is_activated; | 32 | return is_activated; |
| 33 | } | 33 | } |
| 34 | |||
| 35 | void ControllerBase::SetAppletResource(std::shared_ptr<AppletResource> resource) { | ||
| 36 | applet_resource = resource; | ||
| 37 | } | ||
| 38 | |||
| 34 | } // namespace Service::HID | 39 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h index 4326c7821..759ae0053 100644 --- a/src/core/hle/service/hid/controllers/controller_base.h +++ b/src/core/hle/service/hid/controllers/controller_base.h | |||
| @@ -3,8 +3,11 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <memory> | ||
| 7 | |||
| 6 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 7 | #include "core/hle/result.h" | 9 | #include "core/hle/result.h" |
| 10 | #include "core/hle/service/hid/controllers/applet_resource.h" | ||
| 8 | 11 | ||
| 9 | namespace Core::Timing { | 12 | namespace Core::Timing { |
| 10 | class CoreTiming; | 13 | class CoreTiming; |
| @@ -12,7 +15,7 @@ class CoreTiming; | |||
| 12 | 15 | ||
| 13 | namespace Core::HID { | 16 | namespace Core::HID { |
| 14 | class HIDCore; | 17 | class HIDCore; |
| 15 | } | 18 | } // namespace Core::HID |
| 16 | 19 | ||
| 17 | namespace Service::HID { | 20 | namespace Service::HID { |
| 18 | class ControllerBase { | 21 | class ControllerBase { |
| @@ -39,8 +42,11 @@ public: | |||
| 39 | 42 | ||
| 40 | bool IsControllerActivated() const; | 43 | bool IsControllerActivated() const; |
| 41 | 44 | ||
| 45 | void SetAppletResource(std::shared_ptr<AppletResource> resource); | ||
| 46 | |||
| 42 | protected: | 47 | protected: |
| 43 | bool is_activated{false}; | 48 | bool is_activated{false}; |
| 49 | std::shared_ptr<AppletResource> applet_resource{nullptr}; | ||
| 44 | 50 | ||
| 45 | Core::HID::HIDCore& hid_core; | 51 | Core::HID::HIDCore& hid_core; |
| 46 | }; | 52 | }; |
diff --git a/src/core/hle/service/hid/controllers/debug_mouse.cpp b/src/core/hle/service/hid/controllers/debug_mouse.cpp new file mode 100644 index 000000000..f2f1a27f8 --- /dev/null +++ b/src/core/hle/service/hid/controllers/debug_mouse.cpp | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core_timing.h" | ||
| 5 | #include "core/frontend/emu_window.h" | ||
| 6 | #include "core/hid/emulated_devices.h" | ||
| 7 | #include "core/hid/hid_core.h" | ||
| 8 | #include "core/hle/service/hid/controllers/applet_resource.h" | ||
| 9 | #include "core/hle/service/hid/controllers/debug_mouse.h" | ||
| 10 | #include "core/hle/service/hid/controllers/types/shared_memory_format.h" | ||
| 11 | |||
| 12 | namespace Service::HID { | ||
| 13 | |||
| 14 | DebugMouse::DebugMouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} { | ||
| 15 | emulated_devices = hid_core.GetEmulatedDevices(); | ||
| 16 | } | ||
| 17 | |||
| 18 | DebugMouse::~DebugMouse() = default; | ||
| 19 | |||
| 20 | void DebugMouse::OnInit() {} | ||
| 21 | void DebugMouse::OnRelease() {} | ||
| 22 | |||
| 23 | void DebugMouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | ||
| 24 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 25 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 26 | |||
| 27 | if (data == nullptr) { | ||
| 28 | return; | ||
| 29 | } | ||
| 30 | |||
| 31 | MouseSharedMemoryFormat& shared_memory = data->shared_memory_format->debug_mouse; | ||
| 32 | |||
| 33 | if (!IsControllerActivated()) { | ||
| 34 | shared_memory.mouse_lifo.buffer_count = 0; | ||
| 35 | shared_memory.mouse_lifo.buffer_tail = 0; | ||
| 36 | return; | ||
| 37 | } | ||
| 38 | |||
| 39 | next_state = {}; | ||
| 40 | |||
| 41 | const auto& last_entry = shared_memory.mouse_lifo.ReadCurrentEntry().state; | ||
| 42 | next_state.sampling_number = last_entry.sampling_number + 1; | ||
| 43 | |||
| 44 | if (Settings::values.mouse_enabled) { | ||
| 45 | const auto& mouse_button_state = emulated_devices->GetMouseButtons(); | ||
| 46 | const auto& mouse_position_state = emulated_devices->GetMousePosition(); | ||
| 47 | const auto& mouse_wheel_state = emulated_devices->GetMouseWheel(); | ||
| 48 | next_state.attribute.is_connected.Assign(1); | ||
| 49 | next_state.x = static_cast<s32>(mouse_position_state.x * Layout::ScreenUndocked::Width); | ||
| 50 | next_state.y = static_cast<s32>(mouse_position_state.y * Layout::ScreenUndocked::Height); | ||
| 51 | next_state.delta_x = next_state.x - last_entry.x; | ||
| 52 | next_state.delta_y = next_state.y - last_entry.y; | ||
| 53 | next_state.delta_wheel_x = mouse_wheel_state.x - last_mouse_wheel_state.x; | ||
| 54 | next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y; | ||
| 55 | |||
| 56 | last_mouse_wheel_state = mouse_wheel_state; | ||
| 57 | next_state.button = mouse_button_state; | ||
| 58 | } | ||
| 59 | |||
| 60 | shared_memory.mouse_lifo.WriteNextEntry(next_state); | ||
| 61 | } | ||
| 62 | |||
| 63 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/hid/controllers/debug_mouse.h b/src/core/hle/service/hid/controllers/debug_mouse.h new file mode 100644 index 000000000..ec939fa9f --- /dev/null +++ b/src/core/hle/service/hid/controllers/debug_mouse.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/hid/controllers/controller_base.h" | ||
| 7 | |||
| 8 | namespace Core::HID { | ||
| 9 | class EmulatedDevices; | ||
| 10 | struct MouseState; | ||
| 11 | struct AnalogStickState; | ||
| 12 | } // namespace Core::HID | ||
| 13 | |||
| 14 | namespace Service::HID { | ||
| 15 | class DebugMouse final : public ControllerBase { | ||
| 16 | public: | ||
| 17 | explicit DebugMouse(Core::HID::HIDCore& hid_core_); | ||
| 18 | ~DebugMouse() override; | ||
| 19 | |||
| 20 | // Called when the controller is initialized | ||
| 21 | void OnInit() override; | ||
| 22 | |||
| 23 | // When the controller is released | ||
| 24 | void OnRelease() override; | ||
| 25 | |||
| 26 | // When the controller is requesting an update for the shared memory | ||
| 27 | void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; | ||
| 28 | |||
| 29 | private: | ||
| 30 | Core::HID::MouseState next_state{}; | ||
| 31 | Core::HID::AnalogStickState last_mouse_wheel_state{}; | ||
| 32 | Core::HID::EmulatedDevices* emulated_devices = nullptr; | ||
| 33 | }; | ||
| 34 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index 7d2370b4f..1811cf620 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp | |||
| @@ -6,14 +6,13 @@ | |||
| 6 | #include "core/hid/emulated_controller.h" | 6 | #include "core/hid/emulated_controller.h" |
| 7 | #include "core/hid/hid_core.h" | 7 | #include "core/hid/hid_core.h" |
| 8 | #include "core/hid/hid_types.h" | 8 | #include "core/hid/hid_types.h" |
| 9 | #include "core/hle/service/hid/controllers/applet_resource.h" | ||
| 9 | #include "core/hle/service/hid/controllers/debug_pad.h" | 10 | #include "core/hle/service/hid/controllers/debug_pad.h" |
| 10 | #include "core/hle/service/hid/controllers/shared_memory_format.h" | 11 | #include "core/hle/service/hid/controllers/types/shared_memory_format.h" |
| 11 | 12 | ||
| 12 | namespace Service::HID { | 13 | namespace Service::HID { |
| 13 | 14 | ||
| 14 | DebugPad::DebugPad(Core::HID::HIDCore& hid_core_, | 15 | DebugPad::DebugPad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} { |
| 15 | DebugPadSharedMemoryFormat& debug_pad_shared_memory) | ||
| 16 | : ControllerBase{hid_core_}, shared_memory{debug_pad_shared_memory} { | ||
| 17 | controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); | 16 | controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); |
| 18 | } | 17 | } |
| 19 | 18 | ||
| @@ -24,6 +23,15 @@ void DebugPad::OnInit() {} | |||
| 24 | void DebugPad::OnRelease() {} | 23 | void DebugPad::OnRelease() {} |
| 25 | 24 | ||
| 26 | void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | 25 | void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { |
| 26 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 27 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 28 | |||
| 29 | if (data == nullptr) { | ||
| 30 | return; | ||
| 31 | } | ||
| 32 | |||
| 33 | DebugPadSharedMemoryFormat& shared_memory = data->shared_memory_format->debug_pad; | ||
| 34 | |||
| 27 | if (!IsControllerActivated()) { | 35 | if (!IsControllerActivated()) { |
| 28 | shared_memory.debug_pad_lifo.buffer_count = 0; | 36 | shared_memory.debug_pad_lifo.buffer_count = 0; |
| 29 | shared_memory.debug_pad_lifo.buffer_tail = 0; | 37 | shared_memory.debug_pad_lifo.buffer_tail = 0; |
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h index 8ab29eca8..dd00b2402 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ b/src/core/hle/service/hid/controllers/debug_pad.h | |||
| @@ -15,12 +15,9 @@ class CoreTiming; | |||
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | namespace Service::HID { | 17 | namespace Service::HID { |
| 18 | struct DebugPadSharedMemoryFormat; | ||
| 19 | |||
| 20 | class DebugPad final : public ControllerBase { | 18 | class DebugPad final : public ControllerBase { |
| 21 | public: | 19 | public: |
| 22 | explicit DebugPad(Core::HID::HIDCore& hid_core_, | 20 | explicit DebugPad(Core::HID::HIDCore& hid_core_); |
| 23 | DebugPadSharedMemoryFormat& debug_pad_shared_memory); | ||
| 24 | ~DebugPad() override; | 21 | ~DebugPad() override; |
| 25 | 22 | ||
| 26 | // Called when the controller is initialized | 23 | // Called when the controller is initialized |
| @@ -34,7 +31,6 @@ public: | |||
| 34 | 31 | ||
| 35 | private: | 32 | private: |
| 36 | DebugPadState next_state{}; | 33 | DebugPadState next_state{}; |
| 37 | DebugPadSharedMemoryFormat& shared_memory; | ||
| 38 | Core::HID::EmulatedController* controller = nullptr; | 34 | Core::HID::EmulatedController* controller = nullptr; |
| 39 | }; | 35 | }; |
| 40 | } // namespace Service::HID | 36 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/digitizer.cpp b/src/core/hle/service/hid/controllers/digitizer.cpp new file mode 100644 index 000000000..c01580fd6 --- /dev/null +++ b/src/core/hle/service/hid/controllers/digitizer.cpp | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core_timing.h" | ||
| 5 | #include "core/hle/service/hid/controllers/applet_resource.h" | ||
| 6 | #include "core/hle/service/hid/controllers/digitizer.h" | ||
| 7 | #include "core/hle/service/hid/controllers/types/shared_memory_format.h" | ||
| 8 | |||
| 9 | namespace Service::HID { | ||
| 10 | |||
| 11 | Digitizer::Digitizer(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} | ||
| 12 | |||
| 13 | Digitizer::~Digitizer() = default; | ||
| 14 | |||
| 15 | void Digitizer::OnInit() {} | ||
| 16 | |||
| 17 | void Digitizer::OnRelease() {} | ||
| 18 | |||
| 19 | void Digitizer::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | ||
| 20 | if (!smart_update) { | ||
| 21 | return; | ||
| 22 | } | ||
| 23 | |||
| 24 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 25 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 26 | |||
| 27 | if (data == nullptr) { | ||
| 28 | return; | ||
| 29 | } | ||
| 30 | |||
| 31 | auto& header = data->shared_memory_format->digitizer.header; | ||
| 32 | header.timestamp = core_timing.GetGlobalTimeNs().count(); | ||
| 33 | header.total_entry_count = 17; | ||
| 34 | header.entry_count = 0; | ||
| 35 | header.last_entry_index = 0; | ||
| 36 | } | ||
| 37 | |||
| 38 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/hid/controllers/digitizer.h b/src/core/hle/service/hid/controllers/digitizer.h new file mode 100644 index 000000000..d81f814c3 --- /dev/null +++ b/src/core/hle/service/hid/controllers/digitizer.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/hid/controllers/controller_base.h" | ||
| 7 | |||
| 8 | namespace Service::HID { | ||
| 9 | |||
| 10 | class Digitizer final : public ControllerBase { | ||
| 11 | public: | ||
| 12 | explicit Digitizer(Core::HID::HIDCore& hid_core_); | ||
| 13 | ~Digitizer() override; | ||
| 14 | |||
| 15 | // Called when the controller is initialized | ||
| 16 | void OnInit() override; | ||
| 17 | |||
| 18 | // When the controller is released | ||
| 19 | void OnRelease() override; | ||
| 20 | |||
| 21 | // When the controller is requesting an update for the shared memory | ||
| 22 | void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; | ||
| 23 | |||
| 24 | private: | ||
| 25 | bool smart_update{}; | ||
| 26 | }; | ||
| 27 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index f658005f6..6e686fe65 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp | |||
| @@ -6,8 +6,9 @@ | |||
| 6 | #include "core/frontend/emu_window.h" | 6 | #include "core/frontend/emu_window.h" |
| 7 | #include "core/hid/emulated_console.h" | 7 | #include "core/hid/emulated_console.h" |
| 8 | #include "core/hid/hid_core.h" | 8 | #include "core/hid/hid_core.h" |
| 9 | #include "core/hle/service/hid/controllers/applet_resource.h" | ||
| 9 | #include "core/hle/service/hid/controllers/gesture.h" | 10 | #include "core/hle/service/hid/controllers/gesture.h" |
| 10 | #include "core/hle/service/hid/controllers/shared_memory_format.h" | 11 | #include "core/hle/service/hid/controllers/types/shared_memory_format.h" |
| 11 | 12 | ||
| 12 | namespace Service::HID { | 13 | namespace Service::HID { |
| 13 | // HW is around 700, value is set to 400 to make it easier to trigger with mouse | 14 | // HW is around 700, value is set to 400 to make it easier to trigger with mouse |
| @@ -21,24 +22,40 @@ constexpr f32 Square(s32 num) { | |||
| 21 | return static_cast<f32>(num * num); | 22 | return static_cast<f32>(num * num); |
| 22 | } | 23 | } |
| 23 | 24 | ||
| 24 | Gesture::Gesture(Core::HID::HIDCore& hid_core_, GestureSharedMemoryFormat& gesture_shared_memory) | 25 | Gesture::Gesture(Core::HID::HIDCore& hid_core_) : ControllerBase(hid_core_) { |
| 25 | : ControllerBase(hid_core_), shared_memory{gesture_shared_memory} { | ||
| 26 | console = hid_core.GetEmulatedConsole(); | 26 | console = hid_core.GetEmulatedConsole(); |
| 27 | } | 27 | } |
| 28 | Gesture::~Gesture() = default; | 28 | Gesture::~Gesture() = default; |
| 29 | 29 | ||
| 30 | void Gesture::OnInit() { | 30 | void Gesture::OnInit() { |
| 31 | shared_memory.gesture_lifo.buffer_count = 0; | 31 | const u64 aruid = applet_resource->GetActiveAruid(); |
| 32 | shared_memory.gesture_lifo.buffer_tail = 0; | 32 | auto* data = applet_resource->GetAruidData(aruid); |
| 33 | |||
| 34 | if (data == nullptr) { | ||
| 35 | return; | ||
| 36 | } | ||
| 37 | |||
| 38 | shared_memory = &data->shared_memory_format->gesture; | ||
| 39 | shared_memory->gesture_lifo.buffer_count = 0; | ||
| 40 | shared_memory->gesture_lifo.buffer_tail = 0; | ||
| 33 | force_update = true; | 41 | force_update = true; |
| 34 | } | 42 | } |
| 35 | 43 | ||
| 36 | void Gesture::OnRelease() {} | 44 | void Gesture::OnRelease() {} |
| 37 | 45 | ||
| 38 | void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | 46 | void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { |
| 47 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 48 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 49 | |||
| 50 | if (data == nullptr) { | ||
| 51 | return; | ||
| 52 | } | ||
| 53 | |||
| 54 | shared_memory = &data->shared_memory_format->gesture; | ||
| 55 | |||
| 39 | if (!IsControllerActivated()) { | 56 | if (!IsControllerActivated()) { |
| 40 | shared_memory.gesture_lifo.buffer_count = 0; | 57 | shared_memory->gesture_lifo.buffer_count = 0; |
| 41 | shared_memory.gesture_lifo.buffer_tail = 0; | 58 | shared_memory->gesture_lifo.buffer_tail = 0; |
| 42 | return; | 59 | return; |
| 43 | } | 60 | } |
| 44 | 61 | ||
| @@ -46,7 +63,7 @@ void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | |||
| 46 | 63 | ||
| 47 | GestureProperties gesture = GetGestureProperties(); | 64 | GestureProperties gesture = GetGestureProperties(); |
| 48 | f32 time_difference = | 65 | f32 time_difference = |
| 49 | static_cast<f32>(shared_memory.gesture_lifo.timestamp - last_update_timestamp) / | 66 | static_cast<f32>(shared_memory->gesture_lifo.timestamp - last_update_timestamp) / |
| 50 | (1000 * 1000 * 1000); | 67 | (1000 * 1000 * 1000); |
| 51 | 68 | ||
| 52 | // Only update if necessary | 69 | // Only update if necessary |
| @@ -54,7 +71,7 @@ void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | |||
| 54 | return; | 71 | return; |
| 55 | } | 72 | } |
| 56 | 73 | ||
| 57 | last_update_timestamp = shared_memory.gesture_lifo.timestamp; | 74 | last_update_timestamp = shared_memory->gesture_lifo.timestamp; |
| 58 | UpdateGestureSharedMemory(gesture, time_difference); | 75 | UpdateGestureSharedMemory(gesture, time_difference); |
| 59 | } | 76 | } |
| 60 | 77 | ||
| @@ -97,7 +114,7 @@ void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_dif | |||
| 97 | GestureType type = GestureType::Idle; | 114 | GestureType type = GestureType::Idle; |
| 98 | GestureAttribute attributes{}; | 115 | GestureAttribute attributes{}; |
| 99 | 116 | ||
| 100 | const auto& last_entry = shared_memory.gesture_lifo.ReadCurrentEntry().state; | 117 | const auto& last_entry = shared_memory->gesture_lifo.ReadCurrentEntry().state; |
| 101 | 118 | ||
| 102 | // Reset next state to default | 119 | // Reset next state to default |
| 103 | next_state.sampling_number = last_entry.sampling_number + 1; | 120 | next_state.sampling_number = last_entry.sampling_number + 1; |
| @@ -127,7 +144,7 @@ void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_dif | |||
| 127 | next_state.points = gesture.points; | 144 | next_state.points = gesture.points; |
| 128 | last_gesture = gesture; | 145 | last_gesture = gesture; |
| 129 | 146 | ||
| 130 | shared_memory.gesture_lifo.WriteNextEntry(next_state); | 147 | shared_memory->gesture_lifo.WriteNextEntry(next_state); |
| 131 | } | 148 | } |
| 132 | 149 | ||
| 133 | void Gesture::NewGesture(GestureProperties& gesture, GestureType& type, | 150 | void Gesture::NewGesture(GestureProperties& gesture, GestureType& type, |
| @@ -300,7 +317,7 @@ void Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_ | |||
| 300 | } | 317 | } |
| 301 | 318 | ||
| 302 | const GestureState& Gesture::GetLastGestureEntry() const { | 319 | const GestureState& Gesture::GetLastGestureEntry() const { |
| 303 | return shared_memory.gesture_lifo.ReadCurrentEntry().state; | 320 | return shared_memory->gesture_lifo.ReadCurrentEntry().state; |
| 304 | } | 321 | } |
| 305 | 322 | ||
| 306 | GestureProperties Gesture::GetGestureProperties() { | 323 | GestureProperties Gesture::GetGestureProperties() { |
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 41fdfcd03..78da1552a 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h | |||
| @@ -18,8 +18,7 @@ struct GestureSharedMemoryFormat; | |||
| 18 | 18 | ||
| 19 | class Gesture final : public ControllerBase { | 19 | class Gesture final : public ControllerBase { |
| 20 | public: | 20 | public: |
| 21 | explicit Gesture(Core::HID::HIDCore& hid_core_, | 21 | explicit Gesture(Core::HID::HIDCore& hid_core_); |
| 22 | GestureSharedMemoryFormat& gesture_shared_memory); | ||
| 23 | ~Gesture() override; | 22 | ~Gesture() override; |
| 24 | 23 | ||
| 25 | // Called when the controller is initialized | 24 | // Called when the controller is initialized |
| @@ -74,7 +73,7 @@ private: | |||
| 74 | GestureProperties GetGestureProperties(); | 73 | GestureProperties GetGestureProperties(); |
| 75 | 74 | ||
| 76 | GestureState next_state{}; | 75 | GestureState next_state{}; |
| 77 | GestureSharedMemoryFormat& shared_memory; | 76 | GestureSharedMemoryFormat* shared_memory; |
| 78 | Core::HID::EmulatedConsole* console = nullptr; | 77 | Core::HID::EmulatedConsole* console = nullptr; |
| 79 | 78 | ||
| 80 | std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{}; | 79 | std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{}; |
diff --git a/src/core/hle/service/hid/controllers/home_button.cpp b/src/core/hle/service/hid/controllers/home_button.cpp new file mode 100644 index 000000000..71dd9bc08 --- /dev/null +++ b/src/core/hle/service/hid/controllers/home_button.cpp | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core_timing.h" | ||
| 5 | #include "core/hle/service/hid/controllers/applet_resource.h" | ||
| 6 | #include "core/hle/service/hid/controllers/home_button.h" | ||
| 7 | #include "core/hle/service/hid/controllers/types/shared_memory_format.h" | ||
| 8 | |||
| 9 | namespace Service::HID { | ||
| 10 | |||
| 11 | HomeButton::HomeButton(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} | ||
| 12 | |||
| 13 | HomeButton::~HomeButton() = default; | ||
| 14 | |||
| 15 | void HomeButton::OnInit() {} | ||
| 16 | |||
| 17 | void HomeButton::OnRelease() {} | ||
| 18 | |||
| 19 | void HomeButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | ||
| 20 | if (!smart_update) { | ||
| 21 | return; | ||
| 22 | } | ||
| 23 | |||
| 24 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 25 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 26 | |||
| 27 | if (data == nullptr) { | ||
| 28 | return; | ||
| 29 | } | ||
| 30 | |||
| 31 | auto& header = data->shared_memory_format->home_button.header; | ||
| 32 | header.timestamp = core_timing.GetGlobalTimeNs().count(); | ||
| 33 | header.total_entry_count = 17; | ||
| 34 | header.entry_count = 0; | ||
| 35 | header.last_entry_index = 0; | ||
| 36 | } | ||
| 37 | |||
| 38 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/hid/controllers/home_button.h b/src/core/hle/service/hid/controllers/home_button.h new file mode 100644 index 000000000..e91c2aa5d --- /dev/null +++ b/src/core/hle/service/hid/controllers/home_button.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/hid/controllers/controller_base.h" | ||
| 7 | |||
| 8 | namespace Service::HID { | ||
| 9 | |||
| 10 | class HomeButton final : public ControllerBase { | ||
| 11 | public: | ||
| 12 | explicit HomeButton(Core::HID::HIDCore& hid_core_); | ||
| 13 | ~HomeButton() override; | ||
| 14 | |||
| 15 | // Called when the controller is initialized | ||
| 16 | void OnInit() override; | ||
| 17 | |||
| 18 | // When the controller is released | ||
| 19 | void OnRelease() override; | ||
| 20 | |||
| 21 | // When the controller is requesting an update for the shared memory | ||
| 22 | void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; | ||
| 23 | |||
| 24 | private: | ||
| 25 | bool smart_update{}; | ||
| 26 | }; | ||
| 27 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index 871e5036a..c72b3e5ce 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp | |||
| @@ -5,14 +5,13 @@ | |||
| 5 | #include "core/core_timing.h" | 5 | #include "core/core_timing.h" |
| 6 | #include "core/hid/emulated_devices.h" | 6 | #include "core/hid/emulated_devices.h" |
| 7 | #include "core/hid/hid_core.h" | 7 | #include "core/hid/hid_core.h" |
| 8 | #include "core/hle/service/hid/controllers/applet_resource.h" | ||
| 8 | #include "core/hle/service/hid/controllers/keyboard.h" | 9 | #include "core/hle/service/hid/controllers/keyboard.h" |
| 9 | #include "core/hle/service/hid/controllers/shared_memory_format.h" | 10 | #include "core/hle/service/hid/controllers/types/shared_memory_format.h" |
| 10 | 11 | ||
| 11 | namespace Service::HID { | 12 | namespace Service::HID { |
| 12 | 13 | ||
| 13 | Keyboard::Keyboard(Core::HID::HIDCore& hid_core_, | 14 | Keyboard::Keyboard(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} { |
| 14 | KeyboardSharedMemoryFormat& keyboard_shared_memory) | ||
| 15 | : ControllerBase{hid_core_}, shared_memory{keyboard_shared_memory} { | ||
| 16 | emulated_devices = hid_core.GetEmulatedDevices(); | 15 | emulated_devices = hid_core.GetEmulatedDevices(); |
| 17 | } | 16 | } |
| 18 | 17 | ||
| @@ -23,6 +22,15 @@ void Keyboard::OnInit() {} | |||
| 23 | void Keyboard::OnRelease() {} | 22 | void Keyboard::OnRelease() {} |
| 24 | 23 | ||
| 25 | void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | 24 | void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) { |
| 25 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 26 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 27 | |||
| 28 | if (data == nullptr) { | ||
| 29 | return; | ||
| 30 | } | ||
| 31 | |||
| 32 | KeyboardSharedMemoryFormat& shared_memory = data->shared_memory_format->keyboard; | ||
| 33 | |||
| 26 | if (!IsControllerActivated()) { | 34 | if (!IsControllerActivated()) { |
| 27 | shared_memory.keyboard_lifo.buffer_count = 0; | 35 | shared_memory.keyboard_lifo.buffer_count = 0; |
| 28 | shared_memory.keyboard_lifo.buffer_tail = 0; | 36 | shared_memory.keyboard_lifo.buffer_tail = 0; |
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h index 4d72171b9..e8ca326c6 100644 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h | |||
| @@ -7,12 +7,9 @@ | |||
| 7 | #include "core/hle/service/hid/controllers/types/keyboard_types.h" | 7 | #include "core/hle/service/hid/controllers/types/keyboard_types.h" |
| 8 | 8 | ||
| 9 | namespace Service::HID { | 9 | namespace Service::HID { |
| 10 | struct KeyboardSharedMemoryFormat; | ||
| 11 | |||
| 12 | class Keyboard final : public ControllerBase { | 10 | class Keyboard final : public ControllerBase { |
| 13 | public: | 11 | public: |
| 14 | explicit Keyboard(Core::HID::HIDCore& hid_core_, | 12 | explicit Keyboard(Core::HID::HIDCore& hid_core_); |
| 15 | KeyboardSharedMemoryFormat& keyboard_shared_memory); | ||
| 16 | ~Keyboard() override; | 13 | ~Keyboard() override; |
| 17 | 14 | ||
| 18 | // Called when the controller is initialized | 15 | // Called when the controller is initialized |
| @@ -26,7 +23,6 @@ public: | |||
| 26 | 23 | ||
| 27 | private: | 24 | private: |
| 28 | KeyboardState next_state{}; | 25 | KeyboardState next_state{}; |
| 29 | KeyboardSharedMemoryFormat& shared_memory; | ||
| 30 | Core::HID::EmulatedDevices* emulated_devices = nullptr; | 26 | Core::HID::EmulatedDevices* emulated_devices = nullptr; |
| 31 | }; | 27 | }; |
| 32 | } // namespace Service::HID | 28 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index de5b2c804..58deafbc5 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp | |||
| @@ -5,13 +5,13 @@ | |||
| 5 | #include "core/frontend/emu_window.h" | 5 | #include "core/frontend/emu_window.h" |
| 6 | #include "core/hid/emulated_devices.h" | 6 | #include "core/hid/emulated_devices.h" |
| 7 | #include "core/hid/hid_core.h" | 7 | #include "core/hid/hid_core.h" |
| 8 | #include "core/hle/service/hid/controllers/applet_resource.h" | ||
| 8 | #include "core/hle/service/hid/controllers/mouse.h" | 9 | #include "core/hle/service/hid/controllers/mouse.h" |
| 9 | #include "core/hle/service/hid/controllers/shared_memory_format.h" | 10 | #include "core/hle/service/hid/controllers/types/shared_memory_format.h" |
| 10 | 11 | ||
| 11 | namespace Service::HID { | 12 | namespace Service::HID { |
| 12 | 13 | ||
| 13 | Mouse::Mouse(Core::HID::HIDCore& hid_core_, MouseSharedMemoryFormat& mouse_shared_memory) | 14 | Mouse::Mouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} { |
| 14 | : ControllerBase{hid_core_}, shared_memory{mouse_shared_memory} { | ||
| 15 | emulated_devices = hid_core.GetEmulatedDevices(); | 15 | emulated_devices = hid_core.GetEmulatedDevices(); |
| 16 | } | 16 | } |
| 17 | 17 | ||
| @@ -21,6 +21,15 @@ void Mouse::OnInit() {} | |||
| 21 | void Mouse::OnRelease() {} | 21 | void Mouse::OnRelease() {} |
| 22 | 22 | ||
| 23 | void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | 23 | void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { |
| 24 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 25 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 26 | |||
| 27 | if (data == nullptr) { | ||
| 28 | return; | ||
| 29 | } | ||
| 30 | |||
| 31 | MouseSharedMemoryFormat& shared_memory = data->shared_memory_format->mouse; | ||
| 32 | |||
| 24 | if (!IsControllerActivated()) { | 33 | if (!IsControllerActivated()) { |
| 25 | shared_memory.mouse_lifo.buffer_count = 0; | 34 | shared_memory.mouse_lifo.buffer_count = 0; |
| 26 | shared_memory.mouse_lifo.buffer_tail = 0; | 35 | shared_memory.mouse_lifo.buffer_tail = 0; |
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h index 363f316a5..cefad956c 100644 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h | |||
| @@ -12,11 +12,9 @@ struct AnalogStickState; | |||
| 12 | } // namespace Core::HID | 12 | } // namespace Core::HID |
| 13 | 13 | ||
| 14 | namespace Service::HID { | 14 | namespace Service::HID { |
| 15 | struct MouseSharedMemoryFormat; | ||
| 16 | |||
| 17 | class Mouse final : public ControllerBase { | 15 | class Mouse final : public ControllerBase { |
| 18 | public: | 16 | public: |
| 19 | explicit Mouse(Core::HID::HIDCore& hid_core_, MouseSharedMemoryFormat& mouse_shared_memory); | 17 | explicit Mouse(Core::HID::HIDCore& hid_core_); |
| 20 | ~Mouse() override; | 18 | ~Mouse() override; |
| 21 | 19 | ||
| 22 | // Called when the controller is initialized | 20 | // Called when the controller is initialized |
| @@ -31,7 +29,6 @@ public: | |||
| 31 | private: | 29 | private: |
| 32 | Core::HID::MouseState next_state{}; | 30 | Core::HID::MouseState next_state{}; |
| 33 | Core::HID::AnalogStickState last_mouse_wheel_state{}; | 31 | Core::HID::AnalogStickState last_mouse_wheel_state{}; |
| 34 | MouseSharedMemoryFormat& shared_memory; | ||
| 35 | Core::HID::EmulatedDevices* emulated_devices = nullptr; | 32 | Core::HID::EmulatedDevices* emulated_devices = nullptr; |
| 36 | }; | 33 | }; |
| 37 | } // namespace Service::HID | 34 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 53a737cf5..c7aa606bc 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -16,8 +16,9 @@ | |||
| 16 | #include "core/hid/hid_core.h" | 16 | #include "core/hid/hid_core.h" |
| 17 | #include "core/hle/kernel/k_event.h" | 17 | #include "core/hle/kernel/k_event.h" |
| 18 | #include "core/hle/kernel/k_readable_event.h" | 18 | #include "core/hle/kernel/k_readable_event.h" |
| 19 | #include "core/hle/service/hid/controllers/applet_resource.h" | ||
| 19 | #include "core/hle/service/hid/controllers/npad.h" | 20 | #include "core/hle/service/hid/controllers/npad.h" |
| 20 | #include "core/hle/service/hid/controllers/shared_memory_format.h" | 21 | #include "core/hle/service/hid/controllers/types/shared_memory_format.h" |
| 21 | #include "core/hle/service/hid/errors.h" | 22 | #include "core/hle/service/hid/errors.h" |
| 22 | #include "core/hle/service/hid/hid_util.h" | 23 | #include "core/hle/service/hid/hid_util.h" |
| 23 | #include "core/hle/service/kernel_helpers.h" | 24 | #include "core/hle/service/kernel_helpers.h" |
| @@ -30,12 +31,10 @@ constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{ | |||
| 30 | Core::HID::NpadIdType::Handheld, | 31 | Core::HID::NpadIdType::Handheld, |
| 31 | }; | 32 | }; |
| 32 | 33 | ||
| 33 | NPad::NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format, | 34 | NPad::NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_) |
| 34 | KernelHelpers::ServiceContext& service_context_) | ||
| 35 | : ControllerBase{hid_core_}, service_context{service_context_} { | 35 | : ControllerBase{hid_core_}, service_context{service_context_} { |
| 36 | for (std::size_t i = 0; i < controller_data.size(); ++i) { | 36 | for (std::size_t i = 0; i < controller_data.size(); ++i) { |
| 37 | auto& controller = controller_data[i]; | 37 | auto& controller = controller_data[i]; |
| 38 | controller.shared_memory = &npad_shared_memory_format.npad_entry[i].internal_state; | ||
| 39 | controller.device = hid_core.GetEmulatedControllerByIndex(i); | 38 | controller.device = hid_core.GetEmulatedControllerByIndex(i); |
| 40 | controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = | 39 | controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = |
| 41 | Core::HID::DEFAULT_VIBRATION_VALUE; | 40 | Core::HID::DEFAULT_VIBRATION_VALUE; |
| @@ -297,12 +296,20 @@ void NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { | |||
| 297 | } | 296 | } |
| 298 | 297 | ||
| 299 | void NPad::OnInit() { | 298 | void NPad::OnInit() { |
| 299 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 300 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 301 | |||
| 302 | if (data == nullptr) { | ||
| 303 | return; | ||
| 304 | } | ||
| 305 | |||
| 300 | if (!IsControllerActivated()) { | 306 | if (!IsControllerActivated()) { |
| 301 | return; | 307 | return; |
| 302 | } | 308 | } |
| 303 | 309 | ||
| 304 | for (std::size_t i = 0; i < controller_data.size(); ++i) { | 310 | for (std::size_t i = 0; i < controller_data.size(); ++i) { |
| 305 | auto& controller = controller_data[i]; | 311 | auto& controller = controller_data[i]; |
| 312 | controller.shared_memory = &data->shared_memory_format->npad.npad_entry[i].internal_state; | ||
| 306 | controller.styleset_changed_event = | 313 | controller.styleset_changed_event = |
| 307 | service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i)); | 314 | service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i)); |
| 308 | } | 315 | } |
| @@ -355,7 +362,9 @@ void NPad::OnRelease() { | |||
| 355 | is_controller_initialized = false; | 362 | is_controller_initialized = false; |
| 356 | for (std::size_t i = 0; i < controller_data.size(); ++i) { | 363 | for (std::size_t i = 0; i < controller_data.size(); ++i) { |
| 357 | auto& controller = controller_data[i]; | 364 | auto& controller = controller_data[i]; |
| 358 | service_context.CloseEvent(controller.styleset_changed_event); | 365 | if (controller.styleset_changed_event) { |
| 366 | service_context.CloseEvent(controller.styleset_changed_event); | ||
| 367 | } | ||
| 359 | for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { | 368 | for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { |
| 360 | VibrateControllerAtIndex(controller.device->GetNpadIdType(), device_idx, {}); | 369 | VibrateControllerAtIndex(controller.device->GetNpadIdType(), device_idx, {}); |
| 361 | } | 370 | } |
| @@ -432,12 +441,20 @@ void NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { | |||
| 432 | } | 441 | } |
| 433 | 442 | ||
| 434 | void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | 443 | void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { |
| 444 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 445 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 446 | |||
| 447 | if (data == nullptr) { | ||
| 448 | return; | ||
| 449 | } | ||
| 450 | |||
| 435 | if (!IsControllerActivated()) { | 451 | if (!IsControllerActivated()) { |
| 436 | return; | 452 | return; |
| 437 | } | 453 | } |
| 438 | 454 | ||
| 439 | for (std::size_t i = 0; i < controller_data.size(); ++i) { | 455 | for (std::size_t i = 0; i < controller_data.size(); ++i) { |
| 440 | auto& controller = controller_data[i]; | 456 | auto& controller = controller_data[i]; |
| 457 | controller.shared_memory = &data->shared_memory_format->npad.npad_entry[i].internal_state; | ||
| 441 | auto* npad = controller.shared_memory; | 458 | auto* npad = controller.shared_memory; |
| 442 | 459 | ||
| 443 | const auto& controller_type = controller.device->GetNpadStyleIndex(); | 460 | const auto& controller_type = controller.device->GetNpadStyleIndex(); |
| @@ -976,30 +993,6 @@ Result NPad::ResetIsSixAxisSensorDeviceNewlyAssigned( | |||
| 976 | return ResultSuccess; | 993 | return ResultSuccess; |
| 977 | } | 994 | } |
| 978 | 995 | ||
| 979 | NpadSixAxisSensorLifo& NPad::GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id) { | ||
| 980 | return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_fullkey_lifo; | ||
| 981 | } | ||
| 982 | |||
| 983 | NpadSixAxisSensorLifo& NPad::GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id) { | ||
| 984 | return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_handheld_lifo; | ||
| 985 | } | ||
| 986 | |||
| 987 | NpadSixAxisSensorLifo& NPad::GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id) { | ||
| 988 | return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_left_lifo; | ||
| 989 | } | ||
| 990 | |||
| 991 | NpadSixAxisSensorLifo& NPad::GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id) { | ||
| 992 | return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_right_lifo; | ||
| 993 | } | ||
| 994 | |||
| 995 | NpadSixAxisSensorLifo& NPad::GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id) { | ||
| 996 | return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_left_lifo; | ||
| 997 | } | ||
| 998 | |||
| 999 | NpadSixAxisSensorLifo& NPad::GetSixAxisRightLifo(Core::HID::NpadIdType npad_id) { | ||
| 1000 | return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_right_lifo; | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | Result NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, | 996 | Result NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, |
| 1004 | Core::HID::NpadIdType npad_id_2) { | 997 | Core::HID::NpadIdType npad_id_2) { |
| 1005 | if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { | 998 | if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { |
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 4e2412356..80cfcb2bb 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h | |||
| @@ -30,14 +30,14 @@ class ServiceContext; | |||
| 30 | union Result; | 30 | union Result; |
| 31 | 31 | ||
| 32 | namespace Service::HID { | 32 | namespace Service::HID { |
| 33 | class AppletResource; | ||
| 33 | struct NpadInternalState; | 34 | struct NpadInternalState; |
| 34 | struct NpadSixAxisSensorLifo; | 35 | struct NpadSixAxisSensorLifo; |
| 35 | struct NpadSharedMemoryFormat; | 36 | struct NpadSharedMemoryFormat; |
| 36 | 37 | ||
| 37 | class NPad final : public ControllerBase { | 38 | class NPad final : public ControllerBase { |
| 38 | public: | 39 | public: |
| 39 | explicit NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format, | 40 | explicit NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_); |
| 40 | KernelHelpers::ServiceContext& service_context_); | ||
| 41 | ~NPad() override; | 41 | ~NPad() override; |
| 42 | 42 | ||
| 43 | // Called when the controller is initialized | 43 | // Called when the controller is initialized |
| @@ -106,13 +106,6 @@ public: | |||
| 106 | Result ResetIsSixAxisSensorDeviceNewlyAssigned( | 106 | Result ResetIsSixAxisSensorDeviceNewlyAssigned( |
| 107 | const Core::HID::SixAxisSensorHandle& sixaxis_handle); | 107 | const Core::HID::SixAxisSensorHandle& sixaxis_handle); |
| 108 | 108 | ||
| 109 | NpadSixAxisSensorLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id); | ||
| 110 | NpadSixAxisSensorLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id); | ||
| 111 | NpadSixAxisSensorLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id); | ||
| 112 | NpadSixAxisSensorLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id); | ||
| 113 | NpadSixAxisSensorLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id); | ||
| 114 | NpadSixAxisSensorLifo& GetSixAxisRightLifo(Core::HID::NpadIdType npad_id); | ||
| 115 | |||
| 116 | Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const; | 109 | Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const; |
| 117 | Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id, | 110 | Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id, |
| 118 | bool& is_enabled) const; | 111 | bool& is_enabled) const; |
diff --git a/src/core/hle/service/hid/controllers/shared_memory_holder.cpp b/src/core/hle/service/hid/controllers/shared_memory_holder.cpp index 51581188e..0bc5169c6 100644 --- a/src/core/hle/service/hid/controllers/shared_memory_holder.cpp +++ b/src/core/hle/service/hid/controllers/shared_memory_holder.cpp | |||
| @@ -3,8 +3,9 @@ | |||
| 3 | 3 | ||
| 4 | #include "core/core.h" | 4 | #include "core/core.h" |
| 5 | #include "core/hle/kernel/k_shared_memory.h" | 5 | #include "core/hle/kernel/k_shared_memory.h" |
| 6 | #include "core/hle/service/hid/controllers/shared_memory_format.h" | 6 | #include "core/hle/service/hid/controllers/applet_resource.h" |
| 7 | #include "core/hle/service/hid/controllers/shared_memory_holder.h" | 7 | #include "core/hle/service/hid/controllers/shared_memory_holder.h" |
| 8 | #include "core/hle/service/hid/controllers/types/shared_memory_format.h" | ||
| 8 | #include "core/hle/service/hid/errors.h" | 9 | #include "core/hle/service/hid/errors.h" |
| 9 | 10 | ||
| 10 | namespace Service::HID { | 11 | namespace Service::HID { |
diff --git a/src/core/hle/service/hid/controllers/six_axis.cpp b/src/core/hle/service/hid/controllers/six_axis.cpp index 36b72f9ea..a5a67dea6 100644 --- a/src/core/hle/service/hid/controllers/six_axis.cpp +++ b/src/core/hle/service/hid/controllers/six_axis.cpp | |||
| @@ -6,8 +6,8 @@ | |||
| 6 | #include "core/hid/emulated_controller.h" | 6 | #include "core/hid/emulated_controller.h" |
| 7 | #include "core/hid/hid_core.h" | 7 | #include "core/hid/hid_core.h" |
| 8 | #include "core/hle/service/hid/controllers/npad.h" | 8 | #include "core/hle/service/hid/controllers/npad.h" |
| 9 | #include "core/hle/service/hid/controllers/shared_memory_format.h" | ||
| 10 | #include "core/hle/service/hid/controllers/six_axis.h" | 9 | #include "core/hle/service/hid/controllers/six_axis.h" |
| 10 | #include "core/hle/service/hid/controllers/types/shared_memory_format.h" | ||
| 11 | #include "core/hle/service/hid/errors.h" | 11 | #include "core/hle/service/hid/errors.h" |
| 12 | #include "core/hle/service/hid/hid_util.h" | 12 | #include "core/hle/service/hid/hid_util.h" |
| 13 | 13 | ||
| @@ -27,14 +27,20 @@ void SixAxis::OnInit() {} | |||
| 27 | void SixAxis::OnRelease() {} | 27 | void SixAxis::OnRelease() {} |
| 28 | 28 | ||
| 29 | void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | 29 | void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { |
| 30 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 31 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 32 | |||
| 33 | if (data == nullptr) { | ||
| 34 | return; | ||
| 35 | } | ||
| 36 | |||
| 30 | if (!IsControllerActivated()) { | 37 | if (!IsControllerActivated()) { |
| 31 | return; | 38 | return; |
| 32 | } | 39 | } |
| 33 | 40 | ||
| 34 | for (std::size_t i = 0; i < controller_data.size(); ++i) { | 41 | for (std::size_t i = 0; i < controller_data.size(); ++i) { |
| 42 | NpadSharedMemoryEntry& shared_memory = data->shared_memory_format->npad.npad_entry[i]; | ||
| 35 | auto& controller = controller_data[i]; | 43 | auto& controller = controller_data[i]; |
| 36 | |||
| 37 | const auto npad_id = IndexToNpadIdType(i); | ||
| 38 | const auto& controller_type = controller.device->GetNpadStyleIndex(); | 44 | const auto& controller_type = controller.device->GetNpadStyleIndex(); |
| 39 | 45 | ||
| 40 | if (controller_type == Core::HID::NpadStyleIndex::None || | 46 | if (controller_type == Core::HID::NpadStyleIndex::None || |
| @@ -50,12 +56,12 @@ void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | |||
| 50 | auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state; | 56 | auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state; |
| 51 | auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state; | 57 | auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state; |
| 52 | 58 | ||
| 53 | auto& sixaxis_fullkey_lifo = npad->GetSixAxisFullkeyLifo(npad_id); | 59 | auto& sixaxis_fullkey_lifo = shared_memory.internal_state.sixaxis_fullkey_lifo; |
| 54 | auto& sixaxis_handheld_lifo = npad->GetSixAxisHandheldLifo(npad_id); | 60 | auto& sixaxis_handheld_lifo = shared_memory.internal_state.sixaxis_handheld_lifo; |
| 55 | auto& sixaxis_dual_left_lifo = npad->GetSixAxisDualLeftLifo(npad_id); | 61 | auto& sixaxis_dual_left_lifo = shared_memory.internal_state.sixaxis_dual_left_lifo; |
| 56 | auto& sixaxis_dual_right_lifo = npad->GetSixAxisDualRightLifo(npad_id); | 62 | auto& sixaxis_dual_right_lifo = shared_memory.internal_state.sixaxis_dual_right_lifo; |
| 57 | auto& sixaxis_left_lifo = npad->GetSixAxisLeftLifo(npad_id); | 63 | auto& sixaxis_left_lifo = shared_memory.internal_state.sixaxis_left_lifo; |
| 58 | auto& sixaxis_right_lifo = npad->GetSixAxisRightLifo(npad_id); | 64 | auto& sixaxis_right_lifo = shared_memory.internal_state.sixaxis_right_lifo; |
| 59 | 65 | ||
| 60 | // Clear previous state | 66 | // Clear previous state |
| 61 | sixaxis_fullkey_state = {}; | 67 | sixaxis_fullkey_state = {}; |
diff --git a/src/core/hle/service/hid/controllers/sleep_button.cpp b/src/core/hle/service/hid/controllers/sleep_button.cpp new file mode 100644 index 000000000..978dc4c1f --- /dev/null +++ b/src/core/hle/service/hid/controllers/sleep_button.cpp | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core_timing.h" | ||
| 5 | #include "core/hle/service/hid/controllers/applet_resource.h" | ||
| 6 | #include "core/hle/service/hid/controllers/sleep_button.h" | ||
| 7 | #include "core/hle/service/hid/controllers/types/shared_memory_format.h" | ||
| 8 | |||
| 9 | namespace Service::HID { | ||
| 10 | |||
| 11 | SleepButton::SleepButton(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} | ||
| 12 | |||
| 13 | SleepButton::~SleepButton() = default; | ||
| 14 | |||
| 15 | void SleepButton::OnInit() {} | ||
| 16 | |||
| 17 | void SleepButton::OnRelease() {} | ||
| 18 | |||
| 19 | void SleepButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | ||
| 20 | if (!smart_update) { | ||
| 21 | return; | ||
| 22 | } | ||
| 23 | |||
| 24 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 25 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 26 | |||
| 27 | if (data == nullptr) { | ||
| 28 | return; | ||
| 29 | } | ||
| 30 | |||
| 31 | auto& header = data->shared_memory_format->capture_button.header; | ||
| 32 | header.timestamp = core_timing.GetGlobalTimeNs().count(); | ||
| 33 | header.total_entry_count = 17; | ||
| 34 | header.entry_count = 0; | ||
| 35 | header.last_entry_index = 0; | ||
| 36 | } | ||
| 37 | |||
| 38 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/hid/controllers/sleep_button.h b/src/core/hle/service/hid/controllers/sleep_button.h new file mode 100644 index 000000000..59964bf63 --- /dev/null +++ b/src/core/hle/service/hid/controllers/sleep_button.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/hid/controllers/controller_base.h" | ||
| 7 | |||
| 8 | namespace Service::HID { | ||
| 9 | |||
| 10 | class SleepButton final : public ControllerBase { | ||
| 11 | public: | ||
| 12 | explicit SleepButton(Core::HID::HIDCore& hid_core_); | ||
| 13 | ~SleepButton() override; | ||
| 14 | |||
| 15 | // Called when the controller is initialized | ||
| 16 | void OnInit() override; | ||
| 17 | |||
| 18 | // When the controller is released | ||
| 19 | void OnRelease() override; | ||
| 20 | |||
| 21 | // When the controller is requesting an update for the shared memory | ||
| 22 | void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; | ||
| 23 | |||
| 24 | private: | ||
| 25 | bool smart_update{}; | ||
| 26 | }; | ||
| 27 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp deleted file mode 100644 index e2a5f5d79..000000000 --- a/src/core/hle/service/hid/controllers/stubbed.cpp +++ /dev/null | |||
| @@ -1,31 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core_timing.h" | ||
| 5 | #include "core/hle/service/hid/controllers/shared_memory_format.h" | ||
| 6 | #include "core/hle/service/hid/controllers/stubbed.h" | ||
| 7 | |||
| 8 | namespace Service::HID { | ||
| 9 | |||
| 10 | Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_, | ||
| 11 | CommonHeader& ring_lifo_header) | ||
| 12 | : ControllerBase{hid_core_}, header{ring_lifo_header} {} | ||
| 13 | |||
| 14 | Controller_Stubbed::~Controller_Stubbed() = default; | ||
| 15 | |||
| 16 | void Controller_Stubbed::OnInit() {} | ||
| 17 | |||
| 18 | void Controller_Stubbed::OnRelease() {} | ||
| 19 | |||
| 20 | void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | ||
| 21 | if (!smart_update) { | ||
| 22 | return; | ||
| 23 | } | ||
| 24 | |||
| 25 | header.timestamp = core_timing.GetGlobalTimeNs().count(); | ||
| 26 | header.total_entry_count = 17; | ||
| 27 | header.entry_count = 0; | ||
| 28 | header.last_entry_index = 0; | ||
| 29 | } | ||
| 30 | |||
| 31 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 469750006..291dc707e 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp | |||
| @@ -8,15 +8,14 @@ | |||
| 8 | #include "core/frontend/emu_window.h" | 8 | #include "core/frontend/emu_window.h" |
| 9 | #include "core/hid/emulated_console.h" | 9 | #include "core/hid/emulated_console.h" |
| 10 | #include "core/hid/hid_core.h" | 10 | #include "core/hid/hid_core.h" |
| 11 | #include "core/hle/service/hid/controllers/shared_memory_format.h" | 11 | #include "core/hle/service/hid/controllers/applet_resource.h" |
| 12 | #include "core/hle/service/hid/controllers/touchscreen.h" | 12 | #include "core/hle/service/hid/controllers/touchscreen.h" |
| 13 | #include "core/hle/service/hid/controllers/types/shared_memory_format.h" | ||
| 13 | 14 | ||
| 14 | namespace Service::HID { | 15 | namespace Service::HID { |
| 15 | 16 | ||
| 16 | TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_, | 17 | TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_) |
| 17 | TouchScreenSharedMemoryFormat& touch_shared_memory) | 18 | : ControllerBase{hid_core_}, touchscreen_width(Layout::ScreenUndocked::Width), |
| 18 | : ControllerBase{hid_core_}, shared_memory{touch_shared_memory}, | ||
| 19 | touchscreen_width(Layout::ScreenUndocked::Width), | ||
| 20 | touchscreen_height(Layout::ScreenUndocked::Height) { | 19 | touchscreen_height(Layout::ScreenUndocked::Height) { |
| 21 | console = hid_core.GetEmulatedConsole(); | 20 | console = hid_core.GetEmulatedConsole(); |
| 22 | } | 21 | } |
| @@ -28,6 +27,14 @@ void TouchScreen::OnInit() {} | |||
| 28 | void TouchScreen::OnRelease() {} | 27 | void TouchScreen::OnRelease() {} |
| 29 | 28 | ||
| 30 | void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | 29 | void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) { |
| 30 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 31 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 32 | |||
| 33 | if (data == nullptr) { | ||
| 34 | return; | ||
| 35 | } | ||
| 36 | |||
| 37 | TouchScreenSharedMemoryFormat& shared_memory = data->shared_memory_format->touch_screen; | ||
| 31 | shared_memory.touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count(); | 38 | shared_memory.touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count(); |
| 32 | 39 | ||
| 33 | if (!IsControllerActivated()) { | 40 | if (!IsControllerActivated()) { |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 5b6305bfc..945d359be 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h | |||
| @@ -18,8 +18,7 @@ struct TouchScreenSharedMemoryFormat; | |||
| 18 | 18 | ||
| 19 | class TouchScreen final : public ControllerBase { | 19 | class TouchScreen final : public ControllerBase { |
| 20 | public: | 20 | public: |
| 21 | explicit TouchScreen(Core::HID::HIDCore& hid_core_, | 21 | explicit TouchScreen(Core::HID::HIDCore& hid_core_); |
| 22 | TouchScreenSharedMemoryFormat& touch_shared_memory); | ||
| 23 | ~TouchScreen() override; | 22 | ~TouchScreen() override; |
| 24 | 23 | ||
| 25 | // Called when the controller is initialized | 24 | // Called when the controller is initialized |
| @@ -35,7 +34,6 @@ public: | |||
| 35 | 34 | ||
| 36 | private: | 35 | private: |
| 37 | TouchScreenState next_state{}; | 36 | TouchScreenState next_state{}; |
| 38 | TouchScreenSharedMemoryFormat& shared_memory; | ||
| 39 | Core::HID::EmulatedConsole* console = nullptr; | 37 | Core::HID::EmulatedConsole* console = nullptr; |
| 40 | 38 | ||
| 41 | std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{}; | 39 | std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{}; |
diff --git a/src/core/hle/service/hid/controllers/shared_memory_format.h b/src/core/hle/service/hid/controllers/types/shared_memory_format.h index 2986c113e..2986c113e 100644 --- a/src/core/hle/service/hid/controllers/shared_memory_format.h +++ b/src/core/hle/service/hid/controllers/types/shared_memory_format.h | |||
diff --git a/src/core/hle/service/hid/controllers/unique_pad.cpp b/src/core/hle/service/hid/controllers/unique_pad.cpp new file mode 100644 index 000000000..8230501a5 --- /dev/null +++ b/src/core/hle/service/hid/controllers/unique_pad.cpp | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core_timing.h" | ||
| 5 | #include "core/hle/service/hid/controllers/applet_resource.h" | ||
| 6 | #include "core/hle/service/hid/controllers/types/shared_memory_format.h" | ||
| 7 | #include "core/hle/service/hid/controllers/unique_pad.h" | ||
| 8 | |||
| 9 | namespace Service::HID { | ||
| 10 | |||
| 11 | UniquePad::UniquePad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} | ||
| 12 | |||
| 13 | UniquePad::~UniquePad() = default; | ||
| 14 | |||
| 15 | void UniquePad::OnInit() {} | ||
| 16 | |||
| 17 | void UniquePad::OnRelease() {} | ||
| 18 | |||
| 19 | void UniquePad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | ||
| 20 | if (!smart_update) { | ||
| 21 | return; | ||
| 22 | } | ||
| 23 | |||
| 24 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 25 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 26 | |||
| 27 | if (data == nullptr) { | ||
| 28 | return; | ||
| 29 | } | ||
| 30 | |||
| 31 | auto& header = data->shared_memory_format->capture_button.header; | ||
| 32 | header.timestamp = core_timing.GetGlobalTimeNs().count(); | ||
| 33 | header.total_entry_count = 17; | ||
| 34 | header.entry_count = 0; | ||
| 35 | header.last_entry_index = 0; | ||
| 36 | } | ||
| 37 | |||
| 38 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/hid/controllers/unique_pad.h b/src/core/hle/service/hid/controllers/unique_pad.h new file mode 100644 index 000000000..966368264 --- /dev/null +++ b/src/core/hle/service/hid/controllers/unique_pad.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/hid/controllers/controller_base.h" | ||
| 7 | |||
| 8 | namespace Service::HID { | ||
| 9 | |||
| 10 | class UniquePad final : public ControllerBase { | ||
| 11 | public: | ||
| 12 | explicit UniquePad(Core::HID::HIDCore& hid_core_); | ||
| 13 | ~UniquePad() override; | ||
| 14 | |||
| 15 | // Called when the controller is initialized | ||
| 16 | void OnInit() override; | ||
| 17 | |||
| 18 | // When the controller is released | ||
| 19 | void OnRelease() override; | ||
| 20 | |||
| 21 | // When the controller is requesting an update for the shared memory | ||
| 22 | void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; | ||
| 23 | |||
| 24 | private: | ||
| 25 | bool smart_update{}; | ||
| 26 | }; | ||
| 27 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp index d12f9beb0..ffa7e144d 100644 --- a/src/core/hle/service/hid/hidbus.cpp +++ b/src/core/hle/service/hid/hidbus.cpp | |||
| @@ -49,10 +49,10 @@ HidBus::HidBus(Core::System& system_) | |||
| 49 | // Register update callbacks | 49 | // Register update callbacks |
| 50 | hidbus_update_event = Core::Timing::CreateEvent( | 50 | hidbus_update_event = Core::Timing::CreateEvent( |
| 51 | "Hidbus::UpdateCallback", | 51 | "Hidbus::UpdateCallback", |
| 52 | [this](std::uintptr_t user_data, s64 time, | 52 | [this](s64 time, |
| 53 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | 53 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { |
| 54 | const auto guard = LockService(); | 54 | const auto guard = LockService(); |
| 55 | UpdateHidbus(user_data, ns_late); | 55 | UpdateHidbus(ns_late); |
| 56 | return std::nullopt; | 56 | return std::nullopt; |
| 57 | }); | 57 | }); |
| 58 | 58 | ||
| @@ -61,10 +61,10 @@ HidBus::HidBus(Core::System& system_) | |||
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | HidBus::~HidBus() { | 63 | HidBus::~HidBus() { |
| 64 | system.CoreTiming().UnscheduleEvent(hidbus_update_event, 0); | 64 | system.CoreTiming().UnscheduleEvent(hidbus_update_event); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 67 | void HidBus::UpdateHidbus(std::chrono::nanoseconds ns_late) { |
| 68 | if (is_hidbus_enabled) { | 68 | if (is_hidbus_enabled) { |
| 69 | for (std::size_t i = 0; i < devices.size(); ++i) { | 69 | for (std::size_t i = 0; i < devices.size(); ++i) { |
| 70 | if (!devices[i].is_device_initializated) { | 70 | if (!devices[i].is_device_initializated) { |
diff --git a/src/core/hle/service/hid/hidbus.h b/src/core/hle/service/hid/hidbus.h index c29b5e882..85a1df133 100644 --- a/src/core/hle/service/hid/hidbus.h +++ b/src/core/hle/service/hid/hidbus.h | |||
| @@ -108,7 +108,7 @@ private: | |||
| 108 | void DisableJoyPollingReceiveMode(HLERequestContext& ctx); | 108 | void DisableJoyPollingReceiveMode(HLERequestContext& ctx); |
| 109 | void SetStatusManagerType(HLERequestContext& ctx); | 109 | void SetStatusManagerType(HLERequestContext& ctx); |
| 110 | 110 | ||
| 111 | void UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | 111 | void UpdateHidbus(std::chrono::nanoseconds ns_late); |
| 112 | std::optional<std::size_t> GetDeviceIndexFromHandle(BusHandle handle) const; | 112 | std::optional<std::size_t> GetDeviceIndexFromHandle(BusHandle handle) const; |
| 113 | 113 | ||
| 114 | template <typename T> | 114 | template <typename T> |
diff --git a/src/core/hle/service/hid/resource_manager.cpp b/src/core/hle/service/hid/resource_manager.cpp index 6c6cbd802..84b4be3ed 100644 --- a/src/core/hle/service/hid/resource_manager.cpp +++ b/src/core/hle/service/hid/resource_manager.cpp | |||
| @@ -10,18 +10,23 @@ | |||
| 10 | #include "core/hle/service/ipc_helpers.h" | 10 | #include "core/hle/service/ipc_helpers.h" |
| 11 | 11 | ||
| 12 | #include "core/hle/service/hid/controllers/applet_resource.h" | 12 | #include "core/hle/service/hid/controllers/applet_resource.h" |
| 13 | #include "core/hle/service/hid/controllers/capture_button.h" | ||
| 13 | #include "core/hle/service/hid/controllers/console_six_axis.h" | 14 | #include "core/hle/service/hid/controllers/console_six_axis.h" |
| 15 | #include "core/hle/service/hid/controllers/debug_mouse.h" | ||
| 14 | #include "core/hle/service/hid/controllers/debug_pad.h" | 16 | #include "core/hle/service/hid/controllers/debug_pad.h" |
| 17 | #include "core/hle/service/hid/controllers/digitizer.h" | ||
| 15 | #include "core/hle/service/hid/controllers/gesture.h" | 18 | #include "core/hle/service/hid/controllers/gesture.h" |
| 19 | #include "core/hle/service/hid/controllers/home_button.h" | ||
| 16 | #include "core/hle/service/hid/controllers/keyboard.h" | 20 | #include "core/hle/service/hid/controllers/keyboard.h" |
| 17 | #include "core/hle/service/hid/controllers/mouse.h" | 21 | #include "core/hle/service/hid/controllers/mouse.h" |
| 18 | #include "core/hle/service/hid/controllers/npad.h" | 22 | #include "core/hle/service/hid/controllers/npad.h" |
| 19 | #include "core/hle/service/hid/controllers/palma.h" | 23 | #include "core/hle/service/hid/controllers/palma.h" |
| 20 | #include "core/hle/service/hid/controllers/seven_six_axis.h" | 24 | #include "core/hle/service/hid/controllers/seven_six_axis.h" |
| 21 | #include "core/hle/service/hid/controllers/shared_memory_format.h" | ||
| 22 | #include "core/hle/service/hid/controllers/six_axis.h" | 25 | #include "core/hle/service/hid/controllers/six_axis.h" |
| 23 | #include "core/hle/service/hid/controllers/stubbed.h" | 26 | #include "core/hle/service/hid/controllers/sleep_button.h" |
| 24 | #include "core/hle/service/hid/controllers/touchscreen.h" | 27 | #include "core/hle/service/hid/controllers/touchscreen.h" |
| 28 | #include "core/hle/service/hid/controllers/types/shared_memory_format.h" | ||
| 29 | #include "core/hle/service/hid/controllers/unique_pad.h" | ||
| 25 | 30 | ||
| 26 | namespace Service::HID { | 31 | namespace Service::HID { |
| 27 | 32 | ||
| @@ -46,42 +51,13 @@ void ResourceManager::Initialize() { | |||
| 46 | } | 51 | } |
| 47 | 52 | ||
| 48 | system.HIDCore().ReloadInputDevices(); | 53 | system.HIDCore().ReloadInputDevices(); |
| 49 | is_initialized = true; | ||
| 50 | } | ||
| 51 | |||
| 52 | void ResourceManager::InitializeController(u64 aruid) { | ||
| 53 | SharedMemoryFormat* shared_memory = nullptr; | ||
| 54 | const auto result = applet_resource->GetSharedMemoryFormat(&shared_memory, aruid); | ||
| 55 | if (result.IsError()) { | ||
| 56 | return; | ||
| 57 | } | ||
| 58 | |||
| 59 | debug_pad = std::make_shared<DebugPad>(system.HIDCore(), shared_memory->debug_pad); | ||
| 60 | mouse = std::make_shared<Mouse>(system.HIDCore(), shared_memory->mouse); | ||
| 61 | debug_mouse = std::make_shared<DebugMouse>(system.HIDCore(), shared_memory->debug_mouse); | ||
| 62 | keyboard = std::make_shared<Keyboard>(system.HIDCore(), shared_memory->keyboard); | ||
| 63 | unique_pad = std::make_shared<UniquePad>(system.HIDCore(), shared_memory->unique_pad.header); | ||
| 64 | npad = std::make_shared<NPad>(system.HIDCore(), shared_memory->npad, service_context); | ||
| 65 | gesture = std::make_shared<Gesture>(system.HIDCore(), shared_memory->gesture); | ||
| 66 | touch_screen = std::make_shared<TouchScreen>(system.HIDCore(), shared_memory->touch_screen); | ||
| 67 | 54 | ||
| 68 | palma = std::make_shared<Palma>(system.HIDCore(), service_context); | 55 | InitializeHidCommonSampler(); |
| 56 | InitializeTouchScreenSampler(); | ||
| 57 | InitializeConsoleSixAxisSampler(); | ||
| 58 | InitializeAHidSampler(); | ||
| 69 | 59 | ||
| 70 | home_button = std::make_shared<HomeButton>(system.HIDCore(), shared_memory->home_button.header); | 60 | is_initialized = true; |
| 71 | sleep_button = | ||
| 72 | std::make_shared<SleepButton>(system.HIDCore(), shared_memory->sleep_button.header); | ||
| 73 | capture_button = | ||
| 74 | std::make_shared<CaptureButton>(system.HIDCore(), shared_memory->capture_button.header); | ||
| 75 | digitizer = std::make_shared<Digitizer>(system.HIDCore(), shared_memory->digitizer.header); | ||
| 76 | |||
| 77 | six_axis = std::make_shared<SixAxis>(system.HIDCore(), npad); | ||
| 78 | console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore(), shared_memory->console); | ||
| 79 | seven_six_axis = std::make_shared<SevenSixAxis>(system); | ||
| 80 | |||
| 81 | // Homebrew doesn't try to activate some controllers, so we activate them by default | ||
| 82 | npad->Activate(); | ||
| 83 | six_axis->Activate(); | ||
| 84 | touch_screen->Activate(); | ||
| 85 | } | 61 | } |
| 86 | 62 | ||
| 87 | std::shared_ptr<AppletResource> ResourceManager::GetAppletResource() const { | 63 | std::shared_ptr<AppletResource> ResourceManager::GetAppletResource() const { |
| @@ -165,16 +141,65 @@ Result ResourceManager::CreateAppletResource(u64 aruid) { | |||
| 165 | if (result.IsError()) { | 141 | if (result.IsError()) { |
| 166 | return result; | 142 | return result; |
| 167 | } | 143 | } |
| 144 | |||
| 145 | // Homebrew doesn't try to activate some controllers, so we activate them by default | ||
| 146 | npad->Activate(); | ||
| 147 | six_axis->Activate(); | ||
| 148 | touch_screen->Activate(); | ||
| 149 | |||
| 168 | return GetNpad()->Activate(aruid); | 150 | return GetNpad()->Activate(aruid); |
| 169 | } | 151 | } |
| 170 | 152 | ||
| 171 | Result ResourceManager::CreateAppletResourceImpl(u64 aruid) { | 153 | Result ResourceManager::CreateAppletResourceImpl(u64 aruid) { |
| 172 | std::scoped_lock lock{shared_mutex}; | 154 | std::scoped_lock lock{shared_mutex}; |
| 173 | const auto result = applet_resource->CreateAppletResource(aruid); | 155 | return applet_resource->CreateAppletResource(aruid); |
| 174 | if (result.IsSuccess()) { | 156 | } |
| 175 | InitializeController(aruid); | 157 | |
| 176 | } | 158 | void ResourceManager::InitializeHidCommonSampler() { |
| 177 | return result; | 159 | debug_pad = std::make_shared<DebugPad>(system.HIDCore()); |
| 160 | mouse = std::make_shared<Mouse>(system.HIDCore()); | ||
| 161 | debug_mouse = std::make_shared<DebugMouse>(system.HIDCore()); | ||
| 162 | keyboard = std::make_shared<Keyboard>(system.HIDCore()); | ||
| 163 | unique_pad = std::make_shared<UniquePad>(system.HIDCore()); | ||
| 164 | npad = std::make_shared<NPad>(system.HIDCore(), service_context); | ||
| 165 | gesture = std::make_shared<Gesture>(system.HIDCore()); | ||
| 166 | home_button = std::make_shared<HomeButton>(system.HIDCore()); | ||
| 167 | sleep_button = std::make_shared<SleepButton>(system.HIDCore()); | ||
| 168 | capture_button = std::make_shared<CaptureButton>(system.HIDCore()); | ||
| 169 | digitizer = std::make_shared<Digitizer>(system.HIDCore()); | ||
| 170 | |||
| 171 | palma = std::make_shared<Palma>(system.HIDCore(), service_context); | ||
| 172 | six_axis = std::make_shared<SixAxis>(system.HIDCore(), npad); | ||
| 173 | |||
| 174 | debug_pad->SetAppletResource(applet_resource); | ||
| 175 | digitizer->SetAppletResource(applet_resource); | ||
| 176 | keyboard->SetAppletResource(applet_resource); | ||
| 177 | npad->SetAppletResource(applet_resource); | ||
| 178 | six_axis->SetAppletResource(applet_resource); | ||
| 179 | mouse->SetAppletResource(applet_resource); | ||
| 180 | debug_mouse->SetAppletResource(applet_resource); | ||
| 181 | home_button->SetAppletResource(applet_resource); | ||
| 182 | sleep_button->SetAppletResource(applet_resource); | ||
| 183 | capture_button->SetAppletResource(applet_resource); | ||
| 184 | } | ||
| 185 | |||
| 186 | void ResourceManager::InitializeTouchScreenSampler() { | ||
| 187 | gesture = std::make_shared<Gesture>(system.HIDCore()); | ||
| 188 | touch_screen = std::make_shared<TouchScreen>(system.HIDCore()); | ||
| 189 | |||
| 190 | touch_screen->SetAppletResource(applet_resource); | ||
| 191 | gesture->SetAppletResource(applet_resource); | ||
| 192 | } | ||
| 193 | |||
| 194 | void ResourceManager::InitializeConsoleSixAxisSampler() { | ||
| 195 | console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore()); | ||
| 196 | seven_six_axis = std::make_shared<SevenSixAxis>(system); | ||
| 197 | |||
| 198 | console_six_axis->SetAppletResource(applet_resource); | ||
| 199 | } | ||
| 200 | |||
| 201 | void ResourceManager::InitializeAHidSampler() { | ||
| 202 | // TODO | ||
| 178 | } | 203 | } |
| 179 | 204 | ||
| 180 | Result ResourceManager::RegisterCoreAppletResource() { | 205 | Result ResourceManager::RegisterCoreAppletResource() { |
| @@ -227,8 +252,7 @@ void ResourceManager::EnableTouchScreen(u64 aruid, bool is_enabled) { | |||
| 227 | applet_resource->EnableTouchScreen(aruid, is_enabled); | 252 | applet_resource->EnableTouchScreen(aruid, is_enabled); |
| 228 | } | 253 | } |
| 229 | 254 | ||
| 230 | void ResourceManager::UpdateControllers(std::uintptr_t user_data, | 255 | void ResourceManager::UpdateControllers(std::chrono::nanoseconds ns_late) { |
| 231 | std::chrono::nanoseconds ns_late) { | ||
| 232 | auto& core_timing = system.CoreTiming(); | 256 | auto& core_timing = system.CoreTiming(); |
| 233 | debug_pad->OnUpdate(core_timing); | 257 | debug_pad->OnUpdate(core_timing); |
| 234 | digitizer->OnUpdate(core_timing); | 258 | digitizer->OnUpdate(core_timing); |
| @@ -241,20 +265,19 @@ void ResourceManager::UpdateControllers(std::uintptr_t user_data, | |||
| 241 | capture_button->OnUpdate(core_timing); | 265 | capture_button->OnUpdate(core_timing); |
| 242 | } | 266 | } |
| 243 | 267 | ||
| 244 | void ResourceManager::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 268 | void ResourceManager::UpdateNpad(std::chrono::nanoseconds ns_late) { |
| 245 | auto& core_timing = system.CoreTiming(); | 269 | auto& core_timing = system.CoreTiming(); |
| 246 | npad->OnUpdate(core_timing); | 270 | npad->OnUpdate(core_timing); |
| 247 | } | 271 | } |
| 248 | 272 | ||
| 249 | void ResourceManager::UpdateMouseKeyboard(std::uintptr_t user_data, | 273 | void ResourceManager::UpdateMouseKeyboard(std::chrono::nanoseconds ns_late) { |
| 250 | std::chrono::nanoseconds ns_late) { | ||
| 251 | auto& core_timing = system.CoreTiming(); | 274 | auto& core_timing = system.CoreTiming(); |
| 252 | mouse->OnUpdate(core_timing); | 275 | mouse->OnUpdate(core_timing); |
| 253 | debug_mouse->OnUpdate(core_timing); | 276 | debug_mouse->OnUpdate(core_timing); |
| 254 | keyboard->OnUpdate(core_timing); | 277 | keyboard->OnUpdate(core_timing); |
| 255 | } | 278 | } |
| 256 | 279 | ||
| 257 | void ResourceManager::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 280 | void ResourceManager::UpdateMotion(std::chrono::nanoseconds ns_late) { |
| 258 | auto& core_timing = system.CoreTiming(); | 281 | auto& core_timing = system.CoreTiming(); |
| 259 | six_axis->OnUpdate(core_timing); | 282 | six_axis->OnUpdate(core_timing); |
| 260 | seven_six_axis->OnUpdate(core_timing); | 283 | seven_six_axis->OnUpdate(core_timing); |
| @@ -273,34 +296,34 @@ IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<Resource | |||
| 273 | // Register update callbacks | 296 | // Register update callbacks |
| 274 | npad_update_event = Core::Timing::CreateEvent( | 297 | npad_update_event = Core::Timing::CreateEvent( |
| 275 | "HID::UpdatePadCallback", | 298 | "HID::UpdatePadCallback", |
| 276 | [this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late) | 299 | [this, resource]( |
| 277 | -> std::optional<std::chrono::nanoseconds> { | 300 | s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { |
| 278 | const auto guard = LockService(); | 301 | const auto guard = LockService(); |
| 279 | resource->UpdateNpad(user_data, ns_late); | 302 | resource->UpdateNpad(ns_late); |
| 280 | return std::nullopt; | 303 | return std::nullopt; |
| 281 | }); | 304 | }); |
| 282 | default_update_event = Core::Timing::CreateEvent( | 305 | default_update_event = Core::Timing::CreateEvent( |
| 283 | "HID::UpdateDefaultCallback", | 306 | "HID::UpdateDefaultCallback", |
| 284 | [this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late) | 307 | [this, resource]( |
| 285 | -> std::optional<std::chrono::nanoseconds> { | 308 | s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { |
| 286 | const auto guard = LockService(); | 309 | const auto guard = LockService(); |
| 287 | resource->UpdateControllers(user_data, ns_late); | 310 | resource->UpdateControllers(ns_late); |
| 288 | return std::nullopt; | 311 | return std::nullopt; |
| 289 | }); | 312 | }); |
| 290 | mouse_keyboard_update_event = Core::Timing::CreateEvent( | 313 | mouse_keyboard_update_event = Core::Timing::CreateEvent( |
| 291 | "HID::UpdateMouseKeyboardCallback", | 314 | "HID::UpdateMouseKeyboardCallback", |
| 292 | [this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late) | 315 | [this, resource]( |
| 293 | -> std::optional<std::chrono::nanoseconds> { | 316 | s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { |
| 294 | const auto guard = LockService(); | 317 | const auto guard = LockService(); |
| 295 | resource->UpdateMouseKeyboard(user_data, ns_late); | 318 | resource->UpdateMouseKeyboard(ns_late); |
| 296 | return std::nullopt; | 319 | return std::nullopt; |
| 297 | }); | 320 | }); |
| 298 | motion_update_event = Core::Timing::CreateEvent( | 321 | motion_update_event = Core::Timing::CreateEvent( |
| 299 | "HID::UpdateMotionCallback", | 322 | "HID::UpdateMotionCallback", |
| 300 | [this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late) | 323 | [this, resource]( |
| 301 | -> std::optional<std::chrono::nanoseconds> { | 324 | s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { |
| 302 | const auto guard = LockService(); | 325 | const auto guard = LockService(); |
| 303 | resource->UpdateMotion(user_data, ns_late); | 326 | resource->UpdateMotion(ns_late); |
| 304 | return std::nullopt; | 327 | return std::nullopt; |
| 305 | }); | 328 | }); |
| 306 | 329 | ||
| @@ -314,10 +337,10 @@ IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<Resource | |||
| 314 | } | 337 | } |
| 315 | 338 | ||
| 316 | IAppletResource::~IAppletResource() { | 339 | IAppletResource::~IAppletResource() { |
| 317 | system.CoreTiming().UnscheduleEvent(npad_update_event, 0); | 340 | system.CoreTiming().UnscheduleEvent(npad_update_event); |
| 318 | system.CoreTiming().UnscheduleEvent(default_update_event, 0); | 341 | system.CoreTiming().UnscheduleEvent(default_update_event); |
| 319 | system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0); | 342 | system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event); |
| 320 | system.CoreTiming().UnscheduleEvent(motion_update_event, 0); | 343 | system.CoreTiming().UnscheduleEvent(motion_update_event); |
| 321 | resource_manager->FreeAppletResourceId(aruid); | 344 | resource_manager->FreeAppletResourceId(aruid); |
| 322 | } | 345 | } |
| 323 | 346 | ||
diff --git a/src/core/hle/service/hid/resource_manager.h b/src/core/hle/service/hid/resource_manager.h index 5ad7cb564..70d9b6550 100644 --- a/src/core/hle/service/hid/resource_manager.h +++ b/src/core/hle/service/hid/resource_manager.h | |||
| @@ -20,24 +20,23 @@ class KSharedMemory; | |||
| 20 | 20 | ||
| 21 | namespace Service::HID { | 21 | namespace Service::HID { |
| 22 | class AppletResource; | 22 | class AppletResource; |
| 23 | class CaptureButton; | ||
| 23 | class Controller_Stubbed; | 24 | class Controller_Stubbed; |
| 24 | class ConsoleSixAxis; | 25 | class ConsoleSixAxis; |
| 26 | class DebugMouse; | ||
| 25 | class DebugPad; | 27 | class DebugPad; |
| 28 | class Digitizer; | ||
| 26 | class Gesture; | 29 | class Gesture; |
| 30 | class HomeButton; | ||
| 27 | class Keyboard; | 31 | class Keyboard; |
| 28 | class Mouse; | 32 | class Mouse; |
| 29 | class NPad; | 33 | class NPad; |
| 30 | class Palma; | 34 | class Palma; |
| 31 | class SevenSixAxis; | 35 | class SevenSixAxis; |
| 32 | class SixAxis; | 36 | class SixAxis; |
| 37 | class SleepButton; | ||
| 33 | class TouchScreen; | 38 | class TouchScreen; |
| 34 | 39 | class UniquePad; | |
| 35 | using CaptureButton = Controller_Stubbed; | ||
| 36 | using DebugMouse = Mouse; | ||
| 37 | using Digitizer = Controller_Stubbed; | ||
| 38 | using HomeButton = Controller_Stubbed; | ||
| 39 | using SleepButton = Controller_Stubbed; | ||
| 40 | using UniquePad = Controller_Stubbed; | ||
| 41 | 40 | ||
| 42 | class ResourceManager { | 41 | class ResourceManager { |
| 43 | 42 | ||
| @@ -46,7 +45,6 @@ public: | |||
| 46 | ~ResourceManager(); | 45 | ~ResourceManager(); |
| 47 | 46 | ||
| 48 | void Initialize(); | 47 | void Initialize(); |
| 49 | void InitializeController(u64 aruid); | ||
| 50 | 48 | ||
| 51 | std::shared_ptr<AppletResource> GetAppletResource() const; | 49 | std::shared_ptr<AppletResource> GetAppletResource() const; |
| 52 | std::shared_ptr<CaptureButton> GetCaptureButton() const; | 50 | std::shared_ptr<CaptureButton> GetCaptureButton() const; |
| @@ -81,13 +79,17 @@ public: | |||
| 81 | void EnablePadInput(u64 aruid, bool is_enabled); | 79 | void EnablePadInput(u64 aruid, bool is_enabled); |
| 82 | void EnableTouchScreen(u64 aruid, bool is_enabled); | 80 | void EnableTouchScreen(u64 aruid, bool is_enabled); |
| 83 | 81 | ||
| 84 | void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | 82 | void UpdateControllers(std::chrono::nanoseconds ns_late); |
| 85 | void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | 83 | void UpdateNpad(std::chrono::nanoseconds ns_late); |
| 86 | void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | 84 | void UpdateMouseKeyboard(std::chrono::nanoseconds ns_late); |
| 87 | void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | 85 | void UpdateMotion(std::chrono::nanoseconds ns_late); |
| 88 | 86 | ||
| 89 | private: | 87 | private: |
| 90 | Result CreateAppletResourceImpl(u64 aruid); | 88 | Result CreateAppletResourceImpl(u64 aruid); |
| 89 | void InitializeHidCommonSampler(); | ||
| 90 | void InitializeTouchScreenSampler(); | ||
| 91 | void InitializeConsoleSixAxisSampler(); | ||
| 92 | void InitializeAHidSampler(); | ||
| 91 | 93 | ||
| 92 | bool is_initialized{false}; | 94 | bool is_initialized{false}; |
| 93 | 95 | ||
diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp index a94d05e19..77aa6d7d1 100644 --- a/src/core/hle/service/jit/jit.cpp +++ b/src/core/hle/service/jit/jit.cpp | |||
| @@ -4,11 +4,11 @@ | |||
| 4 | #include "core/arm/debug.h" | 4 | #include "core/arm/debug.h" |
| 5 | #include "core/arm/symbols.h" | 5 | #include "core/arm/symbols.h" |
| 6 | #include "core/core.h" | 6 | #include "core/core.h" |
| 7 | #include "core/hle/kernel/k_code_memory.h" | ||
| 8 | #include "core/hle/kernel/k_transfer_memory.h" | 7 | #include "core/hle/kernel/k_transfer_memory.h" |
| 9 | #include "core/hle/result.h" | 8 | #include "core/hle/result.h" |
| 10 | #include "core/hle/service/ipc_helpers.h" | 9 | #include "core/hle/service/ipc_helpers.h" |
| 11 | #include "core/hle/service/jit/jit.h" | 10 | #include "core/hle/service/jit/jit.h" |
| 11 | #include "core/hle/service/jit/jit_code_memory.h" | ||
| 12 | #include "core/hle/service/jit/jit_context.h" | 12 | #include "core/hle/service/jit/jit_context.h" |
| 13 | #include "core/hle/service/server_manager.h" | 13 | #include "core/hle/service/server_manager.h" |
| 14 | #include "core/hle/service/service.h" | 14 | #include "core/hle/service/service.h" |
| @@ -23,10 +23,12 @@ struct CodeRange { | |||
| 23 | 23 | ||
| 24 | class IJitEnvironment final : public ServiceFramework<IJitEnvironment> { | 24 | class IJitEnvironment final : public ServiceFramework<IJitEnvironment> { |
| 25 | public: | 25 | public: |
| 26 | explicit IJitEnvironment(Core::System& system_, Kernel::KProcess& process_, CodeRange user_rx, | 26 | explicit IJitEnvironment(Core::System& system_, |
| 27 | CodeRange user_ro) | 27 | Kernel::KScopedAutoObject<Kernel::KProcess>&& process_, |
| 28 | : ServiceFramework{system_, "IJitEnvironment"}, process{&process_}, | 28 | CodeMemory&& user_rx_, CodeMemory&& user_ro_) |
| 29 | context{process->GetMemory()} { | 29 | : ServiceFramework{system_, "IJitEnvironment"}, process{std::move(process_)}, |
| 30 | user_rx{std::move(user_rx_)}, user_ro{std::move(user_ro_)}, | ||
| 31 | context{system_.ApplicationMemory()} { | ||
| 30 | // clang-format off | 32 | // clang-format off |
| 31 | static const FunctionInfo functions[] = { | 33 | static const FunctionInfo functions[] = { |
| 32 | {0, &IJitEnvironment::GenerateCode, "GenerateCode"}, | 34 | {0, &IJitEnvironment::GenerateCode, "GenerateCode"}, |
| @@ -39,10 +41,13 @@ public: | |||
| 39 | RegisterHandlers(functions); | 41 | RegisterHandlers(functions); |
| 40 | 42 | ||
| 41 | // Identity map user code range into sysmodule context | 43 | // Identity map user code range into sysmodule context |
| 42 | configuration.user_ro_memory = user_ro; | 44 | configuration.user_rx_memory.size = user_rx.GetSize(); |
| 43 | configuration.user_rx_memory = user_rx; | 45 | configuration.user_rx_memory.offset = user_rx.GetAddress(); |
| 44 | configuration.sys_ro_memory = user_ro; | 46 | configuration.user_ro_memory.size = user_ro.GetSize(); |
| 45 | configuration.sys_rx_memory = user_rx; | 47 | configuration.user_ro_memory.offset = user_ro.GetAddress(); |
| 48 | |||
| 49 | configuration.sys_rx_memory = configuration.user_rx_memory; | ||
| 50 | configuration.sys_ro_memory = configuration.user_ro_memory; | ||
| 46 | } | 51 | } |
| 47 | 52 | ||
| 48 | void GenerateCode(HLERequestContext& ctx) { | 53 | void GenerateCode(HLERequestContext& ctx) { |
| @@ -318,6 +323,8 @@ private: | |||
| 318 | } | 323 | } |
| 319 | 324 | ||
| 320 | Kernel::KScopedAutoObject<Kernel::KProcess> process; | 325 | Kernel::KScopedAutoObject<Kernel::KProcess> process; |
| 326 | CodeMemory user_rx; | ||
| 327 | CodeMemory user_ro; | ||
| 321 | GuestCallbacks callbacks; | 328 | GuestCallbacks callbacks; |
| 322 | JITConfiguration configuration; | 329 | JITConfiguration configuration; |
| 323 | JITContext context; | 330 | JITContext context; |
| @@ -335,6 +342,7 @@ public: | |||
| 335 | RegisterHandlers(functions); | 342 | RegisterHandlers(functions); |
| 336 | } | 343 | } |
| 337 | 344 | ||
| 345 | private: | ||
| 338 | void CreateJitEnvironment(HLERequestContext& ctx) { | 346 | void CreateJitEnvironment(HLERequestContext& ctx) { |
| 339 | LOG_DEBUG(Service_JIT, "called"); | 347 | LOG_DEBUG(Service_JIT, "called"); |
| 340 | 348 | ||
| @@ -380,20 +388,35 @@ public: | |||
| 380 | return; | 388 | return; |
| 381 | } | 389 | } |
| 382 | 390 | ||
| 383 | const CodeRange user_rx{ | 391 | CodeMemory rx, ro; |
| 384 | .offset = GetInteger(rx_mem->GetSourceAddress()), | 392 | Result res; |
| 385 | .size = parameters.rx_size, | ||
| 386 | }; | ||
| 387 | 393 | ||
| 388 | const CodeRange user_ro{ | 394 | res = rx.Initialize(*process, *rx_mem, parameters.rx_size, |
| 389 | .offset = GetInteger(ro_mem->GetSourceAddress()), | 395 | Kernel::Svc::MemoryPermission::ReadExecute, generate_random); |
| 390 | .size = parameters.ro_size, | 396 | if (R_FAILED(res)) { |
| 391 | }; | 397 | LOG_ERROR(Service_JIT, "rx_mem could not be mapped for handle=0x{:08X}", rx_mem_handle); |
| 398 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 399 | rb.Push(res); | ||
| 400 | return; | ||
| 401 | } | ||
| 402 | |||
| 403 | res = ro.Initialize(*process, *ro_mem, parameters.ro_size, | ||
| 404 | Kernel::Svc::MemoryPermission::Read, generate_random); | ||
| 405 | if (R_FAILED(res)) { | ||
| 406 | LOG_ERROR(Service_JIT, "ro_mem could not be mapped for handle=0x{:08X}", ro_mem_handle); | ||
| 407 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 408 | rb.Push(res); | ||
| 409 | return; | ||
| 410 | } | ||
| 392 | 411 | ||
| 393 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 412 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 394 | rb.Push(ResultSuccess); | 413 | rb.Push(ResultSuccess); |
| 395 | rb.PushIpcInterface<IJitEnvironment>(system, *process, user_rx, user_ro); | 414 | rb.PushIpcInterface<IJitEnvironment>(system, std::move(process), std::move(rx), |
| 415 | std::move(ro)); | ||
| 396 | } | 416 | } |
| 417 | |||
| 418 | private: | ||
| 419 | std::mt19937_64 generate_random{}; | ||
| 397 | }; | 420 | }; |
| 398 | 421 | ||
| 399 | void LoopProcess(Core::System& system) { | 422 | void LoopProcess(Core::System& system) { |
diff --git a/src/core/hle/service/jit/jit_code_memory.cpp b/src/core/hle/service/jit/jit_code_memory.cpp new file mode 100644 index 000000000..2b480488a --- /dev/null +++ b/src/core/hle/service/jit/jit_code_memory.cpp | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/jit/jit_code_memory.h" | ||
| 5 | |||
| 6 | namespace Service::JIT { | ||
| 7 | |||
| 8 | Result CodeMemory::Initialize(Kernel::KProcess& process, Kernel::KCodeMemory& code_memory, | ||
| 9 | size_t size, Kernel::Svc::MemoryPermission perm, | ||
| 10 | std::mt19937_64& generate_random) { | ||
| 11 | auto& page_table = process.GetPageTable(); | ||
| 12 | const u64 alias_code_start = | ||
| 13 | GetInteger(page_table.GetAliasCodeRegionStart()) / Kernel::PageSize; | ||
| 14 | const u64 alias_code_size = page_table.GetAliasCodeRegionSize() / Kernel::PageSize; | ||
| 15 | |||
| 16 | // NOTE: This will retry indefinitely until mapping the code memory succeeds. | ||
| 17 | while (true) { | ||
| 18 | // Generate a new trial address. | ||
| 19 | const u64 mapped_address = | ||
| 20 | (alias_code_start + (generate_random() % alias_code_size)) * Kernel::PageSize; | ||
| 21 | |||
| 22 | // Try to map the address | ||
| 23 | R_TRY_CATCH(code_memory.MapToOwner(mapped_address, size, perm)) { | ||
| 24 | R_CATCH(Kernel::ResultInvalidMemoryRegion) { | ||
| 25 | // If we could not map here, retry. | ||
| 26 | continue; | ||
| 27 | } | ||
| 28 | } | ||
| 29 | R_END_TRY_CATCH; | ||
| 30 | |||
| 31 | // Set members. | ||
| 32 | m_code_memory = std::addressof(code_memory); | ||
| 33 | m_size = size; | ||
| 34 | m_address = mapped_address; | ||
| 35 | m_perm = perm; | ||
| 36 | |||
| 37 | // Open a new reference to the code memory. | ||
| 38 | m_code_memory->Open(); | ||
| 39 | |||
| 40 | // We succeeded. | ||
| 41 | R_SUCCEED(); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | void CodeMemory::Finalize() { | ||
| 46 | if (m_code_memory) { | ||
| 47 | R_ASSERT(m_code_memory->UnmapFromOwner(m_address, m_size)); | ||
| 48 | m_code_memory->Close(); | ||
| 49 | } | ||
| 50 | |||
| 51 | m_code_memory = nullptr; | ||
| 52 | } | ||
| 53 | |||
| 54 | } // namespace Service::JIT | ||
diff --git a/src/core/hle/service/jit/jit_code_memory.h b/src/core/hle/service/jit/jit_code_memory.h new file mode 100644 index 000000000..6376d4c4e --- /dev/null +++ b/src/core/hle/service/jit/jit_code_memory.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <random> | ||
| 7 | |||
| 8 | #include "core/hle/kernel/k_code_memory.h" | ||
| 9 | |||
| 10 | namespace Service::JIT { | ||
| 11 | |||
| 12 | class CodeMemory { | ||
| 13 | public: | ||
| 14 | YUZU_NON_COPYABLE(CodeMemory); | ||
| 15 | |||
| 16 | explicit CodeMemory() = default; | ||
| 17 | |||
| 18 | CodeMemory(CodeMemory&& rhs) { | ||
| 19 | std::swap(m_code_memory, rhs.m_code_memory); | ||
| 20 | std::swap(m_size, rhs.m_size); | ||
| 21 | std::swap(m_address, rhs.m_address); | ||
| 22 | std::swap(m_perm, rhs.m_perm); | ||
| 23 | } | ||
| 24 | |||
| 25 | ~CodeMemory() { | ||
| 26 | this->Finalize(); | ||
| 27 | } | ||
| 28 | |||
| 29 | public: | ||
| 30 | Result Initialize(Kernel::KProcess& process, Kernel::KCodeMemory& code_memory, size_t size, | ||
| 31 | Kernel::Svc::MemoryPermission perm, std::mt19937_64& generate_random); | ||
| 32 | void Finalize(); | ||
| 33 | |||
| 34 | size_t GetSize() const { | ||
| 35 | return m_size; | ||
| 36 | } | ||
| 37 | |||
| 38 | u64 GetAddress() const { | ||
| 39 | return m_address; | ||
| 40 | } | ||
| 41 | |||
| 42 | private: | ||
| 43 | Kernel::KCodeMemory* m_code_memory{}; | ||
| 44 | size_t m_size{}; | ||
| 45 | u64 m_address{}; | ||
| 46 | Kernel::Svc::MemoryPermission m_perm{}; | ||
| 47 | }; | ||
| 48 | |||
| 49 | } // namespace Service::JIT | ||
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index 6352b09a9..aa8aaa2d9 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp | |||
| @@ -67,7 +67,7 @@ Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_ | |||
| 67 | // Schedule the screen composition events | 67 | // Schedule the screen composition events |
| 68 | multi_composition_event = Core::Timing::CreateEvent( | 68 | multi_composition_event = Core::Timing::CreateEvent( |
| 69 | "ScreenComposition", | 69 | "ScreenComposition", |
| 70 | [this](std::uintptr_t, s64 time, | 70 | [this](s64 time, |
| 71 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | 71 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { |
| 72 | vsync_signal.Set(); | 72 | vsync_signal.Set(); |
| 73 | return std::chrono::nanoseconds(GetNextTicks()); | 73 | return std::chrono::nanoseconds(GetNextTicks()); |
| @@ -75,7 +75,7 @@ Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_ | |||
| 75 | 75 | ||
| 76 | single_composition_event = Core::Timing::CreateEvent( | 76 | single_composition_event = Core::Timing::CreateEvent( |
| 77 | "ScreenComposition", | 77 | "ScreenComposition", |
| 78 | [this](std::uintptr_t, s64 time, | 78 | [this](s64 time, |
| 79 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | 79 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { |
| 80 | const auto lock_guard = Lock(); | 80 | const auto lock_guard = Lock(); |
| 81 | Compose(); | 81 | Compose(); |
| @@ -93,11 +93,11 @@ Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_ | |||
| 93 | 93 | ||
| 94 | Nvnflinger::~Nvnflinger() { | 94 | Nvnflinger::~Nvnflinger() { |
| 95 | if (system.IsMulticore()) { | 95 | if (system.IsMulticore()) { |
| 96 | system.CoreTiming().UnscheduleEvent(multi_composition_event, {}); | 96 | system.CoreTiming().UnscheduleEvent(multi_composition_event); |
| 97 | vsync_thread.request_stop(); | 97 | vsync_thread.request_stop(); |
| 98 | vsync_signal.Set(); | 98 | vsync_signal.Set(); |
| 99 | } else { | 99 | } else { |
| 100 | system.CoreTiming().UnscheduleEvent(single_composition_event, {}); | 100 | system.CoreTiming().UnscheduleEvent(single_composition_event); |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | ShutdownLayers(); | 103 | ShutdownLayers(); |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index c7eb32c19..8176a41be 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "common/assert.h" | 10 | #include "common/assert.h" |
| 11 | #include "common/atomic_ops.h" | 11 | #include "common/atomic_ops.h" |
| 12 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | #include "common/heap_tracker.h" | ||
| 13 | #include "common/logging/log.h" | 14 | #include "common/logging/log.h" |
| 14 | #include "common/page_table.h" | 15 | #include "common/page_table.h" |
| 15 | #include "common/scope_exit.h" | 16 | #include "common/scope_exit.h" |
| @@ -52,10 +53,18 @@ struct Memory::Impl { | |||
| 52 | } else { | 53 | } else { |
| 53 | current_page_table->fastmem_arena = nullptr; | 54 | current_page_table->fastmem_arena = nullptr; |
| 54 | } | 55 | } |
| 56 | |||
| 57 | #ifdef __linux__ | ||
| 58 | heap_tracker.emplace(system.DeviceMemory().buffer); | ||
| 59 | buffer = std::addressof(*heap_tracker); | ||
| 60 | #else | ||
| 61 | buffer = std::addressof(system.DeviceMemory().buffer); | ||
| 62 | #endif | ||
| 55 | } | 63 | } |
| 56 | 64 | ||
| 57 | void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, | 65 | void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, |
| 58 | Common::PhysicalAddress target, Common::MemoryPermission perms) { | 66 | Common::PhysicalAddress target, Common::MemoryPermission perms, |
| 67 | bool separate_heap) { | ||
| 59 | ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size); | 68 | ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size); |
| 60 | ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base)); | 69 | ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base)); |
| 61 | ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}", | 70 | ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}", |
| @@ -64,19 +73,20 @@ struct Memory::Impl { | |||
| 64 | Common::PageType::Memory); | 73 | Common::PageType::Memory); |
| 65 | 74 | ||
| 66 | if (current_page_table->fastmem_arena) { | 75 | if (current_page_table->fastmem_arena) { |
| 67 | system.DeviceMemory().buffer.Map(GetInteger(base), | 76 | buffer->Map(GetInteger(base), GetInteger(target) - DramMemoryMap::Base, size, perms, |
| 68 | GetInteger(target) - DramMemoryMap::Base, size, perms); | 77 | separate_heap); |
| 69 | } | 78 | } |
| 70 | } | 79 | } |
| 71 | 80 | ||
| 72 | void UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size) { | 81 | void UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, |
| 82 | bool separate_heap) { | ||
| 73 | ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size); | 83 | ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size); |
| 74 | ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base)); | 84 | ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base)); |
| 75 | MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, 0, | 85 | MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, 0, |
| 76 | Common::PageType::Unmapped); | 86 | Common::PageType::Unmapped); |
| 77 | 87 | ||
| 78 | if (current_page_table->fastmem_arena) { | 88 | if (current_page_table->fastmem_arena) { |
| 79 | system.DeviceMemory().buffer.Unmap(GetInteger(base), size); | 89 | buffer->Unmap(GetInteger(base), size, separate_heap); |
| 80 | } | 90 | } |
| 81 | } | 91 | } |
| 82 | 92 | ||
| @@ -89,11 +99,6 @@ struct Memory::Impl { | |||
| 89 | return; | 99 | return; |
| 90 | } | 100 | } |
| 91 | 101 | ||
| 92 | const bool is_r = True(perms & Common::MemoryPermission::Read); | ||
| 93 | const bool is_w = True(perms & Common::MemoryPermission::Write); | ||
| 94 | const bool is_x = | ||
| 95 | True(perms & Common::MemoryPermission::Execute) && Settings::IsNceEnabled(); | ||
| 96 | |||
| 97 | u64 protect_bytes{}; | 102 | u64 protect_bytes{}; |
| 98 | u64 protect_begin{}; | 103 | u64 protect_begin{}; |
| 99 | for (u64 addr = vaddr; addr < vaddr + size; addr += YUZU_PAGESIZE) { | 104 | for (u64 addr = vaddr; addr < vaddr + size; addr += YUZU_PAGESIZE) { |
| @@ -102,8 +107,7 @@ struct Memory::Impl { | |||
| 102 | switch (page_type) { | 107 | switch (page_type) { |
| 103 | case Common::PageType::RasterizerCachedMemory: | 108 | case Common::PageType::RasterizerCachedMemory: |
| 104 | if (protect_bytes > 0) { | 109 | if (protect_bytes > 0) { |
| 105 | system.DeviceMemory().buffer.Protect(protect_begin, protect_bytes, is_r, is_w, | 110 | buffer->Protect(protect_begin, protect_bytes, perms); |
| 106 | is_x); | ||
| 107 | protect_bytes = 0; | 111 | protect_bytes = 0; |
| 108 | } | 112 | } |
| 109 | break; | 113 | break; |
| @@ -116,7 +120,7 @@ struct Memory::Impl { | |||
| 116 | } | 120 | } |
| 117 | 121 | ||
| 118 | if (protect_bytes > 0) { | 122 | if (protect_bytes > 0) { |
| 119 | system.DeviceMemory().buffer.Protect(protect_begin, protect_bytes, is_r, is_w, is_x); | 123 | buffer->Protect(protect_begin, protect_bytes, perms); |
| 120 | } | 124 | } |
| 121 | } | 125 | } |
| 122 | 126 | ||
| @@ -486,7 +490,9 @@ struct Memory::Impl { | |||
| 486 | } | 490 | } |
| 487 | 491 | ||
| 488 | if (current_page_table->fastmem_arena) { | 492 | if (current_page_table->fastmem_arena) { |
| 489 | system.DeviceMemory().buffer.Protect(vaddr, size, !debug, !debug); | 493 | const auto perm{debug ? Common::MemoryPermission{} |
| 494 | : Common::MemoryPermission::ReadWrite}; | ||
| 495 | buffer->Protect(vaddr, size, perm); | ||
| 490 | } | 496 | } |
| 491 | 497 | ||
| 492 | // Iterate over a contiguous CPU address space, marking/unmarking the region. | 498 | // Iterate over a contiguous CPU address space, marking/unmarking the region. |
| @@ -543,9 +549,14 @@ struct Memory::Impl { | |||
| 543 | } | 549 | } |
| 544 | 550 | ||
| 545 | if (current_page_table->fastmem_arena) { | 551 | if (current_page_table->fastmem_arena) { |
| 546 | const bool is_read_enable = | 552 | Common::MemoryPermission perm{}; |
| 547 | !Settings::values.use_reactive_flushing.GetValue() || !cached; | 553 | if (!Settings::values.use_reactive_flushing.GetValue() || !cached) { |
| 548 | system.DeviceMemory().buffer.Protect(vaddr, size, is_read_enable, !cached); | 554 | perm |= Common::MemoryPermission::Read; |
| 555 | } | ||
| 556 | if (!cached) { | ||
| 557 | perm |= Common::MemoryPermission::Write; | ||
| 558 | } | ||
| 559 | buffer->Protect(vaddr, size, perm); | ||
| 549 | } | 560 | } |
| 550 | 561 | ||
| 551 | // Iterate over a contiguous CPU address space, which corresponds to the specified GPU | 562 | // Iterate over a contiguous CPU address space, which corresponds to the specified GPU |
| @@ -856,6 +867,13 @@ struct Memory::Impl { | |||
| 856 | std::array<GPUDirtyState, Core::Hardware::NUM_CPU_CORES> rasterizer_write_areas{}; | 867 | std::array<GPUDirtyState, Core::Hardware::NUM_CPU_CORES> rasterizer_write_areas{}; |
| 857 | std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers; | 868 | std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers; |
| 858 | std::mutex sys_core_guard; | 869 | std::mutex sys_core_guard; |
| 870 | |||
| 871 | std::optional<Common::HeapTracker> heap_tracker; | ||
| 872 | #ifdef __linux__ | ||
| 873 | Common::HeapTracker* buffer{}; | ||
| 874 | #else | ||
| 875 | Common::HostMemory* buffer{}; | ||
| 876 | #endif | ||
| 859 | }; | 877 | }; |
| 860 | 878 | ||
| 861 | Memory::Memory(Core::System& system_) : system{system_} { | 879 | Memory::Memory(Core::System& system_) : system{system_} { |
| @@ -873,12 +891,14 @@ void Memory::SetCurrentPageTable(Kernel::KProcess& process) { | |||
| 873 | } | 891 | } |
| 874 | 892 | ||
| 875 | void Memory::MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, | 893 | void Memory::MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, |
| 876 | Common::PhysicalAddress target, Common::MemoryPermission perms) { | 894 | Common::PhysicalAddress target, Common::MemoryPermission perms, |
| 877 | impl->MapMemoryRegion(page_table, base, size, target, perms); | 895 | bool separate_heap) { |
| 896 | impl->MapMemoryRegion(page_table, base, size, target, perms, separate_heap); | ||
| 878 | } | 897 | } |
| 879 | 898 | ||
| 880 | void Memory::UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size) { | 899 | void Memory::UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, |
| 881 | impl->UnmapRegion(page_table, base, size); | 900 | bool separate_heap) { |
| 901 | impl->UnmapRegion(page_table, base, size, separate_heap); | ||
| 882 | } | 902 | } |
| 883 | 903 | ||
| 884 | void Memory::ProtectRegion(Common::PageTable& page_table, Common::ProcessAddress vaddr, u64 size, | 904 | void Memory::ProtectRegion(Common::PageTable& page_table, Common::ProcessAddress vaddr, u64 size, |
| @@ -1048,7 +1068,9 @@ void Memory::FlushRegion(Common::ProcessAddress dest_addr, size_t size) { | |||
| 1048 | } | 1068 | } |
| 1049 | 1069 | ||
| 1050 | bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) { | 1070 | bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) { |
| 1051 | bool mapped = true; | 1071 | [[maybe_unused]] bool mapped = true; |
| 1072 | [[maybe_unused]] bool rasterizer = false; | ||
| 1073 | |||
| 1052 | u8* const ptr = impl->GetPointerImpl( | 1074 | u8* const ptr = impl->GetPointerImpl( |
| 1053 | GetInteger(vaddr), | 1075 | GetInteger(vaddr), |
| 1054 | [&] { | 1076 | [&] { |
| @@ -1056,8 +1078,26 @@ bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) { | |||
| 1056 | GetInteger(vaddr)); | 1078 | GetInteger(vaddr)); |
| 1057 | mapped = false; | 1079 | mapped = false; |
| 1058 | }, | 1080 | }, |
| 1059 | [&] { impl->system.GPU().InvalidateRegion(GetInteger(vaddr), size); }); | 1081 | [&] { |
| 1082 | impl->system.GPU().InvalidateRegion(GetInteger(vaddr), size); | ||
| 1083 | rasterizer = true; | ||
| 1084 | }); | ||
| 1085 | |||
| 1086 | #ifdef __linux__ | ||
| 1087 | if (!rasterizer && mapped) { | ||
| 1088 | impl->buffer->DeferredMapSeparateHeap(GetInteger(vaddr)); | ||
| 1089 | } | ||
| 1090 | #endif | ||
| 1091 | |||
| 1060 | return mapped && ptr != nullptr; | 1092 | return mapped && ptr != nullptr; |
| 1061 | } | 1093 | } |
| 1062 | 1094 | ||
| 1095 | bool Memory::InvalidateSeparateHeap(void* fault_address) { | ||
| 1096 | #ifdef __linux__ | ||
| 1097 | return impl->buffer->DeferredMapSeparateHeap(static_cast<u8*>(fault_address)); | ||
| 1098 | #else | ||
| 1099 | return false; | ||
| 1100 | #endif | ||
| 1101 | } | ||
| 1102 | |||
| 1063 | } // namespace Core::Memory | 1103 | } // namespace Core::Memory |
diff --git a/src/core/memory.h b/src/core/memory.h index c1879e78f..dddfaf4a4 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -86,7 +86,8 @@ public: | |||
| 86 | * @param perms The permissions to map the memory with. | 86 | * @param perms The permissions to map the memory with. |
| 87 | */ | 87 | */ |
| 88 | void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, | 88 | void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, |
| 89 | Common::PhysicalAddress target, Common::MemoryPermission perms); | 89 | Common::PhysicalAddress target, Common::MemoryPermission perms, |
| 90 | bool separate_heap); | ||
| 90 | 91 | ||
| 91 | /** | 92 | /** |
| 92 | * Unmaps a region of the emulated process address space. | 93 | * Unmaps a region of the emulated process address space. |
| @@ -95,7 +96,8 @@ public: | |||
| 95 | * @param base The address to begin unmapping at. | 96 | * @param base The address to begin unmapping at. |
| 96 | * @param size The amount of bytes to unmap. | 97 | * @param size The amount of bytes to unmap. |
| 97 | */ | 98 | */ |
| 98 | void UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size); | 99 | void UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, |
| 100 | bool separate_heap); | ||
| 99 | 101 | ||
| 100 | /** | 102 | /** |
| 101 | * Protects a region of the emulated process address space with the new permissions. | 103 | * Protects a region of the emulated process address space with the new permissions. |
| @@ -486,6 +488,7 @@ public: | |||
| 486 | void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers); | 488 | void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers); |
| 487 | void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size); | 489 | void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size); |
| 488 | bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size); | 490 | bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size); |
| 491 | bool InvalidateSeparateHeap(void* fault_address); | ||
| 489 | void FlushRegion(Common::ProcessAddress dest_addr, size_t size); | 492 | void FlushRegion(Common::ProcessAddress dest_addr, size_t size); |
| 490 | 493 | ||
| 491 | private: | 494 | private: |
| @@ -683,7 +686,8 @@ public: | |||
| 683 | } else { | 686 | } else { |
| 684 | this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes()); | 687 | this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes()); |
| 685 | } | 688 | } |
| 686 | } else if constexpr (FLAGS & GuestMemoryFlags::Safe) { | 689 | } else if constexpr ((FLAGS & GuestMemoryFlags::Safe) || |
| 690 | (FLAGS & GuestMemoryFlags::Cached)) { | ||
| 687 | this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes()); | 691 | this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes()); |
| 688 | } | 692 | } |
| 689 | } | 693 | } |
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index 3fc4024dc..7bc5b5ae5 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp | |||
| @@ -190,15 +190,15 @@ CheatEngine::CheatEngine(System& system_, std::vector<CheatEntry> cheats_, | |||
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | CheatEngine::~CheatEngine() { | 192 | CheatEngine::~CheatEngine() { |
| 193 | core_timing.UnscheduleEvent(event, 0); | 193 | core_timing.UnscheduleEvent(event); |
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | void CheatEngine::Initialize() { | 196 | void CheatEngine::Initialize() { |
| 197 | event = Core::Timing::CreateEvent( | 197 | event = Core::Timing::CreateEvent( |
| 198 | "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id), | 198 | "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id), |
| 199 | [this](std::uintptr_t user_data, s64 time, | 199 | [this](s64 time, |
| 200 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | 200 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { |
| 201 | FrameCallback(user_data, ns_late); | 201 | FrameCallback(ns_late); |
| 202 | return std::nullopt; | 202 | return std::nullopt; |
| 203 | }); | 203 | }); |
| 204 | core_timing.ScheduleLoopingEvent(CHEAT_ENGINE_NS, CHEAT_ENGINE_NS, event); | 204 | core_timing.ScheduleLoopingEvent(CHEAT_ENGINE_NS, CHEAT_ENGINE_NS, event); |
| @@ -239,7 +239,7 @@ void CheatEngine::Reload(std::vector<CheatEntry> reload_cheats) { | |||
| 239 | 239 | ||
| 240 | MICROPROFILE_DEFINE(Cheat_Engine, "Add-Ons", "Cheat Engine", MP_RGB(70, 200, 70)); | 240 | MICROPROFILE_DEFINE(Cheat_Engine, "Add-Ons", "Cheat Engine", MP_RGB(70, 200, 70)); |
| 241 | 241 | ||
| 242 | void CheatEngine::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) { | 242 | void CheatEngine::FrameCallback(std::chrono::nanoseconds ns_late) { |
| 243 | if (is_pending_reload.exchange(false)) { | 243 | if (is_pending_reload.exchange(false)) { |
| 244 | vm.LoadProgram(cheats); | 244 | vm.LoadProgram(cheats); |
| 245 | } | 245 | } |
diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h index 284abdd28..ced2168d1 100644 --- a/src/core/memory/cheat_engine.h +++ b/src/core/memory/cheat_engine.h | |||
| @@ -70,7 +70,7 @@ public: | |||
| 70 | void Reload(std::vector<CheatEntry> reload_cheats); | 70 | void Reload(std::vector<CheatEntry> reload_cheats); |
| 71 | 71 | ||
| 72 | private: | 72 | private: |
| 73 | void FrameCallback(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | 73 | void FrameCallback(std::chrono::nanoseconds ns_late); |
| 74 | 74 | ||
| 75 | DmntCheatVm vm; | 75 | DmntCheatVm vm; |
| 76 | CheatProcessMetadata metadata; | 76 | CheatProcessMetadata metadata; |
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp index 98ebbbf32..9d42c726e 100644 --- a/src/core/tools/freezer.cpp +++ b/src/core/tools/freezer.cpp | |||
| @@ -51,18 +51,17 @@ void MemoryWriteWidth(Core::Memory::Memory& memory, u32 width, VAddr addr, u64 v | |||
| 51 | 51 | ||
| 52 | Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_) | 52 | Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_) |
| 53 | : core_timing{core_timing_}, memory{memory_} { | 53 | : core_timing{core_timing_}, memory{memory_} { |
| 54 | event = Core::Timing::CreateEvent( | 54 | event = Core::Timing::CreateEvent("MemoryFreezer::FrameCallback", |
| 55 | "MemoryFreezer::FrameCallback", | 55 | [this](s64 time, std::chrono::nanoseconds ns_late) |
| 56 | [this](std::uintptr_t user_data, s64 time, | 56 | -> std::optional<std::chrono::nanoseconds> { |
| 57 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | 57 | FrameCallback(ns_late); |
| 58 | FrameCallback(user_data, ns_late); | 58 | return std::nullopt; |
| 59 | return std::nullopt; | 59 | }); |
| 60 | }); | ||
| 61 | core_timing.ScheduleEvent(memory_freezer_ns, event); | 60 | core_timing.ScheduleEvent(memory_freezer_ns, event); |
| 62 | } | 61 | } |
| 63 | 62 | ||
| 64 | Freezer::~Freezer() { | 63 | Freezer::~Freezer() { |
| 65 | core_timing.UnscheduleEvent(event, 0); | 64 | core_timing.UnscheduleEvent(event); |
| 66 | } | 65 | } |
| 67 | 66 | ||
| 68 | void Freezer::SetActive(bool is_active) { | 67 | void Freezer::SetActive(bool is_active) { |
| @@ -159,7 +158,7 @@ Freezer::Entries::const_iterator Freezer::FindEntry(VAddr address) const { | |||
| 159 | [address](const Entry& entry) { return entry.address == address; }); | 158 | [address](const Entry& entry) { return entry.address == address; }); |
| 160 | } | 159 | } |
| 161 | 160 | ||
| 162 | void Freezer::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) { | 161 | void Freezer::FrameCallback(std::chrono::nanoseconds ns_late) { |
| 163 | if (!IsActive()) { | 162 | if (!IsActive()) { |
| 164 | LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events."); | 163 | LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events."); |
| 165 | return; | 164 | return; |
diff --git a/src/core/tools/freezer.h b/src/core/tools/freezer.h index 0d6df5217..2efbc11f3 100644 --- a/src/core/tools/freezer.h +++ b/src/core/tools/freezer.h | |||
| @@ -77,7 +77,7 @@ private: | |||
| 77 | Entries::iterator FindEntry(VAddr address); | 77 | Entries::iterator FindEntry(VAddr address); |
| 78 | Entries::const_iterator FindEntry(VAddr address) const; | 78 | Entries::const_iterator FindEntry(VAddr address) const; |
| 79 | 79 | ||
| 80 | void FrameCallback(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | 80 | void FrameCallback(std::chrono::nanoseconds ns_late); |
| 81 | void FillEntryReads(); | 81 | void FillEntryReads(); |
| 82 | 82 | ||
| 83 | std::atomic_bool active{false}; | 83 | std::atomic_bool active{false}; |
diff --git a/src/frontend_common/config.cpp b/src/frontend_common/config.cpp index d9f99148b..51576b4ee 100644 --- a/src/frontend_common/config.cpp +++ b/src/frontend_common/config.cpp | |||
| @@ -403,59 +403,63 @@ void Config::SavePlayerValues(const std::size_t player_index) { | |||
| 403 | // No custom profile selected | 403 | // No custom profile selected |
| 404 | return; | 404 | return; |
| 405 | } | 405 | } |
| 406 | WriteSetting(std::string(player_prefix).append("profile_name"), player.profile_name, | 406 | WriteStringSetting(std::string(player_prefix).append("profile_name"), player.profile_name, |
| 407 | std::make_optional(std::string(""))); | 407 | std::make_optional(std::string(""))); |
| 408 | } | 408 | } |
| 409 | 409 | ||
| 410 | WriteSetting(std::string(player_prefix).append("type"), static_cast<u8>(player.controller_type), | 410 | WriteIntegerSetting( |
| 411 | std::make_optional(static_cast<u8>(Settings::ControllerType::ProController))); | 411 | std::string(player_prefix).append("type"), static_cast<u8>(player.controller_type), |
| 412 | std::make_optional(static_cast<u8>(Settings::ControllerType::ProController))); | ||
| 412 | 413 | ||
| 413 | if (!player_prefix.empty() || !Settings::IsConfiguringGlobal()) { | 414 | if (!player_prefix.empty() || !Settings::IsConfiguringGlobal()) { |
| 414 | WriteSetting(std::string(player_prefix).append("connected"), player.connected, | 415 | WriteBooleanSetting(std::string(player_prefix).append("connected"), player.connected, |
| 415 | std::make_optional(player_index == 0)); | 416 | std::make_optional(player_index == 0)); |
| 416 | WriteSetting(std::string(player_prefix).append("vibration_enabled"), | 417 | WriteIntegerSetting(std::string(player_prefix).append("vibration_enabled"), |
| 417 | player.vibration_enabled, std::make_optional(true)); | 418 | player.vibration_enabled, std::make_optional(true)); |
| 418 | WriteSetting(std::string(player_prefix).append("vibration_strength"), | 419 | WriteIntegerSetting(std::string(player_prefix).append("vibration_strength"), |
| 419 | player.vibration_strength, std::make_optional(100)); | 420 | player.vibration_strength, std::make_optional(100)); |
| 420 | WriteSetting(std::string(player_prefix).append("body_color_left"), player.body_color_left, | 421 | WriteIntegerSetting(std::string(player_prefix).append("body_color_left"), |
| 421 | std::make_optional(Settings::JOYCON_BODY_NEON_BLUE)); | 422 | player.body_color_left, |
| 422 | WriteSetting(std::string(player_prefix).append("body_color_right"), player.body_color_right, | 423 | std::make_optional(Settings::JOYCON_BODY_NEON_BLUE)); |
| 423 | std::make_optional(Settings::JOYCON_BODY_NEON_RED)); | 424 | WriteIntegerSetting(std::string(player_prefix).append("body_color_right"), |
| 424 | WriteSetting(std::string(player_prefix).append("button_color_left"), | 425 | player.body_color_right, |
| 425 | player.button_color_left, | 426 | std::make_optional(Settings::JOYCON_BODY_NEON_RED)); |
| 426 | std::make_optional(Settings::JOYCON_BUTTONS_NEON_BLUE)); | 427 | WriteIntegerSetting(std::string(player_prefix).append("button_color_left"), |
| 427 | WriteSetting(std::string(player_prefix).append("button_color_right"), | 428 | player.button_color_left, |
| 428 | player.button_color_right, | 429 | std::make_optional(Settings::JOYCON_BUTTONS_NEON_BLUE)); |
| 429 | std::make_optional(Settings::JOYCON_BUTTONS_NEON_RED)); | 430 | WriteIntegerSetting(std::string(player_prefix).append("button_color_right"), |
| 431 | player.button_color_right, | ||
| 432 | std::make_optional(Settings::JOYCON_BUTTONS_NEON_RED)); | ||
| 430 | } | 433 | } |
| 431 | } | 434 | } |
| 432 | 435 | ||
| 433 | void Config::SaveTouchscreenValues() { | 436 | void Config::SaveTouchscreenValues() { |
| 434 | const auto& touchscreen = Settings::values.touchscreen; | 437 | const auto& touchscreen = Settings::values.touchscreen; |
| 435 | 438 | ||
| 436 | WriteSetting(std::string("touchscreen_enabled"), touchscreen.enabled, std::make_optional(true)); | 439 | WriteBooleanSetting(std::string("touchscreen_enabled"), touchscreen.enabled, |
| 440 | std::make_optional(true)); | ||
| 437 | 441 | ||
| 438 | WriteSetting(std::string("touchscreen_angle"), touchscreen.rotation_angle, | 442 | WriteIntegerSetting(std::string("touchscreen_angle"), touchscreen.rotation_angle, |
| 439 | std::make_optional(static_cast<u32>(0))); | 443 | std::make_optional(static_cast<u32>(0))); |
| 440 | WriteSetting(std::string("touchscreen_diameter_x"), touchscreen.diameter_x, | 444 | WriteIntegerSetting(std::string("touchscreen_diameter_x"), touchscreen.diameter_x, |
| 441 | std::make_optional(static_cast<u32>(15))); | 445 | std::make_optional(static_cast<u32>(15))); |
| 442 | WriteSetting(std::string("touchscreen_diameter_y"), touchscreen.diameter_y, | 446 | WriteIntegerSetting(std::string("touchscreen_diameter_y"), touchscreen.diameter_y, |
| 443 | std::make_optional(static_cast<u32>(15))); | 447 | std::make_optional(static_cast<u32>(15))); |
| 444 | } | 448 | } |
| 445 | 449 | ||
| 446 | void Config::SaveMotionTouchValues() { | 450 | void Config::SaveMotionTouchValues() { |
| 447 | BeginArray(std::string("touch_from_button_maps")); | 451 | BeginArray(std::string("touch_from_button_maps")); |
| 448 | for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { | 452 | for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { |
| 449 | SetArrayIndex(static_cast<int>(p)); | 453 | SetArrayIndex(static_cast<int>(p)); |
| 450 | WriteSetting(std::string("name"), Settings::values.touch_from_button_maps[p].name, | 454 | WriteStringSetting(std::string("name"), Settings::values.touch_from_button_maps[p].name, |
| 451 | std::make_optional(std::string("default"))); | 455 | std::make_optional(std::string("default"))); |
| 452 | 456 | ||
| 453 | BeginArray(std::string("entries")); | 457 | BeginArray(std::string("entries")); |
| 454 | for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size(); | 458 | for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size(); |
| 455 | ++q) { | 459 | ++q) { |
| 456 | SetArrayIndex(static_cast<int>(q)); | 460 | SetArrayIndex(static_cast<int>(q)); |
| 457 | WriteSetting(std::string("bind"), | 461 | WriteStringSetting(std::string("bind"), |
| 458 | Settings::values.touch_from_button_maps[p].buttons[q]); | 462 | Settings::values.touch_from_button_maps[p].buttons[q]); |
| 459 | } | 463 | } |
| 460 | EndArray(); // entries | 464 | EndArray(); // entries |
| 461 | } | 465 | } |
| @@ -520,16 +524,16 @@ void Config::SaveCoreValues() { | |||
| 520 | void Config::SaveDataStorageValues() { | 524 | void Config::SaveDataStorageValues() { |
| 521 | BeginGroup(Settings::TranslateCategory(Settings::Category::DataStorage)); | 525 | BeginGroup(Settings::TranslateCategory(Settings::Category::DataStorage)); |
| 522 | 526 | ||
| 523 | WriteSetting(std::string("nand_directory"), FS::GetYuzuPathString(FS::YuzuPath::NANDDir), | 527 | WriteStringSetting(std::string("nand_directory"), FS::GetYuzuPathString(FS::YuzuPath::NANDDir), |
| 524 | std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); | 528 | std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); |
| 525 | WriteSetting(std::string("sdmc_directory"), FS::GetYuzuPathString(FS::YuzuPath::SDMCDir), | 529 | WriteStringSetting(std::string("sdmc_directory"), FS::GetYuzuPathString(FS::YuzuPath::SDMCDir), |
| 526 | std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))); | 530 | std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))); |
| 527 | WriteSetting(std::string("load_directory"), FS::GetYuzuPathString(FS::YuzuPath::LoadDir), | 531 | WriteStringSetting(std::string("load_directory"), FS::GetYuzuPathString(FS::YuzuPath::LoadDir), |
| 528 | std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::LoadDir))); | 532 | std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::LoadDir))); |
| 529 | WriteSetting(std::string("dump_directory"), FS::GetYuzuPathString(FS::YuzuPath::DumpDir), | 533 | WriteStringSetting(std::string("dump_directory"), FS::GetYuzuPathString(FS::YuzuPath::DumpDir), |
| 530 | std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); | 534 | std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); |
| 531 | WriteSetting(std::string("tas_directory"), FS::GetYuzuPathString(FS::YuzuPath::TASDir), | 535 | WriteStringSetting(std::string("tas_directory"), FS::GetYuzuPathString(FS::YuzuPath::TASDir), |
| 532 | std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::TASDir))); | 536 | std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::TASDir))); |
| 533 | 537 | ||
| 534 | WriteCategory(Settings::Category::DataStorage); | 538 | WriteCategory(Settings::Category::DataStorage); |
| 535 | 539 | ||
| @@ -540,7 +544,7 @@ void Config::SaveDebuggingValues() { | |||
| 540 | BeginGroup(Settings::TranslateCategory(Settings::Category::Debugging)); | 544 | BeginGroup(Settings::TranslateCategory(Settings::Category::Debugging)); |
| 541 | 545 | ||
| 542 | // Intentionally not using the QT default setting as this is intended to be changed in the ini | 546 | // Intentionally not using the QT default setting as this is intended to be changed in the ini |
| 543 | WriteSetting(std::string("record_frame_times"), Settings::values.record_frame_times); | 547 | WriteBooleanSetting(std::string("record_frame_times"), Settings::values.record_frame_times); |
| 544 | 548 | ||
| 545 | WriteCategory(Settings::Category::Debugging); | 549 | WriteCategory(Settings::Category::Debugging); |
| 546 | WriteCategory(Settings::Category::DebuggingGraphics); | 550 | WriteCategory(Settings::Category::DebuggingGraphics); |
| @@ -564,11 +568,13 @@ void Config::SaveDisabledAddOnValues() { | |||
| 564 | BeginArray(std::string("")); | 568 | BeginArray(std::string("")); |
| 565 | for (const auto& elem : Settings::values.disabled_addons) { | 569 | for (const auto& elem : Settings::values.disabled_addons) { |
| 566 | SetArrayIndex(i); | 570 | SetArrayIndex(i); |
| 567 | WriteSetting(std::string("title_id"), elem.first, std::make_optional(static_cast<u64>(0))); | 571 | WriteIntegerSetting(std::string("title_id"), elem.first, |
| 572 | std::make_optional(static_cast<u64>(0))); | ||
| 568 | BeginArray(std::string("disabled")); | 573 | BeginArray(std::string("disabled")); |
| 569 | for (std::size_t j = 0; j < elem.second.size(); ++j) { | 574 | for (std::size_t j = 0; j < elem.second.size(); ++j) { |
| 570 | SetArrayIndex(static_cast<int>(j)); | 575 | SetArrayIndex(static_cast<int>(j)); |
| 571 | WriteSetting(std::string("d"), elem.second[j], std::make_optional(std::string(""))); | 576 | WriteStringSetting(std::string("d"), elem.second[j], |
| 577 | std::make_optional(std::string(""))); | ||
| 572 | } | 578 | } |
| 573 | EndArray(); // disabled | 579 | EndArray(); // disabled |
| 574 | ++i; | 580 | ++i; |
| @@ -609,8 +615,8 @@ void Config::SaveRendererValues() { | |||
| 609 | void Config::SaveScreenshotValues() { | 615 | void Config::SaveScreenshotValues() { |
| 610 | BeginGroup(Settings::TranslateCategory(Settings::Category::Screenshots)); | 616 | BeginGroup(Settings::TranslateCategory(Settings::Category::Screenshots)); |
| 611 | 617 | ||
| 612 | WriteSetting(std::string("screenshot_path"), | 618 | WriteStringSetting(std::string("screenshot_path"), |
| 613 | FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir)); | 619 | FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir)); |
| 614 | WriteCategory(Settings::Category::Screenshots); | 620 | WriteCategory(Settings::Category::Screenshots); |
| 615 | 621 | ||
| 616 | EndGroup(); | 622 | EndGroup(); |
| @@ -746,46 +752,70 @@ bool Config::Exists(const std::string& section, const std::string& key) const { | |||
| 746 | return !value.empty(); | 752 | return !value.empty(); |
| 747 | } | 753 | } |
| 748 | 754 | ||
| 749 | template <typename Type> | 755 | void Config::WriteBooleanSetting(const std::string& key, const bool& value, |
| 750 | void Config::WriteSetting(const std::string& key, const Type& value, | 756 | const std::optional<bool>& default_value, |
| 751 | const std::optional<Type>& default_value, | 757 | const std::optional<bool>& use_global) { |
| 752 | const std::optional<bool>& use_global) { | 758 | std::optional<std::string> string_default = std::nullopt; |
| 753 | std::string full_key = GetFullKey(key, false); | 759 | if (default_value.has_value()) { |
| 760 | string_default = std::make_optional(ToString(default_value.value())); | ||
| 761 | } | ||
| 762 | WritePreparedSetting(key, AdjustOutputString(ToString(value)), string_default, use_global); | ||
| 763 | } | ||
| 754 | 764 | ||
| 755 | std::string saved_value; | 765 | template <typename T> |
| 756 | std::string string_default; | 766 | std::enable_if_t<std::is_integral_v<T>> Config::WriteIntegerSetting( |
| 757 | if constexpr (std::is_same_v<Type, std::string>) { | 767 | const std::string& key, const T& value, const std::optional<T>& default_value, |
| 758 | saved_value.append(AdjustOutputString(value)); | 768 | const std::optional<bool>& use_global) { |
| 759 | if (default_value.has_value()) { | 769 | std::optional<std::string> string_default = std::nullopt; |
| 760 | string_default.append(AdjustOutputString(default_value.value())); | 770 | if (default_value.has_value()) { |
| 761 | } | 771 | string_default = std::make_optional(ToString(default_value.value())); |
| 762 | } else { | 772 | } |
| 763 | saved_value.append(AdjustOutputString(ToString(value))); | 773 | WritePreparedSetting(key, AdjustOutputString(ToString(value)), string_default, use_global); |
| 764 | if (default_value.has_value()) { | 774 | } |
| 765 | string_default.append(ToString(default_value.value())); | 775 | |
| 766 | } | 776 | void Config::WriteDoubleSetting(const std::string& key, const double& value, |
| 777 | const std::optional<double>& default_value, | ||
| 778 | const std::optional<bool>& use_global) { | ||
| 779 | std::optional<std::string> string_default = std::nullopt; | ||
| 780 | if (default_value.has_value()) { | ||
| 781 | string_default = std::make_optional(ToString(default_value.value())); | ||
| 767 | } | 782 | } |
| 783 | WritePreparedSetting(key, AdjustOutputString(ToString(value)), string_default, use_global); | ||
| 784 | } | ||
| 768 | 785 | ||
| 769 | if (default_value.has_value() && use_global.has_value()) { | 786 | void Config::WriteStringSetting(const std::string& key, const std::string& value, |
| 787 | const std::optional<std::string>& default_value, | ||
| 788 | const std::optional<bool>& use_global) { | ||
| 789 | std::optional string_default = default_value; | ||
| 790 | if (default_value.has_value()) { | ||
| 791 | string_default.value().append(AdjustOutputString(default_value.value())); | ||
| 792 | } | ||
| 793 | WritePreparedSetting(key, AdjustOutputString(value), string_default, use_global); | ||
| 794 | } | ||
| 795 | |||
| 796 | void Config::WritePreparedSetting(const std::string& key, const std::string& adjusted_value, | ||
| 797 | const std::optional<std::string>& adjusted_default_value, | ||
| 798 | const std::optional<bool>& use_global) { | ||
| 799 | std::string full_key = GetFullKey(key, false); | ||
| 800 | if (adjusted_default_value.has_value() && use_global.has_value()) { | ||
| 770 | if (!global) { | 801 | if (!global) { |
| 771 | WriteSettingInternal(std::string(full_key).append("\\global"), | 802 | WriteString(std::string(full_key).append("\\global"), ToString(use_global.value())); |
| 772 | ToString(use_global.value())); | ||
| 773 | } | 803 | } |
| 774 | if (global || use_global.value() == false) { | 804 | if (global || use_global.value() == false) { |
| 775 | WriteSettingInternal(std::string(full_key).append("\\default"), | 805 | WriteString(std::string(full_key).append("\\default"), |
| 776 | ToString(string_default == saved_value)); | 806 | ToString(adjusted_default_value == adjusted_value)); |
| 777 | WriteSettingInternal(full_key, saved_value); | 807 | WriteString(full_key, adjusted_value); |
| 778 | } | 808 | } |
| 779 | } else if (default_value.has_value() && !use_global.has_value()) { | 809 | } else if (adjusted_default_value.has_value() && !use_global.has_value()) { |
| 780 | WriteSettingInternal(std::string(full_key).append("\\default"), | 810 | WriteString(std::string(full_key).append("\\default"), |
| 781 | ToString(string_default == saved_value)); | 811 | ToString(adjusted_default_value == adjusted_value)); |
| 782 | WriteSettingInternal(full_key, saved_value); | 812 | WriteString(full_key, adjusted_value); |
| 783 | } else { | 813 | } else { |
| 784 | WriteSettingInternal(full_key, saved_value); | 814 | WriteString(full_key, adjusted_value); |
| 785 | } | 815 | } |
| 786 | } | 816 | } |
| 787 | 817 | ||
| 788 | void Config::WriteSettingInternal(const std::string& key, const std::string& value) { | 818 | void Config::WriteString(const std::string& key, const std::string& value) { |
| 789 | config->SetValue(GetSection().c_str(), key.c_str(), value.c_str()); | 819 | config->SetValue(GetSection().c_str(), key.c_str(), value.c_str()); |
| 790 | } | 820 | } |
| 791 | 821 | ||
| @@ -861,17 +891,17 @@ void Config::WriteSettingGeneric(const Settings::BasicSetting* const setting) { | |||
| 861 | std::string key = AdjustKey(setting->GetLabel()); | 891 | std::string key = AdjustKey(setting->GetLabel()); |
| 862 | if (setting->Switchable()) { | 892 | if (setting->Switchable()) { |
| 863 | if (!global) { | 893 | if (!global) { |
| 864 | WriteSetting(std::string(key).append("\\use_global"), setting->UsingGlobal()); | 894 | WriteBooleanSetting(std::string(key).append("\\use_global"), setting->UsingGlobal()); |
| 865 | } | 895 | } |
| 866 | if (global || !setting->UsingGlobal()) { | 896 | if (global || !setting->UsingGlobal()) { |
| 867 | WriteSetting(std::string(key).append("\\default"), | 897 | WriteBooleanSetting(std::string(key).append("\\default"), |
| 868 | setting->ToString() == setting->DefaultToString()); | 898 | setting->ToString() == setting->DefaultToString()); |
| 869 | WriteSetting(key, setting->ToString()); | 899 | WriteStringSetting(key, setting->ToString()); |
| 870 | } | 900 | } |
| 871 | } else if (global) { | 901 | } else if (global) { |
| 872 | WriteSetting(std::string(key).append("\\default"), | 902 | WriteBooleanSetting(std::string(key).append("\\default"), |
| 873 | setting->ToString() == setting->DefaultToString()); | 903 | setting->ToString() == setting->DefaultToString()); |
| 874 | WriteSetting(key, setting->ToString()); | 904 | WriteStringSetting(key, setting->ToString()); |
| 875 | } | 905 | } |
| 876 | } | 906 | } |
| 877 | 907 | ||
diff --git a/src/frontend_common/config.h b/src/frontend_common/config.h index b3812af17..0c4d505b8 100644 --- a/src/frontend_common/config.h +++ b/src/frontend_common/config.h | |||
| @@ -154,11 +154,20 @@ protected: | |||
| 154 | * @param use_global Specifies if the custom or global config should be in use, for custom | 154 | * @param use_global Specifies if the custom or global config should be in use, for custom |
| 155 | * configs | 155 | * configs |
| 156 | */ | 156 | */ |
| 157 | template <typename Type = int> | 157 | void WriteBooleanSetting(const std::string& key, const bool& value, |
| 158 | void WriteSetting(const std::string& key, const Type& value, | 158 | const std::optional<bool>& default_value = std::nullopt, |
| 159 | const std::optional<Type>& default_value = std::nullopt, | 159 | const std::optional<bool>& use_global = std::nullopt); |
| 160 | const std::optional<bool>& use_global = std::nullopt); | 160 | template <typename T> |
| 161 | void WriteSettingInternal(const std::string& key, const std::string& value); | 161 | std::enable_if_t<std::is_integral_v<T>> WriteIntegerSetting( |
| 162 | const std::string& key, const T& value, | ||
| 163 | const std::optional<T>& default_value = std::nullopt, | ||
| 164 | const std::optional<bool>& use_global = std::nullopt); | ||
| 165 | void WriteDoubleSetting(const std::string& key, const double& value, | ||
| 166 | const std::optional<double>& default_value = std::nullopt, | ||
| 167 | const std::optional<bool>& use_global = std::nullopt); | ||
| 168 | void WriteStringSetting(const std::string& key, const std::string& value, | ||
| 169 | const std::optional<std::string>& default_value = std::nullopt, | ||
| 170 | const std::optional<bool>& use_global = std::nullopt); | ||
| 162 | 171 | ||
| 163 | void ReadCategory(Settings::Category category); | 172 | void ReadCategory(Settings::Category category); |
| 164 | void WriteCategory(Settings::Category category); | 173 | void WriteCategory(Settings::Category category); |
| @@ -175,8 +184,10 @@ protected: | |||
| 175 | return value_ ? "true" : "false"; | 184 | return value_ ? "true" : "false"; |
| 176 | } else if constexpr (std::is_same_v<T, u64>) { | 185 | } else if constexpr (std::is_same_v<T, u64>) { |
| 177 | return std::to_string(static_cast<u64>(value_)); | 186 | return std::to_string(static_cast<u64>(value_)); |
| 178 | } else { | 187 | } else if constexpr (std::is_same_v<T, s64>) { |
| 179 | return std::to_string(static_cast<s64>(value_)); | 188 | return std::to_string(static_cast<s64>(value_)); |
| 189 | } else { | ||
| 190 | return std::to_string(value_); | ||
| 180 | } | 191 | } |
| 181 | } | 192 | } |
| 182 | 193 | ||
| @@ -197,9 +208,13 @@ protected: | |||
| 197 | const bool global; | 208 | const bool global; |
| 198 | 209 | ||
| 199 | private: | 210 | private: |
| 200 | inline static std::array<char, 19> special_characters = {'!', '#', '$', '%', '^', '&', '*', | 211 | void WritePreparedSetting(const std::string& key, const std::string& adjusted_value, |
| 201 | '|', ';', '\'', '\"', ',', '<', '.', | 212 | const std::optional<std::string>& adjusted_default_value, |
| 202 | '>', '?', '`', '~', '='}; | 213 | const std::optional<bool>& use_global); |
| 214 | void WriteString(const std::string& key, const std::string& value); | ||
| 215 | |||
| 216 | inline static std::array<char, 18> special_characters = { | ||
| 217 | '!', '#', '$', '%', '^', '&', '*', '|', ';', '\'', '\"', ',', '<', '>', '?', '`', '~', '='}; | ||
| 203 | 218 | ||
| 204 | struct ConfigArray { | 219 | struct ConfigArray { |
| 205 | std::string name; | 220 | std::string name; |
diff --git a/src/tests/common/host_memory.cpp b/src/tests/common/host_memory.cpp index 1a28e862b..cb040c942 100644 --- a/src/tests/common/host_memory.cpp +++ b/src/tests/common/host_memory.cpp | |||
| @@ -12,6 +12,7 @@ using namespace Common::Literals; | |||
| 12 | static constexpr size_t VIRTUAL_SIZE = 1ULL << 39; | 12 | static constexpr size_t VIRTUAL_SIZE = 1ULL << 39; |
| 13 | static constexpr size_t BACKING_SIZE = 4_GiB; | 13 | static constexpr size_t BACKING_SIZE = 4_GiB; |
| 14 | static constexpr auto PERMS = Common::MemoryPermission::ReadWrite; | 14 | static constexpr auto PERMS = Common::MemoryPermission::ReadWrite; |
| 15 | static constexpr auto HEAP = false; | ||
| 15 | 16 | ||
| 16 | TEST_CASE("HostMemory: Initialize and deinitialize", "[common]") { | 17 | TEST_CASE("HostMemory: Initialize and deinitialize", "[common]") { |
| 17 | { HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); } | 18 | { HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); } |
| @@ -20,7 +21,7 @@ TEST_CASE("HostMemory: Initialize and deinitialize", "[common]") { | |||
| 20 | 21 | ||
| 21 | TEST_CASE("HostMemory: Simple map", "[common]") { | 22 | TEST_CASE("HostMemory: Simple map", "[common]") { |
| 22 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 23 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 23 | mem.Map(0x5000, 0x8000, 0x1000, PERMS); | 24 | mem.Map(0x5000, 0x8000, 0x1000, PERMS, HEAP); |
| 24 | 25 | ||
| 25 | volatile u8* const data = mem.VirtualBasePointer() + 0x5000; | 26 | volatile u8* const data = mem.VirtualBasePointer() + 0x5000; |
| 26 | data[0] = 50; | 27 | data[0] = 50; |
| @@ -29,8 +30,8 @@ TEST_CASE("HostMemory: Simple map", "[common]") { | |||
| 29 | 30 | ||
| 30 | TEST_CASE("HostMemory: Simple mirror map", "[common]") { | 31 | TEST_CASE("HostMemory: Simple mirror map", "[common]") { |
| 31 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 32 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 32 | mem.Map(0x5000, 0x3000, 0x2000, PERMS); | 33 | mem.Map(0x5000, 0x3000, 0x2000, PERMS, HEAP); |
| 33 | mem.Map(0x8000, 0x4000, 0x1000, PERMS); | 34 | mem.Map(0x8000, 0x4000, 0x1000, PERMS, HEAP); |
| 34 | 35 | ||
| 35 | volatile u8* const mirror_a = mem.VirtualBasePointer() + 0x5000; | 36 | volatile u8* const mirror_a = mem.VirtualBasePointer() + 0x5000; |
| 36 | volatile u8* const mirror_b = mem.VirtualBasePointer() + 0x8000; | 37 | volatile u8* const mirror_b = mem.VirtualBasePointer() + 0x8000; |
| @@ -40,116 +41,116 @@ TEST_CASE("HostMemory: Simple mirror map", "[common]") { | |||
| 40 | 41 | ||
| 41 | TEST_CASE("HostMemory: Simple unmap", "[common]") { | 42 | TEST_CASE("HostMemory: Simple unmap", "[common]") { |
| 42 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 43 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 43 | mem.Map(0x5000, 0x3000, 0x2000, PERMS); | 44 | mem.Map(0x5000, 0x3000, 0x2000, PERMS, HEAP); |
| 44 | 45 | ||
| 45 | volatile u8* const data = mem.VirtualBasePointer() + 0x5000; | 46 | volatile u8* const data = mem.VirtualBasePointer() + 0x5000; |
| 46 | data[75] = 50; | 47 | data[75] = 50; |
| 47 | REQUIRE(data[75] == 50); | 48 | REQUIRE(data[75] == 50); |
| 48 | 49 | ||
| 49 | mem.Unmap(0x5000, 0x2000); | 50 | mem.Unmap(0x5000, 0x2000, HEAP); |
| 50 | } | 51 | } |
| 51 | 52 | ||
| 52 | TEST_CASE("HostMemory: Simple unmap and remap", "[common]") { | 53 | TEST_CASE("HostMemory: Simple unmap and remap", "[common]") { |
| 53 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 54 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 54 | mem.Map(0x5000, 0x3000, 0x2000, PERMS); | 55 | mem.Map(0x5000, 0x3000, 0x2000, PERMS, HEAP); |
| 55 | 56 | ||
| 56 | volatile u8* const data = mem.VirtualBasePointer() + 0x5000; | 57 | volatile u8* const data = mem.VirtualBasePointer() + 0x5000; |
| 57 | data[0] = 50; | 58 | data[0] = 50; |
| 58 | REQUIRE(data[0] == 50); | 59 | REQUIRE(data[0] == 50); |
| 59 | 60 | ||
| 60 | mem.Unmap(0x5000, 0x2000); | 61 | mem.Unmap(0x5000, 0x2000, HEAP); |
| 61 | 62 | ||
| 62 | mem.Map(0x5000, 0x3000, 0x2000, PERMS); | 63 | mem.Map(0x5000, 0x3000, 0x2000, PERMS, HEAP); |
| 63 | REQUIRE(data[0] == 50); | 64 | REQUIRE(data[0] == 50); |
| 64 | 65 | ||
| 65 | mem.Map(0x7000, 0x2000, 0x5000, PERMS); | 66 | mem.Map(0x7000, 0x2000, 0x5000, PERMS, HEAP); |
| 66 | REQUIRE(data[0x3000] == 50); | 67 | REQUIRE(data[0x3000] == 50); |
| 67 | } | 68 | } |
| 68 | 69 | ||
| 69 | TEST_CASE("HostMemory: Nieche allocation", "[common]") { | 70 | TEST_CASE("HostMemory: Nieche allocation", "[common]") { |
| 70 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 71 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 71 | mem.Map(0x0000, 0, 0x20000, PERMS); | 72 | mem.Map(0x0000, 0, 0x20000, PERMS, HEAP); |
| 72 | mem.Unmap(0x0000, 0x4000); | 73 | mem.Unmap(0x0000, 0x4000, HEAP); |
| 73 | mem.Map(0x1000, 0, 0x2000, PERMS); | 74 | mem.Map(0x1000, 0, 0x2000, PERMS, HEAP); |
| 74 | mem.Map(0x3000, 0, 0x1000, PERMS); | 75 | mem.Map(0x3000, 0, 0x1000, PERMS, HEAP); |
| 75 | mem.Map(0, 0, 0x1000, PERMS); | 76 | mem.Map(0, 0, 0x1000, PERMS, HEAP); |
| 76 | } | 77 | } |
| 77 | 78 | ||
| 78 | TEST_CASE("HostMemory: Full unmap", "[common]") { | 79 | TEST_CASE("HostMemory: Full unmap", "[common]") { |
| 79 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 80 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 80 | mem.Map(0x8000, 0, 0x4000, PERMS); | 81 | mem.Map(0x8000, 0, 0x4000, PERMS, HEAP); |
| 81 | mem.Unmap(0x8000, 0x4000); | 82 | mem.Unmap(0x8000, 0x4000, HEAP); |
| 82 | mem.Map(0x6000, 0, 0x16000, PERMS); | 83 | mem.Map(0x6000, 0, 0x16000, PERMS, HEAP); |
| 83 | } | 84 | } |
| 84 | 85 | ||
| 85 | TEST_CASE("HostMemory: Right out of bounds unmap", "[common]") { | 86 | TEST_CASE("HostMemory: Right out of bounds unmap", "[common]") { |
| 86 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 87 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 87 | mem.Map(0x0000, 0, 0x4000, PERMS); | 88 | mem.Map(0x0000, 0, 0x4000, PERMS, HEAP); |
| 88 | mem.Unmap(0x2000, 0x4000); | 89 | mem.Unmap(0x2000, 0x4000, HEAP); |
| 89 | mem.Map(0x2000, 0x80000, 0x4000, PERMS); | 90 | mem.Map(0x2000, 0x80000, 0x4000, PERMS, HEAP); |
| 90 | } | 91 | } |
| 91 | 92 | ||
| 92 | TEST_CASE("HostMemory: Left out of bounds unmap", "[common]") { | 93 | TEST_CASE("HostMemory: Left out of bounds unmap", "[common]") { |
| 93 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 94 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 94 | mem.Map(0x8000, 0, 0x4000, PERMS); | 95 | mem.Map(0x8000, 0, 0x4000, PERMS, HEAP); |
| 95 | mem.Unmap(0x6000, 0x4000); | 96 | mem.Unmap(0x6000, 0x4000, HEAP); |
| 96 | mem.Map(0x8000, 0, 0x2000, PERMS); | 97 | mem.Map(0x8000, 0, 0x2000, PERMS, HEAP); |
| 97 | } | 98 | } |
| 98 | 99 | ||
| 99 | TEST_CASE("HostMemory: Multiple placeholder unmap", "[common]") { | 100 | TEST_CASE("HostMemory: Multiple placeholder unmap", "[common]") { |
| 100 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 101 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 101 | mem.Map(0x0000, 0, 0x4000, PERMS); | 102 | mem.Map(0x0000, 0, 0x4000, PERMS, HEAP); |
| 102 | mem.Map(0x4000, 0, 0x1b000, PERMS); | 103 | mem.Map(0x4000, 0, 0x1b000, PERMS, HEAP); |
| 103 | mem.Unmap(0x3000, 0x1c000); | 104 | mem.Unmap(0x3000, 0x1c000, HEAP); |
| 104 | mem.Map(0x3000, 0, 0x20000, PERMS); | 105 | mem.Map(0x3000, 0, 0x20000, PERMS, HEAP); |
| 105 | } | 106 | } |
| 106 | 107 | ||
| 107 | TEST_CASE("HostMemory: Unmap between placeholders", "[common]") { | 108 | TEST_CASE("HostMemory: Unmap between placeholders", "[common]") { |
| 108 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 109 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 109 | mem.Map(0x0000, 0, 0x4000, PERMS); | 110 | mem.Map(0x0000, 0, 0x4000, PERMS, HEAP); |
| 110 | mem.Map(0x4000, 0, 0x4000, PERMS); | 111 | mem.Map(0x4000, 0, 0x4000, PERMS, HEAP); |
| 111 | mem.Unmap(0x2000, 0x4000); | 112 | mem.Unmap(0x2000, 0x4000, HEAP); |
| 112 | mem.Map(0x2000, 0, 0x4000, PERMS); | 113 | mem.Map(0x2000, 0, 0x4000, PERMS, HEAP); |
| 113 | } | 114 | } |
| 114 | 115 | ||
| 115 | TEST_CASE("HostMemory: Unmap to origin", "[common]") { | 116 | TEST_CASE("HostMemory: Unmap to origin", "[common]") { |
| 116 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 117 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 117 | mem.Map(0x4000, 0, 0x4000, PERMS); | 118 | mem.Map(0x4000, 0, 0x4000, PERMS, HEAP); |
| 118 | mem.Map(0x8000, 0, 0x4000, PERMS); | 119 | mem.Map(0x8000, 0, 0x4000, PERMS, HEAP); |
| 119 | mem.Unmap(0x4000, 0x4000); | 120 | mem.Unmap(0x4000, 0x4000, HEAP); |
| 120 | mem.Map(0, 0, 0x4000, PERMS); | 121 | mem.Map(0, 0, 0x4000, PERMS, HEAP); |
| 121 | mem.Map(0x4000, 0, 0x4000, PERMS); | 122 | mem.Map(0x4000, 0, 0x4000, PERMS, HEAP); |
| 122 | } | 123 | } |
| 123 | 124 | ||
| 124 | TEST_CASE("HostMemory: Unmap to right", "[common]") { | 125 | TEST_CASE("HostMemory: Unmap to right", "[common]") { |
| 125 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 126 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 126 | mem.Map(0x4000, 0, 0x4000, PERMS); | 127 | mem.Map(0x4000, 0, 0x4000, PERMS, HEAP); |
| 127 | mem.Map(0x8000, 0, 0x4000, PERMS); | 128 | mem.Map(0x8000, 0, 0x4000, PERMS, HEAP); |
| 128 | mem.Unmap(0x8000, 0x4000); | 129 | mem.Unmap(0x8000, 0x4000, HEAP); |
| 129 | mem.Map(0x8000, 0, 0x4000, PERMS); | 130 | mem.Map(0x8000, 0, 0x4000, PERMS, HEAP); |
| 130 | } | 131 | } |
| 131 | 132 | ||
| 132 | TEST_CASE("HostMemory: Partial right unmap check bindings", "[common]") { | 133 | TEST_CASE("HostMemory: Partial right unmap check bindings", "[common]") { |
| 133 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 134 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 134 | mem.Map(0x4000, 0x10000, 0x4000, PERMS); | 135 | mem.Map(0x4000, 0x10000, 0x4000, PERMS, HEAP); |
| 135 | 136 | ||
| 136 | volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; | 137 | volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; |
| 137 | ptr[0x1000] = 17; | 138 | ptr[0x1000] = 17; |
| 138 | 139 | ||
| 139 | mem.Unmap(0x6000, 0x2000); | 140 | mem.Unmap(0x6000, 0x2000, HEAP); |
| 140 | 141 | ||
| 141 | REQUIRE(ptr[0x1000] == 17); | 142 | REQUIRE(ptr[0x1000] == 17); |
| 142 | } | 143 | } |
| 143 | 144 | ||
| 144 | TEST_CASE("HostMemory: Partial left unmap check bindings", "[common]") { | 145 | TEST_CASE("HostMemory: Partial left unmap check bindings", "[common]") { |
| 145 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 146 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 146 | mem.Map(0x4000, 0x10000, 0x4000, PERMS); | 147 | mem.Map(0x4000, 0x10000, 0x4000, PERMS, HEAP); |
| 147 | 148 | ||
| 148 | volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; | 149 | volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; |
| 149 | ptr[0x3000] = 19; | 150 | ptr[0x3000] = 19; |
| 150 | ptr[0x3fff] = 12; | 151 | ptr[0x3fff] = 12; |
| 151 | 152 | ||
| 152 | mem.Unmap(0x4000, 0x2000); | 153 | mem.Unmap(0x4000, 0x2000, HEAP); |
| 153 | 154 | ||
| 154 | REQUIRE(ptr[0x3000] == 19); | 155 | REQUIRE(ptr[0x3000] == 19); |
| 155 | REQUIRE(ptr[0x3fff] == 12); | 156 | REQUIRE(ptr[0x3fff] == 12); |
| @@ -157,13 +158,13 @@ TEST_CASE("HostMemory: Partial left unmap check bindings", "[common]") { | |||
| 157 | 158 | ||
| 158 | TEST_CASE("HostMemory: Partial middle unmap check bindings", "[common]") { | 159 | TEST_CASE("HostMemory: Partial middle unmap check bindings", "[common]") { |
| 159 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 160 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 160 | mem.Map(0x4000, 0x10000, 0x4000, PERMS); | 161 | mem.Map(0x4000, 0x10000, 0x4000, PERMS, HEAP); |
| 161 | 162 | ||
| 162 | volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; | 163 | volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; |
| 163 | ptr[0x0000] = 19; | 164 | ptr[0x0000] = 19; |
| 164 | ptr[0x3fff] = 12; | 165 | ptr[0x3fff] = 12; |
| 165 | 166 | ||
| 166 | mem.Unmap(0x1000, 0x2000); | 167 | mem.Unmap(0x1000, 0x2000, HEAP); |
| 167 | 168 | ||
| 168 | REQUIRE(ptr[0x0000] == 19); | 169 | REQUIRE(ptr[0x0000] == 19); |
| 169 | REQUIRE(ptr[0x3fff] == 12); | 170 | REQUIRE(ptr[0x3fff] == 12); |
| @@ -171,14 +172,14 @@ TEST_CASE("HostMemory: Partial middle unmap check bindings", "[common]") { | |||
| 171 | 172 | ||
| 172 | TEST_CASE("HostMemory: Partial sparse middle unmap and check bindings", "[common]") { | 173 | TEST_CASE("HostMemory: Partial sparse middle unmap and check bindings", "[common]") { |
| 173 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 174 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 174 | mem.Map(0x4000, 0x10000, 0x2000, PERMS); | 175 | mem.Map(0x4000, 0x10000, 0x2000, PERMS, HEAP); |
| 175 | mem.Map(0x6000, 0x20000, 0x2000, PERMS); | 176 | mem.Map(0x6000, 0x20000, 0x2000, PERMS, HEAP); |
| 176 | 177 | ||
| 177 | volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; | 178 | volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; |
| 178 | ptr[0x0000] = 19; | 179 | ptr[0x0000] = 19; |
| 179 | ptr[0x3fff] = 12; | 180 | ptr[0x3fff] = 12; |
| 180 | 181 | ||
| 181 | mem.Unmap(0x5000, 0x2000); | 182 | mem.Unmap(0x5000, 0x2000, HEAP); |
| 182 | 183 | ||
| 183 | REQUIRE(ptr[0x0000] == 19); | 184 | REQUIRE(ptr[0x0000] == 19); |
| 184 | REQUIRE(ptr[0x3fff] == 12); | 185 | REQUIRE(ptr[0x3fff] == 12); |
diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp index f08afbf9a..81898a1d3 100644 --- a/src/tests/core/core_timing.cpp +++ b/src/tests/core/core_timing.cpp | |||
| @@ -16,20 +16,16 @@ | |||
| 16 | 16 | ||
| 17 | namespace { | 17 | namespace { |
| 18 | // Numbers are chosen randomly to make sure the correct one is given. | 18 | // Numbers are chosen randomly to make sure the correct one is given. |
| 19 | constexpr std::array<u64, 5> CB_IDS{{42, 144, 93, 1026, UINT64_C(0xFFFF7FFFF7FFFF)}}; | ||
| 20 | constexpr std::array<u64, 5> calls_order{{2, 0, 1, 4, 3}}; | 19 | constexpr std::array<u64, 5> calls_order{{2, 0, 1, 4, 3}}; |
| 21 | std::array<s64, 5> delays{}; | 20 | std::array<s64, 5> delays{}; |
| 22 | 21 | std::bitset<5> callbacks_ran_flags; | |
| 23 | std::bitset<CB_IDS.size()> callbacks_ran_flags; | ||
| 24 | u64 expected_callback = 0; | 22 | u64 expected_callback = 0; |
| 25 | 23 | ||
| 26 | template <unsigned int IDX> | 24 | template <unsigned int IDX> |
| 27 | std::optional<std::chrono::nanoseconds> HostCallbackTemplate(std::uintptr_t user_data, s64 time, | 25 | std::optional<std::chrono::nanoseconds> HostCallbackTemplate(s64 time, |
| 28 | std::chrono::nanoseconds ns_late) { | 26 | std::chrono::nanoseconds ns_late) { |
| 29 | static_assert(IDX < CB_IDS.size(), "IDX out of range"); | 27 | static_assert(IDX < callbacks_ran_flags.size(), "IDX out of range"); |
| 30 | callbacks_ran_flags.set(IDX); | 28 | callbacks_ran_flags.set(IDX); |
| 31 | REQUIRE(CB_IDS[IDX] == user_data); | ||
| 32 | REQUIRE(CB_IDS[IDX] == CB_IDS[calls_order[expected_callback]]); | ||
| 33 | delays[IDX] = ns_late.count(); | 29 | delays[IDX] = ns_late.count(); |
| 34 | ++expected_callback; | 30 | ++expected_callback; |
| 35 | return std::nullopt; | 31 | return std::nullopt; |
| @@ -76,7 +72,7 @@ TEST_CASE("CoreTiming[BasicOrder]", "[core]") { | |||
| 76 | const u64 order = calls_order[i]; | 72 | const u64 order = calls_order[i]; |
| 77 | const auto future_ns = std::chrono::nanoseconds{static_cast<s64>(i * one_micro + 100)}; | 73 | const auto future_ns = std::chrono::nanoseconds{static_cast<s64>(i * one_micro + 100)}; |
| 78 | 74 | ||
| 79 | core_timing.ScheduleEvent(future_ns, events[order], CB_IDS[order]); | 75 | core_timing.ScheduleEvent(future_ns, events[order]); |
| 80 | } | 76 | } |
| 81 | /// test pause | 77 | /// test pause |
| 82 | REQUIRE(callbacks_ran_flags.none()); | 78 | REQUIRE(callbacks_ran_flags.none()); |
| @@ -118,7 +114,7 @@ TEST_CASE("CoreTiming[BasicOrderNoPausing]", "[core]") { | |||
| 118 | for (std::size_t i = 0; i < events.size(); i++) { | 114 | for (std::size_t i = 0; i < events.size(); i++) { |
| 119 | const u64 order = calls_order[i]; | 115 | const u64 order = calls_order[i]; |
| 120 | const auto future_ns = std::chrono::nanoseconds{static_cast<s64>(i * one_micro + 100)}; | 116 | const auto future_ns = std::chrono::nanoseconds{static_cast<s64>(i * one_micro + 100)}; |
| 121 | core_timing.ScheduleEvent(future_ns, events[order], CB_IDS[order]); | 117 | core_timing.ScheduleEvent(future_ns, events[order]); |
| 122 | } | 118 | } |
| 123 | 119 | ||
| 124 | const u64 end = core_timing.GetGlobalTimeNs().count(); | 120 | const u64 end = core_timing.GetGlobalTimeNs().count(); |
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index 422d4d859..56fbff306 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp | |||
| @@ -228,7 +228,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() { | |||
| 228 | 228 | ||
| 229 | Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer( | 229 | Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer( |
| 230 | memory_manager, src_operand.address, src_size, &read_buffer); | 230 | memory_manager, src_operand.address, src_size, &read_buffer); |
| 231 | Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite> | 231 | Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::UnsafeReadCachedWrite> |
| 232 | tmp_write_buffer(memory_manager, dst_operand.address, dst_size, &write_buffer); | 232 | tmp_write_buffer(memory_manager, dst_operand.address, dst_size, &write_buffer); |
| 233 | 233 | ||
| 234 | UnswizzleSubrect(tmp_write_buffer, tmp_read_buffer, bytes_per_pixel, width, height, depth, | 234 | UnswizzleSubrect(tmp_write_buffer, tmp_read_buffer, bytes_per_pixel, width, height, depth, |
| @@ -292,7 +292,7 @@ void MaxwellDMA::CopyPitchToBlockLinear() { | |||
| 292 | GPUVAddr dst_addr = regs.offset_out; | 292 | GPUVAddr dst_addr = regs.offset_out; |
| 293 | Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer( | 293 | Core::Memory::GpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead> tmp_read_buffer( |
| 294 | memory_manager, src_addr, src_size, &read_buffer); | 294 | memory_manager, src_addr, src_size, &read_buffer); |
| 295 | Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::SafeReadCachedWrite> | 295 | Core::Memory::GpuGuestMemoryScoped<u8, Core::Memory::GuestMemoryFlags::UnsafeReadCachedWrite> |
| 296 | tmp_write_buffer(memory_manager, dst_addr, dst_size, &write_buffer); | 296 | tmp_write_buffer(memory_manager, dst_addr, dst_size, &write_buffer); |
| 297 | 297 | ||
| 298 | // If the input is linear and the output is tiled, swizzle the input and copy it over. | 298 | // If the input is linear and the output is tiled, swizzle the input and copy it over. |
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp index 5e7518d96..792ed9615 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp | |||
| @@ -329,7 +329,7 @@ void PresentManager::CopyToSwapchainImpl(Frame* frame) { | |||
| 329 | // to account for that. | 329 | // to account for that. |
| 330 | const bool is_suboptimal = swapchain.NeedsRecreation(); | 330 | const bool is_suboptimal = swapchain.NeedsRecreation(); |
| 331 | const bool size_changed = | 331 | const bool size_changed = |
| 332 | swapchain.GetWidth() != frame->width || swapchain.GetHeight() != frame->height; | 332 | swapchain.GetWidth() < frame->width || swapchain.GetHeight() < frame->height; |
| 333 | if (is_suboptimal || size_changed) { | 333 | if (is_suboptimal || size_changed) { |
| 334 | RecreateSwapchain(frame); | 334 | RecreateSwapchain(frame); |
| 335 | } | 335 | } |
diff --git a/src/yuzu/configuration/qt_config.cpp b/src/yuzu/configuration/qt_config.cpp index a71000b72..6aca71d7c 100644 --- a/src/yuzu/configuration/qt_config.cpp +++ b/src/yuzu/configuration/qt_config.cpp | |||
| @@ -348,43 +348,45 @@ void QtConfig::SaveQtPlayerValues(const std::size_t player_index) { | |||
| 348 | 348 | ||
| 349 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | 349 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { |
| 350 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | 350 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); |
| 351 | WriteSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]), | 351 | WriteStringSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]), |
| 352 | player.buttons[i], std::make_optional(default_param)); | 352 | player.buttons[i], std::make_optional(default_param)); |
| 353 | } | 353 | } |
| 354 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | 354 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { |
| 355 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | 355 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( |
| 356 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | 356 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], |
| 357 | default_analogs[i][3], default_stick_mod[i], 0.5f); | 357 | default_analogs[i][3], default_stick_mod[i], 0.5f); |
| 358 | WriteSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), | 358 | WriteStringSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), |
| 359 | player.analogs[i], std::make_optional(default_param)); | 359 | player.analogs[i], std::make_optional(default_param)); |
| 360 | } | 360 | } |
| 361 | for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { | 361 | for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { |
| 362 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); | 362 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); |
| 363 | WriteSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), | 363 | WriteStringSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), |
| 364 | player.motions[i], std::make_optional(default_param)); | 364 | player.motions[i], std::make_optional(default_param)); |
| 365 | } | 365 | } |
| 366 | } | 366 | } |
| 367 | 367 | ||
| 368 | void QtConfig::SaveDebugControlValues() { | 368 | void QtConfig::SaveDebugControlValues() { |
| 369 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | 369 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { |
| 370 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | 370 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); |
| 371 | WriteSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), | 371 | WriteStringSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), |
| 372 | Settings::values.debug_pad_buttons[i], std::make_optional(default_param)); | 372 | Settings::values.debug_pad_buttons[i], |
| 373 | std::make_optional(default_param)); | ||
| 373 | } | 374 | } |
| 374 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | 375 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { |
| 375 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | 376 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( |
| 376 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | 377 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], |
| 377 | default_analogs[i][3], default_stick_mod[i], 0.5f); | 378 | default_analogs[i][3], default_stick_mod[i], 0.5f); |
| 378 | WriteSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), | 379 | WriteStringSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), |
| 379 | Settings::values.debug_pad_analogs[i], std::make_optional(default_param)); | 380 | Settings::values.debug_pad_analogs[i], |
| 381 | std::make_optional(default_param)); | ||
| 380 | } | 382 | } |
| 381 | } | 383 | } |
| 382 | 384 | ||
| 383 | void QtConfig::SaveHidbusValues() { | 385 | void QtConfig::SaveHidbusValues() { |
| 384 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | 386 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( |
| 385 | 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); | 387 | 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); |
| 386 | WriteSetting(std::string("ring_controller"), Settings::values.ringcon_analogs, | 388 | WriteStringSetting(std::string("ring_controller"), Settings::values.ringcon_analogs, |
| 387 | std::make_optional(default_param)); | 389 | std::make_optional(default_param)); |
| 388 | } | 390 | } |
| 389 | 391 | ||
| 390 | void QtConfig::SaveQtControlValues() { | 392 | void QtConfig::SaveQtControlValues() { |
| @@ -409,19 +411,20 @@ void QtConfig::SavePathValues() { | |||
| 409 | 411 | ||
| 410 | WriteCategory(Settings::Category::Paths); | 412 | WriteCategory(Settings::Category::Paths); |
| 411 | 413 | ||
| 412 | WriteSetting(std::string("romsPath"), UISettings::values.roms_path); | 414 | WriteStringSetting(std::string("romsPath"), UISettings::values.roms_path); |
| 413 | BeginArray(std::string("gamedirs")); | 415 | BeginArray(std::string("gamedirs")); |
| 414 | for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) { | 416 | for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) { |
| 415 | SetArrayIndex(i); | 417 | SetArrayIndex(i); |
| 416 | const auto& game_dir = UISettings::values.game_dirs[i]; | 418 | const auto& game_dir = UISettings::values.game_dirs[i]; |
| 417 | WriteSetting(std::string("path"), game_dir.path); | 419 | WriteStringSetting(std::string("path"), game_dir.path); |
| 418 | WriteSetting(std::string("deep_scan"), game_dir.deep_scan, std::make_optional(false)); | 420 | WriteBooleanSetting(std::string("deep_scan"), game_dir.deep_scan, |
| 419 | WriteSetting(std::string("expanded"), game_dir.expanded, std::make_optional(true)); | 421 | std::make_optional(false)); |
| 422 | WriteBooleanSetting(std::string("expanded"), game_dir.expanded, std::make_optional(true)); | ||
| 420 | } | 423 | } |
| 421 | EndArray(); | 424 | EndArray(); |
| 422 | 425 | ||
| 423 | WriteSetting(std::string("recentFiles"), | 426 | WriteStringSetting(std::string("recentFiles"), |
| 424 | UISettings::values.recent_files.join(QStringLiteral(", ")).toStdString()); | 427 | UISettings::values.recent_files.join(QStringLiteral(", ")).toStdString()); |
| 425 | 428 | ||
| 426 | EndGroup(); | 429 | EndGroup(); |
| 427 | } | 430 | } |
| @@ -438,14 +441,14 @@ void QtConfig::SaveShortcutValues() { | |||
| 438 | BeginGroup(group); | 441 | BeginGroup(group); |
| 439 | BeginGroup(name); | 442 | BeginGroup(name); |
| 440 | 443 | ||
| 441 | WriteSetting(std::string("KeySeq"), shortcut.keyseq, | 444 | WriteStringSetting(std::string("KeySeq"), shortcut.keyseq, |
| 442 | std::make_optional(default_hotkey.keyseq)); | 445 | std::make_optional(default_hotkey.keyseq)); |
| 443 | WriteSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq, | 446 | WriteStringSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq, |
| 444 | std::make_optional(default_hotkey.controller_keyseq)); | 447 | std::make_optional(default_hotkey.controller_keyseq)); |
| 445 | WriteSetting(std::string("Context"), shortcut.context, | 448 | WriteIntegerSetting(std::string("Context"), shortcut.context, |
| 446 | std::make_optional(default_hotkey.context)); | 449 | std::make_optional(default_hotkey.context)); |
| 447 | WriteSetting(std::string("Repeat"), shortcut.repeat, | 450 | WriteBooleanSetting(std::string("Repeat"), shortcut.repeat, |
| 448 | std::make_optional(default_hotkey.repeat)); | 451 | std::make_optional(default_hotkey.repeat)); |
| 449 | 452 | ||
| 450 | EndGroup(); // name | 453 | EndGroup(); // name |
| 451 | EndGroup(); // group | 454 | EndGroup(); // group |
| @@ -460,9 +463,10 @@ void QtConfig::SaveUIValues() { | |||
| 460 | WriteCategory(Settings::Category::Ui); | 463 | WriteCategory(Settings::Category::Ui); |
| 461 | WriteCategory(Settings::Category::UiGeneral); | 464 | WriteCategory(Settings::Category::UiGeneral); |
| 462 | 465 | ||
| 463 | WriteSetting(std::string("theme"), UISettings::values.theme, | 466 | WriteStringSetting( |
| 464 | std::make_optional(std::string( | 467 | std::string("theme"), UISettings::values.theme, |
| 465 | UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second))); | 468 | std::make_optional(std::string( |
| 469 | UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second))); | ||
| 466 | 470 | ||
| 467 | SaveUIGamelistValues(); | 471 | SaveUIGamelistValues(); |
| 468 | SaveUILayoutValues(); | 472 | SaveUILayoutValues(); |
| @@ -482,7 +486,7 @@ void QtConfig::SaveUIGamelistValues() { | |||
| 482 | BeginArray(std::string("favorites")); | 486 | BeginArray(std::string("favorites")); |
| 483 | for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) { | 487 | for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) { |
| 484 | SetArrayIndex(i); | 488 | SetArrayIndex(i); |
| 485 | WriteSetting(std::string("program_id"), UISettings::values.favorited_ids[i]); | 489 | WriteIntegerSetting(std::string("program_id"), UISettings::values.favorited_ids[i]); |
| 486 | } | 490 | } |
| 487 | EndArray(); // favorites | 491 | EndArray(); // favorites |
| 488 | 492 | ||
| @@ -506,14 +510,15 @@ void QtConfig::SaveMultiplayerValues() { | |||
| 506 | BeginArray(std::string("username_ban_list")); | 510 | BeginArray(std::string("username_ban_list")); |
| 507 | for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.first.size(); ++i) { | 511 | for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.first.size(); ++i) { |
| 508 | SetArrayIndex(static_cast<int>(i)); | 512 | SetArrayIndex(static_cast<int>(i)); |
| 509 | WriteSetting(std::string("username"), UISettings::values.multiplayer_ban_list.first[i]); | 513 | WriteStringSetting(std::string("username"), |
| 514 | UISettings::values.multiplayer_ban_list.first[i]); | ||
| 510 | } | 515 | } |
| 511 | EndArray(); // username_ban_list | 516 | EndArray(); // username_ban_list |
| 512 | 517 | ||
| 513 | BeginArray(std::string("ip_ban_list")); | 518 | BeginArray(std::string("ip_ban_list")); |
| 514 | for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.second.size(); ++i) { | 519 | for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.second.size(); ++i) { |
| 515 | SetArrayIndex(static_cast<int>(i)); | 520 | SetArrayIndex(static_cast<int>(i)); |
| 516 | WriteSetting(std::string("ip"), UISettings::values.multiplayer_ban_list.second[i]); | 521 | WriteStringSetting(std::string("ip"), UISettings::values.multiplayer_ban_list.second[i]); |
| 517 | } | 522 | } |
| 518 | EndArray(); // ip_ban_list | 523 | EndArray(); // ip_ban_list |
| 519 | 524 | ||
diff --git a/src/yuzu_cmd/sdl_config.cpp b/src/yuzu_cmd/sdl_config.cpp index 39fd8050c..e81bf5d45 100644 --- a/src/yuzu_cmd/sdl_config.cpp +++ b/src/yuzu_cmd/sdl_config.cpp | |||
| @@ -213,43 +213,45 @@ void SdlConfig::SaveSdlPlayerValues(const std::size_t player_index) { | |||
| 213 | 213 | ||
| 214 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | 214 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { |
| 215 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | 215 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); |
| 216 | WriteSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]), | 216 | WriteStringSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]), |
| 217 | player.buttons[i], std::make_optional(default_param)); | 217 | player.buttons[i], std::make_optional(default_param)); |
| 218 | } | 218 | } |
| 219 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | 219 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { |
| 220 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | 220 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( |
| 221 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | 221 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], |
| 222 | default_analogs[i][3], default_stick_mod[i], 0.5f); | 222 | default_analogs[i][3], default_stick_mod[i], 0.5f); |
| 223 | WriteSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), | 223 | WriteStringSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), |
| 224 | player.analogs[i], std::make_optional(default_param)); | 224 | player.analogs[i], std::make_optional(default_param)); |
| 225 | } | 225 | } |
| 226 | for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { | 226 | for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { |
| 227 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); | 227 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); |
| 228 | WriteSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), | 228 | WriteStringSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), |
| 229 | player.motions[i], std::make_optional(default_param)); | 229 | player.motions[i], std::make_optional(default_param)); |
| 230 | } | 230 | } |
| 231 | } | 231 | } |
| 232 | 232 | ||
| 233 | void SdlConfig::SaveDebugControlValues() { | 233 | void SdlConfig::SaveDebugControlValues() { |
| 234 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | 234 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { |
| 235 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); | 235 | const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); |
| 236 | WriteSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), | 236 | WriteStringSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), |
| 237 | Settings::values.debug_pad_buttons[i], std::make_optional(default_param)); | 237 | Settings::values.debug_pad_buttons[i], |
| 238 | std::make_optional(default_param)); | ||
| 238 | } | 239 | } |
| 239 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | 240 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { |
| 240 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | 241 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( |
| 241 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], | 242 | default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], |
| 242 | default_analogs[i][3], default_stick_mod[i], 0.5f); | 243 | default_analogs[i][3], default_stick_mod[i], 0.5f); |
| 243 | WriteSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), | 244 | WriteStringSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), |
| 244 | Settings::values.debug_pad_analogs[i], std::make_optional(default_param)); | 245 | Settings::values.debug_pad_analogs[i], |
| 246 | std::make_optional(default_param)); | ||
| 245 | } | 247 | } |
| 246 | } | 248 | } |
| 247 | 249 | ||
| 248 | void SdlConfig::SaveHidbusValues() { | 250 | void SdlConfig::SaveHidbusValues() { |
| 249 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( | 251 | const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( |
| 250 | 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); | 252 | 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); |
| 251 | WriteSetting(std::string("ring_controller"), Settings::values.ringcon_analogs, | 253 | WriteStringSetting(std::string("ring_controller"), Settings::values.ringcon_analogs, |
| 252 | std::make_optional(default_param)); | 254 | std::make_optional(default_param)); |
| 253 | } | 255 | } |
| 254 | 256 | ||
| 255 | std::vector<Settings::BasicSetting*>& SdlConfig::FindRelevantList(Settings::Category category) { | 257 | std::vector<Settings::BasicSetting*>& SdlConfig::FindRelevantList(Settings::Category category) { |