diff options
Diffstat (limited to 'src')
223 files changed, 7289 insertions, 3004 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 21e4e1afd..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 | |||
| @@ -18,7 +18,12 @@ enum class IntSetting(override val key: String) : AbstractIntSetting { | |||
| 18 | RENDERER_ANTI_ALIASING("anti_aliasing"), | 18 | RENDERER_ANTI_ALIASING("anti_aliasing"), |
| 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"), | ||
| 23 | THEME("theme"), | ||
| 24 | THEME_MODE("theme_mode"), | ||
| 25 | OVERLAY_SCALE("control_scale"), | ||
| 26 | OVERLAY_OPACITY("control_opacity"); | ||
| 22 | 27 | ||
| 23 | override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal) | 28 | override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal) |
| 24 | 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..fee80bb21 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,7 +64,33 @@ object Settings { | |||
| 83 | PREF_BUTTON_STICK_R | 64 | PREF_BUTTON_STICK_R |
| 84 | ) | 65 | ) |
| 85 | 66 | ||
| 86 | const val LayoutOption_Unspecified = 0 | 67 | // Deprecated layout preference keys |
| 87 | const val LayoutOption_MobilePortrait = 4 | 68 | const val PREF_LANDSCAPE_SUFFIX = "_Landscape" |
| 88 | const val LayoutOption_MobileLandscape = 5 | 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 | |||
| 82 | enum class EmulationOrientation(val int: Int) { | ||
| 83 | Unspecified(0), | ||
| 84 | SensorLandscape(5), | ||
| 85 | Landscape(1), | ||
| 86 | ReverseLandscape(2), | ||
| 87 | SensorPortrait(6), | ||
| 88 | Portrait(4), | ||
| 89 | ReversePortrait(3); | ||
| 90 | |||
| 91 | companion object { | ||
| 92 | fun from(int: Int): EmulationOrientation = | ||
| 93 | entries.firstOrNull { it.int == int } ?: Unspecified | ||
| 94 | } | ||
| 95 | } | ||
| 89 | } | 96 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 2e97aee2c..12f7aa1ab 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt | |||
| @@ -245,6 +245,15 @@ abstract class SettingsItem( | |||
| 245 | ) | 245 | ) |
| 246 | put( | 246 | put( |
| 247 | SingleChoiceSetting( | 247 | SingleChoiceSetting( |
| 248 | IntSetting.MAX_ANISOTROPY, | ||
| 249 | R.string.anisotropic_filtering, | ||
| 250 | R.string.anisotropic_filtering_description, | ||
| 251 | R.array.anisoEntries, | ||
| 252 | R.array.anisoValues | ||
| 253 | ) | ||
| 254 | ) | ||
| 255 | put( | ||
| 256 | SingleChoiceSetting( | ||
| 248 | IntSetting.AUDIO_OUTPUT_ENGINE, | 257 | IntSetting.AUDIO_OUTPUT_ENGINE, |
| 249 | R.string.audio_output_engine, | 258 | R.string.audio_output_engine, |
| 250 | 0, | 259 | 0, |
| @@ -298,6 +307,7 @@ abstract class SettingsItem( | |||
| 298 | 307 | ||
| 299 | override val key: String = FASTMEM_COMBINED | 308 | override val key: String = FASTMEM_COMBINED |
| 300 | override val isRuntimeModifiable: Boolean = false | 309 | override val isRuntimeModifiable: Boolean = false |
| 310 | override val pairedSettingKey = BooleanSetting.CPU_DEBUG_MODE.key | ||
| 301 | override val defaultValue: Boolean = true | 311 | override val defaultValue: Boolean = true |
| 302 | override val isSwitchable: Boolean = true | 312 | override val isSwitchable: Boolean = true |
| 303 | override var global: Boolean | 313 | override var global: Boolean |
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 a7e965589..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]!! |
| @@ -149,6 +144,7 @@ class SettingsFragmentPresenter( | |||
| 149 | add(IntSetting.RENDERER_VSYNC.key) | 144 | add(IntSetting.RENDERER_VSYNC.key) |
| 150 | add(IntSetting.RENDERER_SCALING_FILTER.key) | 145 | add(IntSetting.RENDERER_SCALING_FILTER.key) |
| 151 | add(IntSetting.RENDERER_ANTI_ALIASING.key) | 146 | add(IntSetting.RENDERER_ANTI_ALIASING.key) |
| 147 | add(IntSetting.MAX_ANISOTROPY.key) | ||
| 152 | add(IntSetting.RENDERER_SCREEN_LAYOUT.key) | 148 | add(IntSetting.RENDERER_SCREEN_LAYOUT.key) |
| 153 | add(IntSetting.RENDERER_ASPECT_RATIO.key) | 149 | add(IntSetting.RENDERER_ASPECT_RATIO.key) |
| 154 | add(BooleanSetting.PICTURE_IN_PICTURE.key) | 150 | add(BooleanSetting.PICTURE_IN_PICTURE.key) |
| @@ -169,25 +165,19 @@ class SettingsFragmentPresenter( | |||
| 169 | private fun addThemeSettings(sl: ArrayList<SettingsItem>) { | 165 | private fun addThemeSettings(sl: ArrayList<SettingsItem>) { |
| 170 | sl.apply { | 166 | sl.apply { |
| 171 | val theme: AbstractIntSetting = object : AbstractIntSetting { | 167 | val theme: AbstractIntSetting = object : AbstractIntSetting { |
| 172 | override fun getInt(needsGlobal: Boolean): Int = | 168 | override fun getInt(needsGlobal: Boolean): Int = IntSetting.THEME.getInt() |
| 173 | preferences.getInt(Settings.PREF_THEME, 0) | ||
| 174 | |||
| 175 | override fun setInt(value: Int) { | 169 | override fun setInt(value: Int) { |
| 176 | preferences.edit() | 170 | IntSetting.THEME.setInt(value) |
| 177 | .putInt(Settings.PREF_THEME, value) | ||
| 178 | .apply() | ||
| 179 | settingsViewModel.setShouldRecreate(true) | 171 | settingsViewModel.setShouldRecreate(true) |
| 180 | } | 172 | } |
| 181 | 173 | ||
| 182 | override val key: String = Settings.PREF_THEME | 174 | override val key: String = IntSetting.THEME.key |
| 183 | override val isRuntimeModifiable: Boolean = false | 175 | override val isRuntimeModifiable: Boolean = IntSetting.THEME.isRuntimeModifiable |
| 184 | override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString() | 176 | override fun getValueAsString(needsGlobal: Boolean): String = |
| 185 | override val defaultValue: Int = 0 | 177 | IntSetting.THEME.getValueAsString() |
| 186 | override fun reset() { | 178 | |
| 187 | preferences.edit() | 179 | override val defaultValue: Int = IntSetting.THEME.defaultValue |
| 188 | .putInt(Settings.PREF_THEME, defaultValue) | 180 | override fun reset() = IntSetting.THEME.setInt(defaultValue) |
| 189 | .apply() | ||
| 190 | } | ||
| 191 | } | 181 | } |
| 192 | 182 | ||
| 193 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { | 183 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { |
| @@ -213,24 +203,22 @@ class SettingsFragmentPresenter( | |||
| 213 | } | 203 | } |
| 214 | 204 | ||
| 215 | val themeMode: AbstractIntSetting = object : AbstractIntSetting { | 205 | val themeMode: AbstractIntSetting = object : AbstractIntSetting { |
| 216 | override fun getInt(needsGlobal: Boolean): Int = | 206 | override fun getInt(needsGlobal: Boolean): Int = IntSetting.THEME_MODE.getInt() |
| 217 | preferences.getInt(Settings.PREF_THEME_MODE, -1) | ||
| 218 | |||
| 219 | override fun setInt(value: Int) { | 207 | override fun setInt(value: Int) { |
| 220 | preferences.edit() | 208 | IntSetting.THEME_MODE.setInt(value) |
| 221 | .putInt(Settings.PREF_THEME_MODE, value) | ||
| 222 | .apply() | ||
| 223 | settingsViewModel.setShouldRecreate(true) | 209 | settingsViewModel.setShouldRecreate(true) |
| 224 | } | 210 | } |
| 225 | 211 | ||
| 226 | override val key: String = Settings.PREF_THEME_MODE | 212 | override val key: String = IntSetting.THEME_MODE.key |
| 227 | override val isRuntimeModifiable: Boolean = false | 213 | override val isRuntimeModifiable: Boolean = |
| 228 | override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString() | 214 | IntSetting.THEME_MODE.isRuntimeModifiable |
| 229 | 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 | ||
| 230 | override fun reset() { | 220 | override fun reset() { |
| 231 | preferences.edit() | 221 | IntSetting.THEME_MODE.setInt(defaultValue) |
| 232 | .putInt(Settings.PREF_BLACK_BACKGROUNDS, defaultValue) | ||
| 233 | .apply() | ||
| 234 | settingsViewModel.setShouldRecreate(true) | 222 | settingsViewModel.setShouldRecreate(true) |
| 235 | } | 223 | } |
| 236 | } | 224 | } |
| @@ -247,25 +235,24 @@ class SettingsFragmentPresenter( | |||
| 247 | 235 | ||
| 248 | val blackBackgrounds: AbstractBooleanSetting = object : AbstractBooleanSetting { | 236 | val blackBackgrounds: AbstractBooleanSetting = object : AbstractBooleanSetting { |
| 249 | override fun getBoolean(needsGlobal: Boolean): Boolean = | 237 | override fun getBoolean(needsGlobal: Boolean): Boolean = |
| 250 | preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false) | 238 | BooleanSetting.BLACK_BACKGROUNDS.getBoolean() |
| 251 | 239 | ||
| 252 | override fun setBoolean(value: Boolean) { | 240 | override fun setBoolean(value: Boolean) { |
| 253 | preferences.edit() | 241 | BooleanSetting.BLACK_BACKGROUNDS.setBoolean(value) |
| 254 | .putBoolean(Settings.PREF_BLACK_BACKGROUNDS, value) | ||
| 255 | .apply() | ||
| 256 | settingsViewModel.setShouldRecreate(true) | 242 | settingsViewModel.setShouldRecreate(true) |
| 257 | } | 243 | } |
| 258 | 244 | ||
| 259 | override val key: String = Settings.PREF_BLACK_BACKGROUNDS | 245 | override val key: String = BooleanSetting.BLACK_BACKGROUNDS.key |
| 260 | override val isRuntimeModifiable: Boolean = false | 246 | override val isRuntimeModifiable: Boolean = |
| 247 | BooleanSetting.BLACK_BACKGROUNDS.isRuntimeModifiable | ||
| 248 | |||
| 261 | override fun getValueAsString(needsGlobal: Boolean): String = | 249 | override fun getValueAsString(needsGlobal: Boolean): String = |
| 262 | getBoolean().toString() | 250 | BooleanSetting.BLACK_BACKGROUNDS.getValueAsString() |
| 263 | 251 | ||
| 264 | override val defaultValue: Boolean = false | 252 | override val defaultValue: Boolean = BooleanSetting.BLACK_BACKGROUNDS.defaultValue |
| 265 | override fun reset() { | 253 | override fun reset() { |
| 266 | preferences.edit() | 254 | BooleanSetting.BLACK_BACKGROUNDS |
| 267 | .putBoolean(Settings.PREF_BLACK_BACKGROUNDS, defaultValue) | 255 | .setBoolean(BooleanSetting.BLACK_BACKGROUNDS.defaultValue) |
| 268 | .apply() | ||
| 269 | settingsViewModel.setShouldRecreate(true) | 256 | settingsViewModel.setShouldRecreate(true) |
| 270 | } | 257 | } |
| 271 | } | 258 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt index 0dce8ad8d..816336820 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt | |||
| @@ -149,7 +149,7 @@ class AddonsFragment : Fragment() { | |||
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | val isValid = externalAddonDirectory.listFiles() | 151 | val isValid = externalAddonDirectory.listFiles() |
| 152 | .any { AddonUtil.validAddonDirectories.contains(it.name) } | 152 | .any { AddonUtil.validAddonDirectories.contains(it.name?.lowercase()) } |
| 153 | val errorMessage = MessageDialogFragment.newInstance( | 153 | val errorMessage = MessageDialogFragment.newInstance( |
| 154 | requireActivity(), | 154 | requireActivity(), |
| 155 | titleId = R.string.invalid_directory, | 155 | titleId = R.string.invalid_directory, |
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..9efc1705d 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,23 @@ 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 |
| 53 | import org.yuzu.yuzu_emu.features.settings.model.Settings.EmulationOrientation | ||
| 55 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile | 54 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile |
| 56 | import org.yuzu.yuzu_emu.model.DriverViewModel | 55 | import org.yuzu.yuzu_emu.model.DriverViewModel |
| 57 | import org.yuzu.yuzu_emu.model.Game | 56 | import org.yuzu.yuzu_emu.model.Game |
| 58 | import org.yuzu.yuzu_emu.model.EmulationViewModel | 57 | import org.yuzu.yuzu_emu.model.EmulationViewModel |
| 59 | import org.yuzu.yuzu_emu.overlay.InputOverlay | 58 | import org.yuzu.yuzu_emu.overlay.model.OverlayControl |
| 59 | import org.yuzu.yuzu_emu.overlay.model.OverlayLayout | ||
| 60 | import org.yuzu.yuzu_emu.utils.* | 60 | import org.yuzu.yuzu_emu.utils.* |
| 61 | import java.lang.NullPointerException | 61 | import java.lang.NullPointerException |
| 62 | 62 | ||
| 63 | class EmulationFragment : Fragment(), SurfaceHolder.Callback { | 63 | class EmulationFragment : Fragment(), SurfaceHolder.Callback { |
| 64 | private lateinit var preferences: SharedPreferences | ||
| 65 | private lateinit var emulationState: EmulationState | 64 | private lateinit var emulationState: EmulationState |
| 66 | private var emulationActivity: EmulationActivity? = null | 65 | private var emulationActivity: EmulationActivity? = null |
| 67 | private var perfStatsUpdater: (() -> Unit)? = null | 66 | private var perfStatsUpdater: (() -> Unit)? = null |
| @@ -101,6 +100,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 101 | */ | 100 | */ |
| 102 | override fun onCreate(savedInstanceState: Bundle?) { | 101 | override fun onCreate(savedInstanceState: Bundle?) { |
| 103 | super.onCreate(savedInstanceState) | 102 | super.onCreate(savedInstanceState) |
| 103 | updateOrientation() | ||
| 104 | 104 | ||
| 105 | val intentUri: Uri? = requireActivity().intent.data | 105 | val intentUri: Uri? = requireActivity().intent.data |
| 106 | var intentGame: Game? = null | 106 | var intentGame: Game? = null |
| @@ -141,7 +141,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 141 | 141 | ||
| 142 | // So this fragment doesn't restart on configuration changes; i.e. rotation. | 142 | // So this fragment doesn't restart on configuration changes; i.e. rotation. |
| 143 | retainInstance = true | 143 | retainInstance = true |
| 144 | preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||
| 145 | emulationState = EmulationState(game.path) | 144 | emulationState = EmulationState(game.path) |
| 146 | } | 145 | } |
| 147 | 146 | ||
| @@ -382,24 +381,25 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 382 | } | 381 | } |
| 383 | 382 | ||
| 384 | updateScreenLayout() | 383 | updateScreenLayout() |
| 384 | val showInputOverlay = BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean() | ||
| 385 | if (emulationActivity?.isInPictureInPictureMode == true) { | 385 | if (emulationActivity?.isInPictureInPictureMode == true) { |
| 386 | if (binding.drawerLayout.isOpen) { | 386 | if (binding.drawerLayout.isOpen) { |
| 387 | binding.drawerLayout.close() | 387 | binding.drawerLayout.close() |
| 388 | } | 388 | } |
| 389 | if (EmulationMenuSettings.showOverlay) { | 389 | if (showInputOverlay) { |
| 390 | binding.surfaceInputOverlay.visibility = View.INVISIBLE | 390 | binding.surfaceInputOverlay.visibility = View.INVISIBLE |
| 391 | } | 391 | } |
| 392 | } else { | 392 | } else { |
| 393 | if (EmulationMenuSettings.showOverlay && emulationViewModel.emulationStarted.value) { | 393 | if (showInputOverlay && emulationViewModel.emulationStarted.value) { |
| 394 | binding.surfaceInputOverlay.visibility = View.VISIBLE | 394 | binding.surfaceInputOverlay.visibility = View.VISIBLE |
| 395 | } else { | 395 | } else { |
| 396 | binding.surfaceInputOverlay.visibility = View.INVISIBLE | 396 | binding.surfaceInputOverlay.visibility = View.INVISIBLE |
| 397 | } | 397 | } |
| 398 | if (!isInFoldableLayout) { | 398 | if (!isInFoldableLayout) { |
| 399 | if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { | 399 | if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { |
| 400 | binding.surfaceInputOverlay.layout = InputOverlay.PORTRAIT | 400 | binding.surfaceInputOverlay.layout = OverlayLayout.Portrait |
| 401 | } else { | 401 | } else { |
| 402 | binding.surfaceInputOverlay.layout = InputOverlay.LANDSCAPE | 402 | binding.surfaceInputOverlay.layout = OverlayLayout.Landscape |
| 403 | } | 403 | } |
| 404 | } | 404 | } |
| 405 | } | 405 | } |
| @@ -423,17 +423,15 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 423 | } | 423 | } |
| 424 | 424 | ||
| 425 | private fun resetInputOverlay() { | 425 | private fun resetInputOverlay() { |
| 426 | preferences.edit() | 426 | IntSetting.OVERLAY_SCALE.reset() |
| 427 | .remove(Settings.PREF_CONTROL_SCALE) | 427 | IntSetting.OVERLAY_OPACITY.reset() |
| 428 | .remove(Settings.PREF_CONTROL_OPACITY) | ||
| 429 | .apply() | ||
| 430 | binding.surfaceInputOverlay.post { | 428 | binding.surfaceInputOverlay.post { |
| 431 | binding.surfaceInputOverlay.resetLayoutVisibilityAndPlacement() | 429 | binding.surfaceInputOverlay.resetLayoutVisibilityAndPlacement() |
| 432 | } | 430 | } |
| 433 | } | 431 | } |
| 434 | 432 | ||
| 435 | private fun updateShowFpsOverlay() { | 433 | private fun updateShowFpsOverlay() { |
| 436 | if (EmulationMenuSettings.showFps) { | 434 | if (BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()) { |
| 437 | val SYSTEM_FPS = 0 | 435 | val SYSTEM_FPS = 0 |
| 438 | val FPS = 1 | 436 | val FPS = 1 |
| 439 | val FRAMETIME = 2 | 437 | val FRAMETIME = 2 |
| @@ -462,13 +460,23 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 462 | @SuppressLint("SourceLockedOrientationActivity") | 460 | @SuppressLint("SourceLockedOrientationActivity") |
| 463 | private fun updateOrientation() { | 461 | private fun updateOrientation() { |
| 464 | emulationActivity?.let { | 462 | emulationActivity?.let { |
| 465 | it.requestedOrientation = when (IntSetting.RENDERER_SCREEN_LAYOUT.getInt()) { | 463 | val orientationSetting = |
| 466 | Settings.LayoutOption_MobileLandscape -> | 464 | EmulationOrientation.from(IntSetting.RENDERER_SCREEN_LAYOUT.getInt()) |
| 465 | it.requestedOrientation = when (orientationSetting) { | ||
| 466 | EmulationOrientation.Unspecified -> ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED | ||
| 467 | EmulationOrientation.SensorLandscape -> | ||
| 467 | ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE | 468 | ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE |
| 468 | Settings.LayoutOption_MobilePortrait -> | 469 | |
| 469 | ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT | 470 | EmulationOrientation.Landscape -> ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE |
| 470 | Settings.LayoutOption_Unspecified -> ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED | 471 | EmulationOrientation.ReverseLandscape -> |
| 471 | else -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE | 472 | ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE |
| 473 | |||
| 474 | EmulationOrientation.SensorPortrait -> | ||
| 475 | ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT | ||
| 476 | |||
| 477 | EmulationOrientation.Portrait -> ActivityInfo.SCREEN_ORIENTATION_PORTRAIT | ||
| 478 | EmulationOrientation.ReversePortrait -> | ||
| 479 | ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT | ||
| 472 | } | 480 | } |
| 473 | } | 481 | } |
| 474 | } | 482 | } |
| @@ -496,7 +504,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 496 | binding.inGameMenu.layoutParams.height = it.bounds.bottom | 504 | binding.inGameMenu.layoutParams.height = it.bounds.bottom |
| 497 | 505 | ||
| 498 | isInFoldableLayout = true | 506 | isInFoldableLayout = true |
| 499 | binding.surfaceInputOverlay.layout = InputOverlay.FOLDABLE | 507 | binding.surfaceInputOverlay.layout = OverlayLayout.Foldable |
| 500 | } | 508 | } |
| 501 | } | 509 | } |
| 502 | it.isSeparating | 510 | it.isSeparating |
| @@ -535,18 +543,22 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 535 | popup.menuInflater.inflate(R.menu.menu_overlay_options, popup.menu) | 543 | popup.menuInflater.inflate(R.menu.menu_overlay_options, popup.menu) |
| 536 | 544 | ||
| 537 | popup.menu.apply { | 545 | popup.menu.apply { |
| 538 | findItem(R.id.menu_toggle_fps).isChecked = EmulationMenuSettings.showFps | 546 | findItem(R.id.menu_toggle_fps).isChecked = |
| 539 | findItem(R.id.menu_rel_stick_center).isChecked = EmulationMenuSettings.joystickRelCenter | 547 | BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean() |
| 540 | findItem(R.id.menu_dpad_slide).isChecked = EmulationMenuSettings.dpadSlide | 548 | findItem(R.id.menu_rel_stick_center).isChecked = |
| 541 | findItem(R.id.menu_show_overlay).isChecked = EmulationMenuSettings.showOverlay | 549 | BooleanSetting.JOYSTICK_REL_CENTER.getBoolean() |
| 542 | findItem(R.id.menu_haptics).isChecked = EmulationMenuSettings.hapticFeedback | 550 | findItem(R.id.menu_dpad_slide).isChecked = BooleanSetting.DPAD_SLIDE.getBoolean() |
| 551 | findItem(R.id.menu_show_overlay).isChecked = | ||
| 552 | BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean() | ||
| 553 | findItem(R.id.menu_haptics).isChecked = BooleanSetting.HAPTIC_FEEDBACK.getBoolean() | ||
| 554 | findItem(R.id.menu_touchscreen).isChecked = BooleanSetting.TOUCHSCREEN.getBoolean() | ||
| 543 | } | 555 | } |
| 544 | 556 | ||
| 545 | popup.setOnMenuItemClickListener { | 557 | popup.setOnMenuItemClickListener { |
| 546 | when (it.itemId) { | 558 | when (it.itemId) { |
| 547 | R.id.menu_toggle_fps -> { | 559 | R.id.menu_toggle_fps -> { |
| 548 | it.isChecked = !it.isChecked | 560 | it.isChecked = !it.isChecked |
| 549 | EmulationMenuSettings.showFps = it.isChecked | 561 | BooleanSetting.SHOW_PERFORMANCE_OVERLAY.setBoolean(it.isChecked) |
| 550 | updateShowFpsOverlay() | 562 | updateShowFpsOverlay() |
| 551 | true | 563 | true |
| 552 | } | 564 | } |
| @@ -564,11 +576,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 564 | } | 576 | } |
| 565 | 577 | ||
| 566 | R.id.menu_toggle_controls -> { | 578 | R.id.menu_toggle_controls -> { |
| 567 | val preferences = | 579 | val overlayControlData = NativeConfig.getOverlayControlData() |
| 568 | PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | 580 | val optionsArray = BooleanArray(overlayControlData.size) |
| 569 | val optionsArray = BooleanArray(Settings.overlayPreferences.size) | 581 | overlayControlData.forEachIndexed { i, _ -> |
| 570 | Settings.overlayPreferences.forEachIndexed { i, _ -> | 582 | optionsArray[i] = overlayControlData.firstOrNull { data -> |
| 571 | optionsArray[i] = preferences.getBoolean("buttonToggle$i", i < 15) | 583 | OverlayControl.entries[i].id == data.id |
| 584 | }?.enabled == true | ||
| 572 | } | 585 | } |
| 573 | 586 | ||
| 574 | val dialog = MaterialAlertDialogBuilder(requireContext()) | 587 | val dialog = MaterialAlertDialogBuilder(requireContext()) |
| @@ -577,11 +590,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 577 | R.array.gamepadButtons, | 590 | R.array.gamepadButtons, |
| 578 | optionsArray | 591 | optionsArray |
| 579 | ) { _, indexSelected, isChecked -> | 592 | ) { _, indexSelected, isChecked -> |
| 580 | preferences.edit() | 593 | overlayControlData.firstOrNull { data -> |
| 581 | .putBoolean("buttonToggle$indexSelected", isChecked) | 594 | OverlayControl.entries[indexSelected].id == data.id |
| 582 | .apply() | 595 | }?.enabled = isChecked |
| 583 | } | 596 | } |
| 584 | .setPositiveButton(android.R.string.ok) { _, _ -> | 597 | .setPositiveButton(android.R.string.ok) { _, _ -> |
| 598 | NativeConfig.setOverlayControlData(overlayControlData) | ||
| 599 | NativeConfig.saveGlobalConfig() | ||
| 585 | binding.surfaceInputOverlay.refreshControls() | 600 | binding.surfaceInputOverlay.refreshControls() |
| 586 | } | 601 | } |
| 587 | .setNegativeButton(android.R.string.cancel, null) | 602 | .setNegativeButton(android.R.string.cancel, null) |
| @@ -592,12 +607,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 592 | dialog.getButton(AlertDialog.BUTTON_NEUTRAL) | 607 | dialog.getButton(AlertDialog.BUTTON_NEUTRAL) |
| 593 | .setOnClickListener { | 608 | .setOnClickListener { |
| 594 | val isChecked = !optionsArray[0] | 609 | val isChecked = !optionsArray[0] |
| 595 | Settings.overlayPreferences.forEachIndexed { i, _ -> | 610 | overlayControlData.forEachIndexed { i, _ -> |
| 596 | optionsArray[i] = isChecked | 611 | optionsArray[i] = isChecked |
| 597 | dialog.listView.setItemChecked(i, isChecked) | 612 | dialog.listView.setItemChecked(i, isChecked) |
| 598 | preferences.edit() | 613 | overlayControlData[i].enabled = isChecked |
| 599 | .putBoolean("buttonToggle$i", isChecked) | ||
| 600 | .apply() | ||
| 601 | } | 614 | } |
| 602 | } | 615 | } |
| 603 | true | 616 | true |
| @@ -605,26 +618,32 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 605 | 618 | ||
| 606 | R.id.menu_show_overlay -> { | 619 | R.id.menu_show_overlay -> { |
| 607 | it.isChecked = !it.isChecked | 620 | it.isChecked = !it.isChecked |
| 608 | EmulationMenuSettings.showOverlay = it.isChecked | 621 | BooleanSetting.SHOW_INPUT_OVERLAY.setBoolean(it.isChecked) |
| 609 | binding.surfaceInputOverlay.refreshControls() | 622 | binding.surfaceInputOverlay.refreshControls() |
| 610 | true | 623 | true |
| 611 | } | 624 | } |
| 612 | 625 | ||
| 613 | R.id.menu_rel_stick_center -> { | 626 | R.id.menu_rel_stick_center -> { |
| 614 | it.isChecked = !it.isChecked | 627 | it.isChecked = !it.isChecked |
| 615 | EmulationMenuSettings.joystickRelCenter = it.isChecked | 628 | BooleanSetting.JOYSTICK_REL_CENTER.setBoolean(it.isChecked) |
| 616 | true | 629 | true |
| 617 | } | 630 | } |
| 618 | 631 | ||
| 619 | R.id.menu_dpad_slide -> { | 632 | R.id.menu_dpad_slide -> { |
| 620 | it.isChecked = !it.isChecked | 633 | it.isChecked = !it.isChecked |
| 621 | EmulationMenuSettings.dpadSlide = it.isChecked | 634 | BooleanSetting.DPAD_SLIDE.setBoolean(it.isChecked) |
| 622 | true | 635 | true |
| 623 | } | 636 | } |
| 624 | 637 | ||
| 625 | R.id.menu_haptics -> { | 638 | R.id.menu_haptics -> { |
| 626 | it.isChecked = !it.isChecked | 639 | it.isChecked = !it.isChecked |
| 627 | EmulationMenuSettings.hapticFeedback = it.isChecked | 640 | BooleanSetting.HAPTIC_FEEDBACK.setBoolean(it.isChecked) |
| 641 | true | ||
| 642 | } | ||
| 643 | |||
| 644 | R.id.menu_touchscreen -> { | ||
| 645 | it.isChecked = !it.isChecked | ||
| 646 | BooleanSetting.TOUCHSCREEN.setBoolean(it.isChecked) | ||
| 628 | true | 647 | true |
| 629 | } | 648 | } |
| 630 | 649 | ||
| @@ -644,7 +663,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 644 | @SuppressLint("SourceLockedOrientationActivity") | 663 | @SuppressLint("SourceLockedOrientationActivity") |
| 645 | private fun startConfiguringControls() { | 664 | private fun startConfiguringControls() { |
| 646 | // Lock the current orientation to prevent editing inconsistencies | 665 | // Lock the current orientation to prevent editing inconsistencies |
| 647 | if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == Settings.LayoutOption_Unspecified) { | 666 | if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == EmulationOrientation.Unspecified.int) { |
| 648 | emulationActivity?.let { | 667 | emulationActivity?.let { |
| 649 | it.requestedOrientation = | 668 | it.requestedOrientation = |
| 650 | if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) { | 669 | if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) { |
| @@ -662,11 +681,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 662 | binding.doneControlConfig.visibility = View.GONE | 681 | binding.doneControlConfig.visibility = View.GONE |
| 663 | binding.surfaceInputOverlay.setIsInEditMode(false) | 682 | binding.surfaceInputOverlay.setIsInEditMode(false) |
| 664 | // Unlock the orientation if it was locked for editing | 683 | // Unlock the orientation if it was locked for editing |
| 665 | if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == Settings.LayoutOption_Unspecified) { | 684 | if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == EmulationOrientation.Unspecified.int) { |
| 666 | emulationActivity?.let { | 685 | emulationActivity?.let { |
| 667 | it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED | 686 | it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED |
| 668 | } | 687 | } |
| 669 | } | 688 | } |
| 689 | NativeConfig.saveGlobalConfig() | ||
| 670 | } | 690 | } |
| 671 | 691 | ||
| 672 | @SuppressLint("SetTextI18n") | 692 | @SuppressLint("SetTextI18n") |
| @@ -675,7 +695,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 675 | adjustBinding.apply { | 695 | adjustBinding.apply { |
| 676 | inputScaleSlider.apply { | 696 | inputScaleSlider.apply { |
| 677 | valueTo = 150F | 697 | valueTo = 150F |
| 678 | value = preferences.getInt(Settings.PREF_CONTROL_SCALE, 50).toFloat() | 698 | value = IntSetting.OVERLAY_SCALE.getInt().toFloat() |
| 679 | addOnChangeListener( | 699 | addOnChangeListener( |
| 680 | Slider.OnChangeListener { _, value, _ -> | 700 | Slider.OnChangeListener { _, value, _ -> |
| 681 | inputScaleValue.text = "${value.toInt()}%" | 701 | inputScaleValue.text = "${value.toInt()}%" |
| @@ -685,7 +705,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 685 | } | 705 | } |
| 686 | inputOpacitySlider.apply { | 706 | inputOpacitySlider.apply { |
| 687 | valueTo = 100F | 707 | valueTo = 100F |
| 688 | value = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100).toFloat() | 708 | value = IntSetting.OVERLAY_OPACITY.getInt().toFloat() |
| 689 | addOnChangeListener( | 709 | addOnChangeListener( |
| 690 | Slider.OnChangeListener { _, value, _ -> | 710 | Slider.OnChangeListener { _, value, _ -> |
| 691 | inputOpacityValue.text = "${value.toInt()}%" | 711 | inputOpacityValue.text = "${value.toInt()}%" |
| @@ -709,16 +729,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 709 | } | 729 | } |
| 710 | 730 | ||
| 711 | private fun setControlScale(scale: Int) { | 731 | private fun setControlScale(scale: Int) { |
| 712 | preferences.edit() | 732 | IntSetting.OVERLAY_SCALE.setInt(scale) |
| 713 | .putInt(Settings.PREF_CONTROL_SCALE, scale) | ||
| 714 | .apply() | ||
| 715 | binding.surfaceInputOverlay.refreshControls() | 733 | binding.surfaceInputOverlay.refreshControls() |
| 716 | } | 734 | } |
| 717 | 735 | ||
| 718 | private fun setControlOpacity(opacity: Int) { | 736 | private fun setControlOpacity(opacity: Int) { |
| 719 | preferences.edit() | 737 | IntSetting.OVERLAY_OPACITY.setInt(opacity) |
| 720 | .putInt(Settings.PREF_CONTROL_OPACITY, opacity) | ||
| 721 | .apply() | ||
| 722 | binding.surfaceInputOverlay.refreshControls() | 738 | binding.surfaceInputOverlay.refreshControls() |
| 723 | } | 739 | } |
| 724 | 740 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt index b1d3c0040..b04d1208f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt | |||
| @@ -445,7 +445,8 @@ class GamePropertiesFragment : Fragment() { | |||
| 445 | val zipResult = FileUtil.zipFromInternalStorage( | 445 | val zipResult = FileUtil.zipFromInternalStorage( |
| 446 | File(saveLocation), | 446 | File(saveLocation), |
| 447 | saveLocation.replaceAfterLast("/", ""), | 447 | saveLocation.replaceAfterLast("/", ""), |
| 448 | BufferedOutputStream(requireContext().contentResolver.openOutputStream(result)) | 448 | BufferedOutputStream(requireContext().contentResolver.openOutputStream(result)), |
| 449 | compression = false | ||
| 449 | ) | 450 | ) |
| 450 | return@newInstance when (zipResult) { | 451 | return@newInstance when (zipResult) { |
| 451 | TaskState.Completed -> getString(R.string.export_success) | 452 | TaskState.Completed -> getString(R.string.export_success) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt index d19f20dc2..5ae05b5cc 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt | |||
| @@ -167,13 +167,14 @@ class GamesViewModel : ViewModel() { | |||
| 167 | } | 167 | } |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | fun onCloseGameFoldersFragment() = | 170 | fun onCloseGameFoldersFragment() { |
| 171 | NativeConfig.saveGlobalConfig() | ||
| 171 | viewModelScope.launch { | 172 | viewModelScope.launch { |
| 172 | withContext(Dispatchers.IO) { | 173 | withContext(Dispatchers.IO) { |
| 173 | NativeConfig.saveGlobalConfig() | ||
| 174 | getGameDirs(true) | 174 | getGameDirs(true) |
| 175 | } | 175 | } |
| 176 | } | 176 | } |
| 177 | } | ||
| 177 | 178 | ||
| 178 | private fun getGameDirs(reloadList: Boolean = false) { | 179 | private fun getGameDirs(reloadList: Boolean = false) { |
| 179 | val gameDirs = NativeConfig.getGameDirs() | 180 | val gameDirs = NativeConfig.getGameDirs() |
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..c87486c90 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,12 @@ 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 |
| 33 | import org.yuzu.yuzu_emu.features.settings.model.Settings | 32 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting |
| 34 | import org.yuzu.yuzu_emu.utils.EmulationMenuSettings | 33 | import org.yuzu.yuzu_emu.overlay.model.OverlayControl |
| 34 | import org.yuzu.yuzu_emu.overlay.model.OverlayControlData | ||
| 35 | import org.yuzu.yuzu_emu.overlay.model.OverlayLayout | ||
| 36 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 35 | 37 | ||
| 36 | /** | 38 | /** |
| 37 | * Draws the interactive input overlay on top of the | 39 | * Draws the interactive input overlay on top of the |
| @@ -51,23 +53,18 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 51 | 53 | ||
| 52 | private lateinit var windowInsets: WindowInsets | 54 | private lateinit var windowInsets: WindowInsets |
| 53 | 55 | ||
| 54 | var layout = LANDSCAPE | 56 | var layout = OverlayLayout.Landscape |
| 55 | 57 | ||
| 56 | override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { | 58 | override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { |
| 57 | super.onLayout(changed, left, top, right, bottom) | 59 | super.onLayout(changed, left, top, right, bottom) |
| 58 | 60 | ||
| 59 | windowInsets = rootWindowInsets | 61 | windowInsets = rootWindowInsets |
| 60 | 62 | ||
| 61 | val overlayVersion = preferences.getInt(Settings.PREF_OVERLAY_VERSION, 0) | 63 | val overlayControlData = NativeConfig.getOverlayControlData() |
| 62 | if (overlayVersion != OVERLAY_VERSION) { | 64 | if (overlayControlData.isEmpty()) { |
| 63 | resetAllLayouts() | 65 | populateDefaultConfig() |
| 64 | } else { | 66 | } else { |
| 65 | val layoutIndex = overlayLayouts.indexOf(layout) | 67 | checkForNewControls(overlayControlData) |
| 66 | val currentLayoutVersion = | ||
| 67 | preferences.getInt(Settings.overlayLayoutPrefs[layoutIndex], 0) | ||
| 68 | if (currentLayoutVersion != overlayLayoutVersions[layoutIndex]) { | ||
| 69 | resetCurrentLayout() | ||
| 70 | } | ||
| 71 | } | 68 | } |
| 72 | 69 | ||
| 73 | // Load the controls. | 70 | // Load the controls. |
| @@ -123,7 +120,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 123 | } | 120 | } |
| 124 | 121 | ||
| 125 | for (dpad in overlayDpads) { | 122 | for (dpad in overlayDpads) { |
| 126 | if (!dpad.updateStatus(event, EmulationMenuSettings.dpadSlide)) { | 123 | if (!dpad.updateStatus(event, BooleanSetting.DPAD_SLIDE.getBoolean())) { |
| 127 | continue | 124 | continue |
| 128 | } | 125 | } |
| 129 | NativeLibrary.onGamePadButtonEvent( | 126 | NativeLibrary.onGamePadButtonEvent( |
| @@ -174,7 +171,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 174 | invalidate() | 171 | invalidate() |
| 175 | } | 172 | } |
| 176 | 173 | ||
| 177 | if (!preferences.getBoolean(Settings.PREF_TOUCH_ENABLED, true)) { | 174 | if (!BooleanSetting.TOUCHSCREEN.getBoolean()) { |
| 178 | return true | 175 | return true |
| 179 | } | 176 | } |
| 180 | 177 | ||
| @@ -211,7 +208,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 211 | } | 208 | } |
| 212 | 209 | ||
| 213 | private fun playHaptics(event: MotionEvent) { | 210 | private fun playHaptics(event: MotionEvent) { |
| 214 | if (EmulationMenuSettings.hapticFeedback) { | 211 | if (BooleanSetting.HAPTIC_FEEDBACK.getBoolean()) { |
| 215 | when (event.actionMasked) { | 212 | when (event.actionMasked) { |
| 216 | MotionEvent.ACTION_DOWN, | 213 | MotionEvent.ACTION_DOWN, |
| 217 | MotionEvent.ACTION_POINTER_DOWN -> | 214 | MotionEvent.ACTION_POINTER_DOWN -> |
| @@ -255,10 +252,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 255 | MotionEvent.ACTION_POINTER_DOWN -> | 252 | MotionEvent.ACTION_POINTER_DOWN -> |
| 256 | // If no button is being moved now, remember the currently touched button to move. | 253 | // If no button is being moved now, remember the currently touched button to move. |
| 257 | if (buttonBeingConfigured == null && | 254 | if (buttonBeingConfigured == null && |
| 258 | button.bounds.contains( | 255 | button.bounds.contains(fingerPositionX, fingerPositionY) |
| 259 | fingerPositionX, | ||
| 260 | fingerPositionY | ||
| 261 | ) | ||
| 262 | ) { | 256 | ) { |
| 263 | buttonBeingConfigured = button | 257 | buttonBeingConfigured = button |
| 264 | buttonBeingConfigured!!.onConfigureTouch(event) | 258 | buttonBeingConfigured!!.onConfigureTouch(event) |
| @@ -274,7 +268,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 274 | MotionEvent.ACTION_POINTER_UP -> if (buttonBeingConfigured === button) { | 268 | MotionEvent.ACTION_POINTER_UP -> if (buttonBeingConfigured === button) { |
| 275 | // Persist button position by saving new place. | 269 | // Persist button position by saving new place. |
| 276 | saveControlPosition( | 270 | saveControlPosition( |
| 277 | buttonBeingConfigured!!.prefId, | 271 | buttonBeingConfigured!!.overlayControlData.id, |
| 278 | buttonBeingConfigured!!.bounds.centerX(), | 272 | buttonBeingConfigured!!.bounds.centerX(), |
| 279 | buttonBeingConfigured!!.bounds.centerY(), | 273 | buttonBeingConfigured!!.bounds.centerY(), |
| 280 | layout | 274 | layout |
| @@ -307,7 +301,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 307 | MotionEvent.ACTION_POINTER_UP -> if (dpadBeingConfigured === dpad) { | 301 | MotionEvent.ACTION_POINTER_UP -> if (dpadBeingConfigured === dpad) { |
| 308 | // Persist button position by saving new place. | 302 | // Persist button position by saving new place. |
| 309 | saveControlPosition( | 303 | saveControlPosition( |
| 310 | Settings.PREF_BUTTON_DPAD, | 304 | OverlayControl.COMBINED_DPAD.id, |
| 311 | dpadBeingConfigured!!.bounds.centerX(), | 305 | dpadBeingConfigured!!.bounds.centerX(), |
| 312 | dpadBeingConfigured!!.bounds.centerY(), | 306 | dpadBeingConfigured!!.bounds.centerY(), |
| 313 | layout | 307 | layout |
| @@ -321,10 +315,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 321 | when (event.action) { | 315 | when (event.action) { |
| 322 | MotionEvent.ACTION_DOWN, | 316 | MotionEvent.ACTION_DOWN, |
| 323 | MotionEvent.ACTION_POINTER_DOWN -> if (joystickBeingConfigured == null && | 317 | MotionEvent.ACTION_POINTER_DOWN -> if (joystickBeingConfigured == null && |
| 324 | joystick.bounds.contains( | 318 | joystick.bounds.contains(fingerPositionX, fingerPositionY) |
| 325 | fingerPositionX, | ||
| 326 | fingerPositionY | ||
| 327 | ) | ||
| 328 | ) { | 319 | ) { |
| 329 | joystickBeingConfigured = joystick | 320 | joystickBeingConfigured = joystick |
| 330 | joystickBeingConfigured!!.onConfigureTouch(event) | 321 | joystickBeingConfigured!!.onConfigureTouch(event) |
| @@ -351,231 +342,257 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 351 | return true | 342 | return true |
| 352 | } | 343 | } |
| 353 | 344 | ||
| 354 | private fun addOverlayControls(layout: String) { | 345 | private fun addOverlayControls(layout: OverlayLayout) { |
| 355 | val windowSize = getSafeScreenSize(context, Pair(measuredWidth, measuredHeight)) | 346 | val windowSize = getSafeScreenSize(context, Pair(measuredWidth, measuredHeight)) |
| 356 | if (preferences.getBoolean(Settings.PREF_BUTTON_A, true)) { | 347 | val overlayControlData = NativeConfig.getOverlayControlData() |
| 357 | overlayButtons.add( | 348 | for (data in overlayControlData) { |
| 358 | initializeOverlayButton( | 349 | if (!data.enabled) { |
| 359 | context, | 350 | continue |
| 360 | windowSize, | 351 | } |
| 361 | R.drawable.facebutton_a, | 352 | |
| 362 | R.drawable.facebutton_a_depressed, | 353 | val position = data.positionFromLayout(layout) |
| 363 | ButtonType.BUTTON_A, | 354 | when (data.id) { |
| 364 | Settings.PREF_BUTTON_A, | 355 | OverlayControl.BUTTON_A.id -> { |
| 365 | layout | 356 | overlayButtons.add( |
| 366 | ) | 357 | initializeOverlayButton( |
| 367 | ) | 358 | context, |
| 368 | } | 359 | windowSize, |
| 369 | if (preferences.getBoolean(Settings.PREF_BUTTON_B, true)) { | 360 | R.drawable.facebutton_a, |
| 370 | overlayButtons.add( | 361 | R.drawable.facebutton_a_depressed, |
| 371 | initializeOverlayButton( | 362 | ButtonType.BUTTON_A, |
| 372 | context, | 363 | data, |
| 373 | windowSize, | 364 | position |
| 374 | R.drawable.facebutton_b, | 365 | ) |
| 375 | R.drawable.facebutton_b_depressed, | 366 | ) |
| 376 | ButtonType.BUTTON_B, | 367 | } |
| 377 | Settings.PREF_BUTTON_B, | 368 | |
| 378 | layout | 369 | OverlayControl.BUTTON_B.id -> { |
| 379 | ) | 370 | overlayButtons.add( |
| 380 | ) | 371 | initializeOverlayButton( |
| 381 | } | 372 | context, |
| 382 | if (preferences.getBoolean(Settings.PREF_BUTTON_X, true)) { | 373 | windowSize, |
| 383 | overlayButtons.add( | 374 | R.drawable.facebutton_b, |
| 384 | initializeOverlayButton( | 375 | R.drawable.facebutton_b_depressed, |
| 385 | context, | 376 | ButtonType.BUTTON_B, |
| 386 | windowSize, | 377 | data, |
| 387 | R.drawable.facebutton_x, | 378 | position |
| 388 | R.drawable.facebutton_x_depressed, | 379 | ) |
| 389 | ButtonType.BUTTON_X, | 380 | ) |
| 390 | Settings.PREF_BUTTON_X, | 381 | } |
| 391 | layout | 382 | |
| 392 | ) | 383 | OverlayControl.BUTTON_X.id -> { |
| 393 | ) | 384 | overlayButtons.add( |
| 394 | } | 385 | initializeOverlayButton( |
| 395 | if (preferences.getBoolean(Settings.PREF_BUTTON_Y, true)) { | 386 | context, |
| 396 | overlayButtons.add( | 387 | windowSize, |
| 397 | initializeOverlayButton( | 388 | R.drawable.facebutton_x, |
| 398 | context, | 389 | R.drawable.facebutton_x_depressed, |
| 399 | windowSize, | 390 | ButtonType.BUTTON_X, |
| 400 | R.drawable.facebutton_y, | 391 | data, |
| 401 | R.drawable.facebutton_y_depressed, | 392 | position |
| 402 | ButtonType.BUTTON_Y, | 393 | ) |
| 403 | Settings.PREF_BUTTON_Y, | 394 | ) |
| 404 | layout | 395 | } |
| 405 | ) | 396 | |
| 406 | ) | 397 | OverlayControl.BUTTON_Y.id -> { |
| 407 | } | 398 | overlayButtons.add( |
| 408 | if (preferences.getBoolean(Settings.PREF_BUTTON_L, true)) { | 399 | initializeOverlayButton( |
| 409 | overlayButtons.add( | 400 | context, |
| 410 | initializeOverlayButton( | 401 | windowSize, |
| 411 | context, | 402 | R.drawable.facebutton_y, |
| 412 | windowSize, | 403 | R.drawable.facebutton_y_depressed, |
| 413 | R.drawable.l_shoulder, | 404 | ButtonType.BUTTON_Y, |
| 414 | R.drawable.l_shoulder_depressed, | 405 | data, |
| 415 | ButtonType.TRIGGER_L, | 406 | position |
| 416 | Settings.PREF_BUTTON_L, | 407 | ) |
| 417 | layout | 408 | ) |
| 418 | ) | 409 | } |
| 419 | ) | 410 | |
| 420 | } | 411 | OverlayControl.BUTTON_PLUS.id -> { |
| 421 | if (preferences.getBoolean(Settings.PREF_BUTTON_R, true)) { | 412 | overlayButtons.add( |
| 422 | overlayButtons.add( | 413 | initializeOverlayButton( |
| 423 | initializeOverlayButton( | 414 | context, |
| 424 | context, | 415 | windowSize, |
| 425 | windowSize, | 416 | R.drawable.facebutton_plus, |
| 426 | R.drawable.r_shoulder, | 417 | R.drawable.facebutton_plus_depressed, |
| 427 | R.drawable.r_shoulder_depressed, | 418 | ButtonType.BUTTON_PLUS, |
| 428 | ButtonType.TRIGGER_R, | 419 | data, |
| 429 | Settings.PREF_BUTTON_R, | 420 | position |
| 430 | layout | 421 | ) |
| 431 | ) | 422 | ) |
| 432 | ) | 423 | } |
| 433 | } | 424 | |
| 434 | if (preferences.getBoolean(Settings.PREF_BUTTON_ZL, true)) { | 425 | OverlayControl.BUTTON_MINUS.id -> { |
| 435 | overlayButtons.add( | 426 | overlayButtons.add( |
| 436 | initializeOverlayButton( | 427 | initializeOverlayButton( |
| 437 | context, | 428 | context, |
| 438 | windowSize, | 429 | windowSize, |
| 439 | R.drawable.zl_trigger, | 430 | R.drawable.facebutton_minus, |
| 440 | R.drawable.zl_trigger_depressed, | 431 | R.drawable.facebutton_minus_depressed, |
| 441 | ButtonType.TRIGGER_ZL, | 432 | ButtonType.BUTTON_MINUS, |
| 442 | Settings.PREF_BUTTON_ZL, | 433 | data, |
| 443 | layout | 434 | position |
| 444 | ) | 435 | ) |
| 445 | ) | 436 | ) |
| 446 | } | 437 | } |
| 447 | if (preferences.getBoolean(Settings.PREF_BUTTON_ZR, true)) { | 438 | |
| 448 | overlayButtons.add( | 439 | OverlayControl.BUTTON_HOME.id -> { |
| 449 | initializeOverlayButton( | 440 | overlayButtons.add( |
| 450 | context, | 441 | initializeOverlayButton( |
| 451 | windowSize, | 442 | context, |
| 452 | R.drawable.zr_trigger, | 443 | windowSize, |
| 453 | R.drawable.zr_trigger_depressed, | 444 | R.drawable.facebutton_home, |
| 454 | ButtonType.TRIGGER_ZR, | 445 | R.drawable.facebutton_home_depressed, |
| 455 | Settings.PREF_BUTTON_ZR, | 446 | ButtonType.BUTTON_HOME, |
| 456 | layout | 447 | data, |
| 457 | ) | 448 | position |
| 458 | ) | 449 | ) |
| 459 | } | 450 | ) |
| 460 | if (preferences.getBoolean(Settings.PREF_BUTTON_PLUS, true)) { | 451 | } |
| 461 | overlayButtons.add( | 452 | |
| 462 | initializeOverlayButton( | 453 | OverlayControl.BUTTON_CAPTURE.id -> { |
| 463 | context, | 454 | overlayButtons.add( |
| 464 | windowSize, | 455 | initializeOverlayButton( |
| 465 | R.drawable.facebutton_plus, | 456 | context, |
| 466 | R.drawable.facebutton_plus_depressed, | 457 | windowSize, |
| 467 | ButtonType.BUTTON_PLUS, | 458 | R.drawable.facebutton_screenshot, |
| 468 | Settings.PREF_BUTTON_PLUS, | 459 | R.drawable.facebutton_screenshot_depressed, |
| 469 | layout | 460 | ButtonType.BUTTON_CAPTURE, |
| 470 | ) | 461 | data, |
| 471 | ) | 462 | position |
| 472 | } | 463 | ) |
| 473 | if (preferences.getBoolean(Settings.PREF_BUTTON_MINUS, true)) { | 464 | ) |
| 474 | overlayButtons.add( | 465 | } |
| 475 | initializeOverlayButton( | 466 | |
| 476 | context, | 467 | OverlayControl.BUTTON_L.id -> { |
| 477 | windowSize, | 468 | overlayButtons.add( |
| 478 | R.drawable.facebutton_minus, | 469 | initializeOverlayButton( |
| 479 | R.drawable.facebutton_minus_depressed, | 470 | context, |
| 480 | ButtonType.BUTTON_MINUS, | 471 | windowSize, |
| 481 | Settings.PREF_BUTTON_MINUS, | 472 | R.drawable.l_shoulder, |
| 482 | layout | 473 | R.drawable.l_shoulder_depressed, |
| 483 | ) | 474 | ButtonType.TRIGGER_L, |
| 484 | ) | 475 | data, |
| 485 | } | 476 | position |
| 486 | if (preferences.getBoolean(Settings.PREF_BUTTON_DPAD, true)) { | 477 | ) |
| 487 | overlayDpads.add( | 478 | ) |
| 488 | initializeOverlayDpad( | 479 | } |
| 489 | context, | 480 | |
| 490 | windowSize, | 481 | OverlayControl.BUTTON_R.id -> { |
| 491 | R.drawable.dpad_standard, | 482 | overlayButtons.add( |
| 492 | R.drawable.dpad_standard_cardinal_depressed, | 483 | initializeOverlayButton( |
| 493 | R.drawable.dpad_standard_diagonal_depressed, | 484 | context, |
| 494 | layout | 485 | windowSize, |
| 495 | ) | 486 | R.drawable.r_shoulder, |
| 496 | ) | 487 | R.drawable.r_shoulder_depressed, |
| 497 | } | 488 | ButtonType.TRIGGER_R, |
| 498 | if (preferences.getBoolean(Settings.PREF_STICK_L, true)) { | 489 | data, |
| 499 | overlayJoysticks.add( | 490 | position |
| 500 | initializeOverlayJoystick( | 491 | ) |
| 501 | context, | 492 | ) |
| 502 | windowSize, | 493 | } |
| 503 | R.drawable.joystick_range, | 494 | |
| 504 | R.drawable.joystick, | 495 | OverlayControl.BUTTON_ZL.id -> { |
| 505 | R.drawable.joystick_depressed, | 496 | overlayButtons.add( |
| 506 | StickType.STICK_L, | 497 | initializeOverlayButton( |
| 507 | ButtonType.STICK_L, | 498 | context, |
| 508 | Settings.PREF_STICK_L, | 499 | windowSize, |
| 509 | layout | 500 | R.drawable.zl_trigger, |
| 510 | ) | 501 | R.drawable.zl_trigger_depressed, |
| 511 | ) | 502 | ButtonType.TRIGGER_ZL, |
| 512 | } | 503 | data, |
| 513 | if (preferences.getBoolean(Settings.PREF_STICK_R, true)) { | 504 | position |
| 514 | overlayJoysticks.add( | 505 | ) |
| 515 | initializeOverlayJoystick( | 506 | ) |
| 516 | context, | 507 | } |
| 517 | windowSize, | 508 | |
| 518 | R.drawable.joystick_range, | 509 | OverlayControl.BUTTON_ZR.id -> { |
| 519 | R.drawable.joystick, | 510 | overlayButtons.add( |
| 520 | R.drawable.joystick_depressed, | 511 | initializeOverlayButton( |
| 521 | StickType.STICK_R, | 512 | context, |
| 522 | ButtonType.STICK_R, | 513 | windowSize, |
| 523 | Settings.PREF_STICK_R, | 514 | R.drawable.zr_trigger, |
| 524 | layout | 515 | R.drawable.zr_trigger_depressed, |
| 525 | ) | 516 | ButtonType.TRIGGER_ZR, |
| 526 | ) | 517 | data, |
| 527 | } | 518 | position |
| 528 | if (preferences.getBoolean(Settings.PREF_BUTTON_HOME, false)) { | 519 | ) |
| 529 | overlayButtons.add( | 520 | ) |
| 530 | initializeOverlayButton( | 521 | } |
| 531 | context, | 522 | |
| 532 | windowSize, | 523 | OverlayControl.BUTTON_STICK_L.id -> { |
| 533 | R.drawable.facebutton_home, | 524 | overlayButtons.add( |
| 534 | R.drawable.facebutton_home_depressed, | 525 | initializeOverlayButton( |
| 535 | ButtonType.BUTTON_HOME, | 526 | context, |
| 536 | Settings.PREF_BUTTON_HOME, | 527 | windowSize, |
| 537 | layout | 528 | R.drawable.button_l3, |
| 538 | ) | 529 | R.drawable.button_l3_depressed, |
| 539 | ) | 530 | ButtonType.STICK_L, |
| 540 | } | 531 | data, |
| 541 | if (preferences.getBoolean(Settings.PREF_BUTTON_SCREENSHOT, false)) { | 532 | position |
| 542 | overlayButtons.add( | 533 | ) |
| 543 | initializeOverlayButton( | 534 | ) |
| 544 | context, | 535 | } |
| 545 | windowSize, | 536 | |
| 546 | R.drawable.facebutton_screenshot, | 537 | OverlayControl.BUTTON_STICK_R.id -> { |
| 547 | R.drawable.facebutton_screenshot_depressed, | 538 | overlayButtons.add( |
| 548 | ButtonType.BUTTON_CAPTURE, | 539 | initializeOverlayButton( |
| 549 | Settings.PREF_BUTTON_SCREENSHOT, | 540 | context, |
| 550 | layout | 541 | windowSize, |
| 551 | ) | 542 | R.drawable.button_r3, |
| 552 | ) | 543 | R.drawable.button_r3_depressed, |
| 553 | } | 544 | ButtonType.STICK_R, |
| 554 | if (preferences.getBoolean(Settings.PREF_BUTTON_STICK_L, true)) { | 545 | data, |
| 555 | overlayButtons.add( | 546 | position |
| 556 | initializeOverlayButton( | 547 | ) |
| 557 | context, | 548 | ) |
| 558 | windowSize, | 549 | } |
| 559 | R.drawable.button_l3, | 550 | |
| 560 | R.drawable.button_l3_depressed, | 551 | OverlayControl.STICK_L.id -> { |
| 561 | ButtonType.STICK_L, | 552 | overlayJoysticks.add( |
| 562 | Settings.PREF_BUTTON_STICK_L, | 553 | initializeOverlayJoystick( |
| 563 | layout | 554 | context, |
| 564 | ) | 555 | windowSize, |
| 565 | ) | 556 | R.drawable.joystick_range, |
| 566 | } | 557 | R.drawable.joystick, |
| 567 | if (preferences.getBoolean(Settings.PREF_BUTTON_STICK_R, true)) { | 558 | R.drawable.joystick_depressed, |
| 568 | overlayButtons.add( | 559 | StickType.STICK_L, |
| 569 | initializeOverlayButton( | 560 | ButtonType.STICK_L, |
| 570 | context, | 561 | data, |
| 571 | windowSize, | 562 | position |
| 572 | R.drawable.button_r3, | 563 | ) |
| 573 | R.drawable.button_r3_depressed, | 564 | ) |
| 574 | ButtonType.STICK_R, | 565 | } |
| 575 | Settings.PREF_BUTTON_STICK_R, | 566 | |
| 576 | layout | 567 | OverlayControl.STICK_R.id -> { |
| 577 | ) | 568 | overlayJoysticks.add( |
| 578 | ) | 569 | initializeOverlayJoystick( |
| 570 | context, | ||
| 571 | windowSize, | ||
| 572 | R.drawable.joystick_range, | ||
| 573 | R.drawable.joystick, | ||
| 574 | R.drawable.joystick_depressed, | ||
| 575 | StickType.STICK_R, | ||
| 576 | ButtonType.STICK_R, | ||
| 577 | data, | ||
| 578 | position | ||
| 579 | ) | ||
| 580 | ) | ||
| 581 | } | ||
| 582 | |||
| 583 | OverlayControl.COMBINED_DPAD.id -> { | ||
| 584 | overlayDpads.add( | ||
| 585 | initializeOverlayDpad( | ||
| 586 | context, | ||
| 587 | windowSize, | ||
| 588 | R.drawable.dpad_standard, | ||
| 589 | R.drawable.dpad_standard_cardinal_depressed, | ||
| 590 | R.drawable.dpad_standard_diagonal_depressed, | ||
| 591 | position | ||
| 592 | ) | ||
| 593 | ) | ||
| 594 | } | ||
| 595 | } | ||
| 579 | } | 596 | } |
| 580 | } | 597 | } |
| 581 | 598 | ||
| @@ -586,313 +603,87 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 586 | overlayJoysticks.clear() | 603 | overlayJoysticks.clear() |
| 587 | 604 | ||
| 588 | // Add all the enabled overlay items back to the HashSet. | 605 | // Add all the enabled overlay items back to the HashSet. |
| 589 | if (EmulationMenuSettings.showOverlay) { | 606 | if (BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()) { |
| 590 | addOverlayControls(layout) | 607 | addOverlayControls(layout) |
| 591 | } | 608 | } |
| 592 | invalidate() | 609 | invalidate() |
| 593 | } | 610 | } |
| 594 | 611 | ||
| 595 | private fun saveControlPosition(prefId: String, x: Int, y: Int, layout: String) { | 612 | private fun saveControlPosition(id: String, x: Int, y: Int, layout: OverlayLayout) { |
| 596 | val windowSize = getSafeScreenSize(context, Pair(measuredWidth, measuredHeight)) | 613 | val windowSize = getSafeScreenSize(context, Pair(measuredWidth, measuredHeight)) |
| 597 | val min = windowSize.first | 614 | val min = windowSize.first |
| 598 | val max = windowSize.second | 615 | val max = windowSize.second |
| 599 | PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext).edit() | 616 | val overlayControlData = NativeConfig.getOverlayControlData() |
| 600 | .putFloat("$prefId-X$layout", (x - min.x).toFloat() / max.x) | 617 | val data = overlayControlData.firstOrNull { it.id == id } |
| 601 | .putFloat("$prefId-Y$layout", (y - min.y).toFloat() / max.y) | 618 | val newPosition = Pair((x - min.x).toDouble() / max.x, (y - min.y).toDouble() / max.y) |
| 602 | .apply() | 619 | when (layout) { |
| 620 | OverlayLayout.Landscape -> data?.landscapePosition = newPosition | ||
| 621 | OverlayLayout.Portrait -> data?.portraitPosition = newPosition | ||
| 622 | OverlayLayout.Foldable -> data?.foldablePosition = newPosition | ||
| 623 | } | ||
| 624 | NativeConfig.setOverlayControlData(overlayControlData) | ||
| 603 | } | 625 | } |
| 604 | 626 | ||
| 605 | fun setIsInEditMode(editMode: Boolean) { | 627 | fun setIsInEditMode(editMode: Boolean) { |
| 606 | inEditMode = editMode | 628 | inEditMode = editMode |
| 607 | } | 629 | } |
| 608 | 630 | ||
| 609 | private fun resetCurrentLayout() { | 631 | /** |
| 610 | defaultOverlayByLayout(layout) | 632 | * Applies and saves all default values for the overlay |
| 611 | val layoutIndex = overlayLayouts.indexOf(layout) | 633 | */ |
| 612 | preferences.edit() | 634 | private fun populateDefaultConfig() { |
| 613 | .putInt(Settings.overlayLayoutPrefs[layoutIndex], overlayLayoutVersions[layoutIndex]) | 635 | val newConfig = OverlayControl.entries.map { it.toOverlayControlData() } |
| 614 | .apply() | 636 | NativeConfig.setOverlayControlData(newConfig.toTypedArray()) |
| 637 | NativeConfig.saveGlobalConfig() | ||
| 615 | } | 638 | } |
| 616 | 639 | ||
| 617 | private fun resetAllLayouts() { | 640 | /** |
| 618 | val editor = preferences.edit() | 641 | * Checks if any new controls were added to OverlayControl that do not exist within deserialized |
| 619 | overlayLayouts.forEachIndexed { i, layout -> | 642 | * config and adds / saves them if necessary |
| 620 | defaultOverlayByLayout(layout) | 643 | * |
| 621 | editor.putInt(Settings.overlayLayoutPrefs[i], overlayLayoutVersions[i]) | 644 | * @param overlayControlData Overlay control data from [NativeConfig.getOverlayControlData] |
| 645 | */ | ||
| 646 | private fun checkForNewControls(overlayControlData: Array<OverlayControlData>) { | ||
| 647 | val missingControls = mutableListOf<OverlayControlData>() | ||
| 648 | OverlayControl.entries.forEach { defaultControl -> | ||
| 649 | val controlData = overlayControlData.firstOrNull { it.id == defaultControl.id } | ||
| 650 | if (controlData == null) { | ||
| 651 | missingControls.add(defaultControl.toOverlayControlData()) | ||
| 652 | } | ||
| 653 | } | ||
| 654 | |||
| 655 | if (missingControls.isNotEmpty()) { | ||
| 656 | NativeConfig.setOverlayControlData( | ||
| 657 | arrayOf(*overlayControlData, *(missingControls.toTypedArray())) | ||
| 658 | ) | ||
| 659 | NativeConfig.saveGlobalConfig() | ||
| 622 | } | 660 | } |
| 623 | editor.putInt(Settings.PREF_OVERLAY_VERSION, OVERLAY_VERSION) | ||
| 624 | editor.apply() | ||
| 625 | } | 661 | } |
| 626 | 662 | ||
| 627 | fun resetLayoutVisibilityAndPlacement() { | 663 | fun resetLayoutVisibilityAndPlacement() { |
| 628 | defaultOverlayByLayout(layout) | 664 | defaultOverlayPositionByLayout(layout) |
| 629 | val editor = preferences.edit() | 665 | |
| 630 | Settings.overlayPreferences.forEachIndexed { _, pref -> | 666 | val overlayControlData = NativeConfig.getOverlayControlData() |
| 631 | editor.remove(pref) | 667 | overlayControlData.forEach { |
| 668 | it.enabled = OverlayControl.from(it.id)?.defaultVisibility == false | ||
| 632 | } | 669 | } |
| 633 | editor.apply() | 670 | NativeConfig.setOverlayControlData(overlayControlData) |
| 671 | |||
| 634 | refreshControls() | 672 | refreshControls() |
| 635 | } | 673 | } |
| 636 | 674 | ||
| 637 | private val landscapeResources = arrayOf( | 675 | private fun defaultOverlayPositionByLayout(layout: OverlayLayout) { |
| 638 | R.integer.SWITCH_BUTTON_A_X, | 676 | val overlayControlData = NativeConfig.getOverlayControlData() |
| 639 | R.integer.SWITCH_BUTTON_A_Y, | 677 | for (data in overlayControlData) { |
| 640 | R.integer.SWITCH_BUTTON_B_X, | 678 | val defaultControlData = OverlayControl.from(data.id) ?: continue |
| 641 | R.integer.SWITCH_BUTTON_B_Y, | 679 | val position = defaultControlData.getDefaultPositionForLayout(layout) |
| 642 | R.integer.SWITCH_BUTTON_X_X, | 680 | when (layout) { |
| 643 | R.integer.SWITCH_BUTTON_X_Y, | 681 | OverlayLayout.Landscape -> data.landscapePosition = position |
| 644 | R.integer.SWITCH_BUTTON_Y_X, | 682 | OverlayLayout.Portrait -> data.portraitPosition = position |
| 645 | R.integer.SWITCH_BUTTON_Y_Y, | 683 | OverlayLayout.Foldable -> data.foldablePosition = position |
| 646 | R.integer.SWITCH_TRIGGER_ZL_X, | 684 | } |
| 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 | } | 685 | } |
| 754 | } | 686 | 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 | } | 687 | } |
| 897 | 688 | ||
| 898 | override fun isInEditMode(): Boolean { | 689 | override fun isInEditMode(): Boolean { |
| @@ -913,18 +704,6 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 913 | FOLDABLE_OVERLAY_VERSION | 704 | FOLDABLE_OVERLAY_VERSION |
| 914 | ) | 705 | ) |
| 915 | 706 | ||
| 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 | /** | 707 | /** |
| 929 | * Resizes a [Bitmap] by a given scale factor | 708 | * Resizes a [Bitmap] by a given scale factor |
| 930 | * | 709 | * |
| @@ -1036,29 +815,19 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1036 | * In the input overlay configuration menu, | 815 | * 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). | 816 | * 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 | 817 | * 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 | 818 | * (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 | * | 819 | * |
| 1051 | * Technically no modifications should need to be performed on the returned | 820 | * Technically no modifications should need to be performed on the returned |
| 1052 | * InputOverlayDrawableButton. Simply add it to the HashSet of overlay items and wait | 821 | * InputOverlayDrawableButton. Simply add it to the HashSet of overlay items and wait |
| 1053 | * for Android to call the onDraw method. | 822 | * for Android to call the onDraw method. |
| 1054 | * | 823 | * |
| 1055 | * @param context The current [Context]. | 824 | * @param context The current [Context]. |
| 1056 | * @param windowSize The size of the window to draw the overlay on. | 825 | * @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). | 826 | * @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). | 827 | * @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. | 828 | * @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. | 829 | * @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]. | 830 | * @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. | 831 | * @return An [InputOverlayDrawableButton] with the correct drawing bounds set. |
| 1063 | */ | 832 | */ |
| 1064 | private fun initializeOverlayButton( | 833 | private fun initializeOverlayButton( |
| @@ -1067,33 +836,30 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1067 | defaultResId: Int, | 836 | defaultResId: Int, |
| 1068 | pressedResId: Int, | 837 | pressedResId: Int, |
| 1069 | buttonId: Int, | 838 | buttonId: Int, |
| 1070 | prefId: String, | 839 | overlayControlData: OverlayControlData, |
| 1071 | layout: String | 840 | position: Pair<Double, Double> |
| 1072 | ): InputOverlayDrawableButton { | 841 | ): InputOverlayDrawableButton { |
| 1073 | // Resources handle for fetching the initial Drawable resource. | 842 | // Resources handle for fetching the initial Drawable resource. |
| 1074 | val res = context.resources | 843 | val res = context.resources |
| 1075 | 844 | ||
| 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 | 845 | // Decide scale based on button preference ID and user preference |
| 1080 | var scale: Float = when (prefId) { | 846 | var scale: Float = when (overlayControlData.id) { |
| 1081 | Settings.PREF_BUTTON_HOME, | 847 | OverlayControl.BUTTON_HOME.id, |
| 1082 | Settings.PREF_BUTTON_SCREENSHOT, | 848 | OverlayControl.BUTTON_CAPTURE.id, |
| 1083 | Settings.PREF_BUTTON_PLUS, | 849 | OverlayControl.BUTTON_PLUS.id, |
| 1084 | Settings.PREF_BUTTON_MINUS -> 0.07f | 850 | OverlayControl.BUTTON_MINUS.id -> 0.07f |
| 1085 | 851 | ||
| 1086 | Settings.PREF_BUTTON_L, | 852 | OverlayControl.BUTTON_L.id, |
| 1087 | Settings.PREF_BUTTON_R, | 853 | OverlayControl.BUTTON_R.id, |
| 1088 | Settings.PREF_BUTTON_ZL, | 854 | OverlayControl.BUTTON_ZL.id, |
| 1089 | Settings.PREF_BUTTON_ZR -> 0.26f | 855 | OverlayControl.BUTTON_ZR.id -> 0.26f |
| 1090 | 856 | ||
| 1091 | Settings.PREF_BUTTON_STICK_L, | 857 | OverlayControl.BUTTON_STICK_L.id, |
| 1092 | Settings.PREF_BUTTON_STICK_R -> 0.155f | 858 | OverlayControl.BUTTON_STICK_R.id -> 0.155f |
| 1093 | 859 | ||
| 1094 | else -> 0.11f | 860 | else -> 0.11f |
| 1095 | } | 861 | } |
| 1096 | scale *= (sPrefs.getInt(Settings.PREF_CONTROL_SCALE, 50) + 50).toFloat() | 862 | scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat() |
| 1097 | scale /= 100f | 863 | scale /= 100f |
| 1098 | 864 | ||
| 1099 | // Initialize the InputOverlayDrawableButton. | 865 | // Initialize the InputOverlayDrawableButton. |
| @@ -1104,7 +870,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1104 | defaultStateBitmap, | 870 | defaultStateBitmap, |
| 1105 | pressedStateBitmap, | 871 | pressedStateBitmap, |
| 1106 | buttonId, | 872 | buttonId, |
| 1107 | prefId | 873 | overlayControlData |
| 1108 | ) | 874 | ) |
| 1109 | 875 | ||
| 1110 | // Get the minimum and maximum coordinates of the screen where the button can be placed. | 876 | // Get the minimum and maximum coordinates of the screen where the button can be placed. |
| @@ -1113,12 +879,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1113 | 879 | ||
| 1114 | // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. | 880 | // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. |
| 1115 | // These were set in the input overlay configuration menu. | 881 | // These were set in the input overlay configuration menu. |
| 1116 | val xKey = "$prefId-X$layout" | 882 | val drawableX = (position.first * max.x + min.x).toInt() |
| 1117 | val yKey = "$prefId-Y$layout" | 883 | 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 | 884 | val width = overlayDrawable.width |
| 1123 | val height = overlayDrawable.height | 885 | val height = overlayDrawable.height |
| 1124 | 886 | ||
| @@ -1136,8 +898,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1136 | drawableX - (width / 2), | 898 | drawableX - (width / 2), |
| 1137 | drawableY - (height / 2) | 899 | drawableY - (height / 2) |
| 1138 | ) | 900 | ) |
| 1139 | val savedOpacity = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100) | 901 | overlayDrawable.setOpacity(IntSetting.OVERLAY_OPACITY.getInt() * 255 / 100) |
| 1140 | overlayDrawable.setOpacity(savedOpacity * 255 / 100) | ||
| 1141 | return overlayDrawable | 902 | return overlayDrawable |
| 1142 | } | 903 | } |
| 1143 | 904 | ||
| @@ -1149,7 +910,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1149 | * @param defaultResId The [Bitmap] resource ID of the default state. | 910 | * @param defaultResId The [Bitmap] resource ID of the default state. |
| 1150 | * @param pressedOneDirectionResId The [Bitmap] resource ID of the pressed state in one direction. | 911 | * @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. | 912 | * @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]. | 913 | * @param position The position on screen as represented by an x and y value between 0 and 1. |
| 1153 | * @return The initialized [InputOverlayDrawableDpad] | 914 | * @return The initialized [InputOverlayDrawableDpad] |
| 1154 | */ | 915 | */ |
| 1155 | private fun initializeOverlayDpad( | 916 | private fun initializeOverlayDpad( |
| @@ -1158,17 +919,14 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1158 | defaultResId: Int, | 919 | defaultResId: Int, |
| 1159 | pressedOneDirectionResId: Int, | 920 | pressedOneDirectionResId: Int, |
| 1160 | pressedTwoDirectionsResId: Int, | 921 | pressedTwoDirectionsResId: Int, |
| 1161 | layout: String | 922 | position: Pair<Double, Double> |
| 1162 | ): InputOverlayDrawableDpad { | 923 | ): InputOverlayDrawableDpad { |
| 1163 | // Resources handle for fetching the initial Drawable resource. | 924 | // Resources handle for fetching the initial Drawable resource. |
| 1164 | val res = context.resources | 925 | val res = context.resources |
| 1165 | 926 | ||
| 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 | 927 | // Decide scale based on button ID and user preference |
| 1170 | var scale = 0.25f | 928 | var scale = 0.25f |
| 1171 | scale *= (sPrefs.getInt(Settings.PREF_CONTROL_SCALE, 50) + 50).toFloat() | 929 | scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat() |
| 1172 | scale /= 100f | 930 | scale /= 100f |
| 1173 | 931 | ||
| 1174 | // Initialize the InputOverlayDrawableDpad. | 932 | // Initialize the InputOverlayDrawableDpad. |
| @@ -1195,10 +953,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1195 | 953 | ||
| 1196 | // The X and Y coordinates of the InputOverlayDrawableDpad on the InputOverlay. | 954 | // The X and Y coordinates of the InputOverlayDrawableDpad on the InputOverlay. |
| 1197 | // These were set in the input overlay configuration menu. | 955 | // These were set in the input overlay configuration menu. |
| 1198 | val drawableXPercent = sPrefs.getFloat("${Settings.PREF_BUTTON_DPAD}-X$layout", 0f) | 956 | val drawableX = (position.first * max.x + min.x).toInt() |
| 1199 | val drawableYPercent = sPrefs.getFloat("${Settings.PREF_BUTTON_DPAD}-Y$layout", 0f) | 957 | 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 | 958 | val width = overlayDrawable.width |
| 1203 | val height = overlayDrawable.height | 959 | val height = overlayDrawable.height |
| 1204 | 960 | ||
| @@ -1213,8 +969,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1213 | 969 | ||
| 1214 | // Need to set the image's position | 970 | // Need to set the image's position |
| 1215 | overlayDrawable.setPosition(drawableX - (width / 2), drawableY - (height / 2)) | 971 | overlayDrawable.setPosition(drawableX - (width / 2), drawableY - (height / 2)) |
| 1216 | val savedOpacity = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100) | 972 | overlayDrawable.setOpacity(IntSetting.OVERLAY_OPACITY.getInt() * 255 / 100) |
| 1217 | overlayDrawable.setOpacity(savedOpacity * 255 / 100) | ||
| 1218 | return overlayDrawable | 973 | return overlayDrawable |
| 1219 | } | 974 | } |
| 1220 | 975 | ||
| @@ -1227,9 +982,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). | 982 | * @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. | 983 | * @param pressedResInner Resource ID for the pressed inner image of the joystick. |
| 1229 | * @param joystick Identifier for which joystick this is. | 984 | * @param joystick Identifier for which joystick this is. |
| 1230 | * @param button Identifier for which joystick button this is. | 985 | * @param buttonId Identifier for which joystick button this is. |
| 1231 | * @param prefId Identifier for determining where a button appears on screen. | 986 | * @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]. | 987 | * @param position The position on screen as represented by an x and y value between 0 and 1. |
| 1233 | * @return The initialized [InputOverlayDrawableJoystick]. | 988 | * @return The initialized [InputOverlayDrawableJoystick]. |
| 1234 | */ | 989 | */ |
| 1235 | private fun initializeOverlayJoystick( | 990 | private fun initializeOverlayJoystick( |
| @@ -1239,19 +994,16 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1239 | defaultResInner: Int, | 994 | defaultResInner: Int, |
| 1240 | pressedResInner: Int, | 995 | pressedResInner: Int, |
| 1241 | joystick: Int, | 996 | joystick: Int, |
| 1242 | button: Int, | 997 | buttonId: Int, |
| 1243 | prefId: String, | 998 | overlayControlData: OverlayControlData, |
| 1244 | layout: String | 999 | position: Pair<Double, Double> |
| 1245 | ): InputOverlayDrawableJoystick { | 1000 | ): InputOverlayDrawableJoystick { |
| 1246 | // Resources handle for fetching the initial Drawable resource. | 1001 | // Resources handle for fetching the initial Drawable resource. |
| 1247 | val res = context.resources | 1002 | val res = context.resources |
| 1248 | 1003 | ||
| 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 | 1004 | // Decide scale based on user preference |
| 1253 | var scale = 0.3f | 1005 | var scale = 0.3f |
| 1254 | scale *= (sPrefs.getInt(Settings.PREF_CONTROL_SCALE, 50) + 50).toFloat() | 1006 | scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat() |
| 1255 | scale /= 100f | 1007 | scale /= 100f |
| 1256 | 1008 | ||
| 1257 | // Initialize the InputOverlayDrawableJoystick. | 1009 | // Initialize the InputOverlayDrawableJoystick. |
| @@ -1265,10 +1017,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1265 | 1017 | ||
| 1266 | // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. | 1018 | // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. |
| 1267 | // These were set in the input overlay configuration menu. | 1019 | // These were set in the input overlay configuration menu. |
| 1268 | val drawableXPercent = sPrefs.getFloat("$prefId-X$layout", 0f) | 1020 | val drawableX = (position.first * max.x + min.x).toInt() |
| 1269 | val drawableYPercent = sPrefs.getFloat("$prefId-Y$layout", 0f) | 1021 | 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 | 1022 | val outerScale = 1.66f |
| 1273 | 1023 | ||
| 1274 | // Now set the bounds for the InputOverlayDrawableJoystick. | 1024 | // Now set the bounds for the InputOverlayDrawableJoystick. |
| @@ -1292,14 +1042,13 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1292 | outerRect, | 1042 | outerRect, |
| 1293 | innerRect, | 1043 | innerRect, |
| 1294 | joystick, | 1044 | joystick, |
| 1295 | button, | 1045 | buttonId, |
| 1296 | prefId | 1046 | overlayControlData.id |
| 1297 | ) | 1047 | ) |
| 1298 | 1048 | ||
| 1299 | // Need to set the image's position | 1049 | // Need to set the image's position |
| 1300 | overlayDrawable.setPosition(drawableX, drawableY) | 1050 | overlayDrawable.setPosition(drawableX, drawableY) |
| 1301 | val savedOpacity = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100) | 1051 | overlayDrawable.setOpacity(IntSetting.OVERLAY_OPACITY.getInt() * 255 / 100) |
| 1302 | overlayDrawable.setOpacity(savedOpacity * 255 / 100) | ||
| 1303 | return overlayDrawable | 1052 | return overlayDrawable |
| 1304 | } | 1053 | } |
| 1305 | } | 1054 | } |
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/ui/GamesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt index fc0eeb9ad..54380323e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt | |||
| @@ -91,18 +91,20 @@ class GamesFragment : Fragment() { | |||
| 91 | viewLifecycleOwner.lifecycleScope.apply { | 91 | viewLifecycleOwner.lifecycleScope.apply { |
| 92 | launch { | 92 | launch { |
| 93 | repeatOnLifecycle(Lifecycle.State.RESUMED) { | 93 | repeatOnLifecycle(Lifecycle.State.RESUMED) { |
| 94 | gamesViewModel.isReloading.collect { binding.swipeRefresh.isRefreshing = it } | 94 | gamesViewModel.isReloading.collect { |
| 95 | binding.swipeRefresh.isRefreshing = it | ||
| 96 | if (gamesViewModel.games.value.isEmpty() && !it) { | ||
| 97 | binding.noticeText.visibility = View.VISIBLE | ||
| 98 | } else { | ||
| 99 | binding.noticeText.visibility = View.INVISIBLE | ||
| 100 | } | ||
| 101 | } | ||
| 95 | } | 102 | } |
| 96 | } | 103 | } |
| 97 | launch { | 104 | launch { |
| 98 | repeatOnLifecycle(Lifecycle.State.RESUMED) { | 105 | repeatOnLifecycle(Lifecycle.State.RESUMED) { |
| 99 | gamesViewModel.games.collectLatest { | 106 | gamesViewModel.games.collectLatest { |
| 100 | (binding.gridGames.adapter as GameAdapter).submitList(it) | 107 | (binding.gridGames.adapter as GameAdapter).submitList(it) |
| 101 | if (it.isEmpty()) { | ||
| 102 | binding.noticeText.visibility = View.VISIBLE | ||
| 103 | } else { | ||
| 104 | binding.noticeText.visibility = View.GONE | ||
| 105 | } | ||
| 106 | } | 108 | } |
| 107 | } | 109 | } |
| 108 | } | 110 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index b4117d761..622ae996e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt | |||
| @@ -625,7 +625,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 625 | File(DirectoryInitialization.userDirectory!!), | 625 | File(DirectoryInitialization.userDirectory!!), |
| 626 | DirectoryInitialization.userDirectory!!, | 626 | DirectoryInitialization.userDirectory!!, |
| 627 | BufferedOutputStream(contentResolver.openOutputStream(result)), | 627 | BufferedOutputStream(contentResolver.openOutputStream(result)), |
| 628 | taskViewModel.cancelled | 628 | taskViewModel.cancelled, |
| 629 | compression = false | ||
| 629 | ) | 630 | ) |
| 630 | return@newInstance when (zipResult) { | 631 | return@newInstance when (zipResult) { |
| 631 | TaskState.Completed -> getString(R.string.user_data_export_success) | 632 | TaskState.Completed -> getString(R.string.user_data_export_success) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt index 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/FileUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt index 00c6bf90e..132f002fb 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt | |||
| @@ -21,6 +21,7 @@ import org.yuzu.yuzu_emu.model.TaskState | |||
| 21 | import java.io.BufferedOutputStream | 21 | import java.io.BufferedOutputStream |
| 22 | import java.lang.NullPointerException | 22 | import java.lang.NullPointerException |
| 23 | import java.nio.charset.StandardCharsets | 23 | import java.nio.charset.StandardCharsets |
| 24 | import java.util.zip.Deflater | ||
| 24 | import java.util.zip.ZipOutputStream | 25 | import java.util.zip.ZipOutputStream |
| 25 | import kotlin.IllegalStateException | 26 | import kotlin.IllegalStateException |
| 26 | 27 | ||
| @@ -312,15 +313,23 @@ object FileUtil { | |||
| 312 | * @param inputFile File representation of the item that will be zipped | 313 | * @param inputFile File representation of the item that will be zipped |
| 313 | * @param rootDir Directory containing the inputFile | 314 | * @param rootDir Directory containing the inputFile |
| 314 | * @param outputStream Stream where the zip file will be output | 315 | * @param outputStream Stream where the zip file will be output |
| 316 | * @param cancelled [StateFlow] that reports whether this process has been cancelled | ||
| 317 | * @param compression Disables compression if true | ||
| 315 | */ | 318 | */ |
| 316 | fun zipFromInternalStorage( | 319 | fun zipFromInternalStorage( |
| 317 | inputFile: File, | 320 | inputFile: File, |
| 318 | rootDir: String, | 321 | rootDir: String, |
| 319 | outputStream: BufferedOutputStream, | 322 | outputStream: BufferedOutputStream, |
| 320 | cancelled: StateFlow<Boolean>? = null | 323 | cancelled: StateFlow<Boolean>? = null, |
| 324 | compression: Boolean = true | ||
| 321 | ): TaskState { | 325 | ): TaskState { |
| 322 | try { | 326 | try { |
| 323 | ZipOutputStream(outputStream).use { zos -> | 327 | ZipOutputStream(outputStream).use { zos -> |
| 328 | if (!compression) { | ||
| 329 | zos.setMethod(ZipOutputStream.DEFLATED) | ||
| 330 | zos.setLevel(Deflater.NO_COMPRESSION) | ||
| 331 | } | ||
| 332 | |||
| 324 | inputFile.walkTopDown().forEach { file -> | 333 | inputFile.walkTopDown().forEach { file -> |
| 325 | if (cancelled?.value == true) { | 334 | if (cancelled?.value == true) { |
| 326 | return TaskState.Cancelled | 335 | return TaskState.Cancelled |
| @@ -338,6 +347,7 @@ object FileUtil { | |||
| 338 | } | 347 | } |
| 339 | } | 348 | } |
| 340 | } catch (e: Exception) { | 349 | } catch (e: Exception) { |
| 350 | Log.error("[FileUtil] Failed creating zip file - ${e.message}") | ||
| 341 | return TaskState.Failed | 351 | return TaskState.Failed |
| 342 | } | 352 | } |
| 343 | return TaskState.Completed | 353 | return TaskState.Completed |
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..08aed3216 100644 --- a/src/android/app/src/main/jni/android_config.cpp +++ b/src/android/app/src/main/jni/android_config.cpp | |||
| @@ -14,12 +14,6 @@ AndroidConfig::AndroidConfig(const std::string& config_name, ConfigType config_t | |||
| 14 | } | 14 | } |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | AndroidConfig::~AndroidConfig() { | ||
| 18 | if (global) { | ||
| 19 | AndroidConfig::SaveAllValues(); | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | void AndroidConfig::ReloadAllValues() { | 17 | void AndroidConfig::ReloadAllValues() { |
| 24 | Reload(); | 18 | Reload(); |
| 25 | ReadAndroidValues(); | 19 | ReadAndroidValues(); |
| @@ -35,6 +29,7 @@ void AndroidConfig::ReadAndroidValues() { | |||
| 35 | if (global) { | 29 | if (global) { |
| 36 | ReadAndroidUIValues(); | 30 | ReadAndroidUIValues(); |
| 37 | ReadUIValues(); | 31 | ReadUIValues(); |
| 32 | ReadOverlayValues(); | ||
| 38 | } | 33 | } |
| 39 | ReadDriverValues(); | 34 | ReadDriverValues(); |
| 40 | } | 35 | } |
| @@ -81,10 +76,42 @@ void AndroidConfig::ReadDriverValues() { | |||
| 81 | EndGroup(); | 76 | EndGroup(); |
| 82 | } | 77 | } |
| 83 | 78 | ||
| 79 | void AndroidConfig::ReadOverlayValues() { | ||
| 80 | BeginGroup(Settings::TranslateCategory(Settings::Category::Overlay)); | ||
| 81 | |||
| 82 | ReadCategory(Settings::Category::Overlay); | ||
| 83 | |||
| 84 | AndroidSettings::values.overlay_control_data.clear(); | ||
| 85 | const int control_data_size = BeginArray("control_data"); | ||
| 86 | for (int i = 0; i < control_data_size; ++i) { | ||
| 87 | SetArrayIndex(i); | ||
| 88 | AndroidSettings::OverlayControlData control_data; | ||
| 89 | control_data.id = ReadStringSetting(std::string("id")); | ||
| 90 | control_data.enabled = ReadBooleanSetting(std::string("enabled")); | ||
| 91 | control_data.landscape_position.first = | ||
| 92 | ReadDoubleSetting(std::string("landscape\\x_position")); | ||
| 93 | control_data.landscape_position.second = | ||
| 94 | ReadDoubleSetting(std::string("landscape\\y_position")); | ||
| 95 | control_data.portrait_position.first = | ||
| 96 | ReadDoubleSetting(std::string("portrait\\x_position")); | ||
| 97 | control_data.portrait_position.second = | ||
| 98 | ReadDoubleSetting(std::string("portrait\\y_position")); | ||
| 99 | control_data.foldable_position.first = | ||
| 100 | ReadDoubleSetting(std::string("foldable\\x_position")); | ||
| 101 | control_data.foldable_position.second = | ||
| 102 | ReadDoubleSetting(std::string("foldable\\y_position")); | ||
| 103 | AndroidSettings::values.overlay_control_data.push_back(control_data); | ||
| 104 | } | ||
| 105 | EndArray(); | ||
| 106 | |||
| 107 | EndGroup(); | ||
| 108 | } | ||
| 109 | |||
| 84 | void AndroidConfig::SaveAndroidValues() { | 110 | void AndroidConfig::SaveAndroidValues() { |
| 85 | if (global) { | 111 | if (global) { |
| 86 | SaveAndroidUIValues(); | 112 | SaveAndroidUIValues(); |
| 87 | SaveUIValues(); | 113 | SaveUIValues(); |
| 114 | SaveOverlayValues(); | ||
| 88 | } | 115 | } |
| 89 | SaveDriverValues(); | 116 | SaveDriverValues(); |
| 90 | 117 | ||
| @@ -114,8 +141,9 @@ void AndroidConfig::SavePathValues() { | |||
| 114 | for (size_t i = 0; i < AndroidSettings::values.game_dirs.size(); ++i) { | 141 | for (size_t i = 0; i < AndroidSettings::values.game_dirs.size(); ++i) { |
| 115 | SetArrayIndex(i); | 142 | SetArrayIndex(i); |
| 116 | const auto& game_dir = AndroidSettings::values.game_dirs[i]; | 143 | const auto& game_dir = AndroidSettings::values.game_dirs[i]; |
| 117 | WriteSetting(std::string("path"), game_dir.path); | 144 | WriteStringSetting(std::string("path"), game_dir.path); |
| 118 | WriteSetting(std::string("deep_scan"), game_dir.deep_scan, std::make_optional(false)); | 145 | WriteBooleanSetting(std::string("deep_scan"), game_dir.deep_scan, |
| 146 | std::make_optional(false)); | ||
| 119 | } | 147 | } |
| 120 | EndArray(); | 148 | EndArray(); |
| 121 | 149 | ||
| @@ -130,6 +158,35 @@ void AndroidConfig::SaveDriverValues() { | |||
| 130 | EndGroup(); | 158 | EndGroup(); |
| 131 | } | 159 | } |
| 132 | 160 | ||
| 161 | void AndroidConfig::SaveOverlayValues() { | ||
| 162 | BeginGroup(Settings::TranslateCategory(Settings::Category::Overlay)); | ||
| 163 | |||
| 164 | WriteCategory(Settings::Category::Overlay); | ||
| 165 | |||
| 166 | BeginArray("control_data"); | ||
| 167 | for (size_t i = 0; i < AndroidSettings::values.overlay_control_data.size(); ++i) { | ||
| 168 | SetArrayIndex(i); | ||
| 169 | const auto& control_data = AndroidSettings::values.overlay_control_data[i]; | ||
| 170 | WriteStringSetting(std::string("id"), control_data.id); | ||
| 171 | WriteBooleanSetting(std::string("enabled"), control_data.enabled); | ||
| 172 | WriteDoubleSetting(std::string("landscape\\x_position"), | ||
| 173 | control_data.landscape_position.first); | ||
| 174 | WriteDoubleSetting(std::string("landscape\\y_position"), | ||
| 175 | control_data.landscape_position.second); | ||
| 176 | WriteDoubleSetting(std::string("portrait\\x_position"), | ||
| 177 | control_data.portrait_position.first); | ||
| 178 | WriteDoubleSetting(std::string("portrait\\y_position"), | ||
| 179 | control_data.portrait_position.second); | ||
| 180 | WriteDoubleSetting(std::string("foldable\\x_position"), | ||
| 181 | control_data.foldable_position.first); | ||
| 182 | WriteDoubleSetting(std::string("foldable\\y_position"), | ||
| 183 | control_data.foldable_position.second); | ||
| 184 | } | ||
| 185 | EndArray(); | ||
| 186 | |||
| 187 | EndGroup(); | ||
| 188 | } | ||
| 189 | |||
| 133 | std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) { | 190 | std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) { |
| 134 | auto& map = Settings::values.linkage.by_category; | 191 | auto& map = Settings::values.linkage.by_category; |
| 135 | if (map.contains(category)) { | 192 | 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..693e1e3f0 100644 --- a/src/android/app/src/main/jni/android_config.h +++ b/src/android/app/src/main/jni/android_config.h | |||
| @@ -9,7 +9,6 @@ class AndroidConfig final : public Config { | |||
| 9 | public: | 9 | public: |
| 10 | explicit AndroidConfig(const std::string& config_name = "config", | 10 | explicit AndroidConfig(const std::string& config_name = "config", |
| 11 | ConfigType config_type = ConfigType::GlobalConfig); | 11 | ConfigType config_type = ConfigType::GlobalConfig); |
| 12 | ~AndroidConfig() override; | ||
| 13 | 12 | ||
| 14 | void ReloadAllValues() override; | 13 | void ReloadAllValues() override; |
| 15 | void SaveAllValues() override; | 14 | void SaveAllValues() override; |
| @@ -18,6 +17,7 @@ protected: | |||
| 18 | void ReadAndroidValues(); | 17 | void ReadAndroidValues(); |
| 19 | void ReadAndroidUIValues(); | 18 | void ReadAndroidUIValues(); |
| 20 | void ReadDriverValues(); | 19 | void ReadDriverValues(); |
| 20 | void ReadOverlayValues(); | ||
| 21 | void ReadHidbusValues() override {} | 21 | void ReadHidbusValues() override {} |
| 22 | void ReadDebugControlValues() override {} | 22 | void ReadDebugControlValues() override {} |
| 23 | void ReadPathValues() override; | 23 | void ReadPathValues() override; |
| @@ -30,6 +30,7 @@ protected: | |||
| 30 | void SaveAndroidValues(); | 30 | void SaveAndroidValues(); |
| 31 | void SaveAndroidUIValues(); | 31 | void SaveAndroidUIValues(); |
| 32 | void SaveDriverValues(); | 32 | void SaveDriverValues(); |
| 33 | void SaveOverlayValues(); | ||
| 33 | void SaveHidbusValues() override {} | 34 | void SaveHidbusValues() override {} |
| 34 | void SaveDebugControlValues() override {} | 35 | void SaveDebugControlValues() override {} |
| 35 | void SavePathValues() override; | 36 | 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/layout/list_item_setting_switch.xml b/src/android/app/src/main/res/layout/list_item_setting_switch.xml index 5cb84182e..1c08e2e1b 100644 --- a/src/android/app/src/main/res/layout/list_item_setting_switch.xml +++ b/src/android/app/src/main/res/layout/list_item_setting_switch.xml | |||
| @@ -24,7 +24,7 @@ | |||
| 24 | android:layout_width="0dp" | 24 | android:layout_width="0dp" |
| 25 | android:layout_height="wrap_content" | 25 | android:layout_height="wrap_content" |
| 26 | android:layout_marginEnd="24dp" | 26 | android:layout_marginEnd="24dp" |
| 27 | android:gravity="center_vertical" | 27 | android:layout_gravity="center_vertical" |
| 28 | android:orientation="vertical" | 28 | android:orientation="vertical" |
| 29 | android:layout_weight="1"> | 29 | android:layout_weight="1"> |
| 30 | 30 | ||
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 e3915ef4f..0363ff3b6 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml | |||
| @@ -118,15 +118,23 @@ | |||
| 118 | </integer-array> | 118 | </integer-array> |
| 119 | 119 | ||
| 120 | <string-array name="rendererScreenLayoutNames"> | 120 | <string-array name="rendererScreenLayoutNames"> |
| 121 | <item>@string/screen_layout_auto</item> | ||
| 122 | <item>@string/screen_layout_sensor_landscape</item> | ||
| 121 | <item>@string/screen_layout_landscape</item> | 123 | <item>@string/screen_layout_landscape</item> |
| 124 | <item>@string/screen_layout_reverse_landscape</item> | ||
| 125 | <item>@string/screen_layout_sensor_portrait</item> | ||
| 122 | <item>@string/screen_layout_portrait</item> | 126 | <item>@string/screen_layout_portrait</item> |
| 123 | <item>@string/screen_layout_auto</item> | 127 | <item>@string/screen_layout_reverse_portrait</item> |
| 124 | </string-array> | 128 | </string-array> |
| 125 | 129 | ||
| 126 | <integer-array name="rendererScreenLayoutValues"> | 130 | <integer-array name="rendererScreenLayoutValues"> |
| 131 | <item>0</item> | ||
| 127 | <item>5</item> | 132 | <item>5</item> |
| 133 | <item>1</item> | ||
| 134 | <item>2</item> | ||
| 135 | <item>6</item> | ||
| 128 | <item>4</item> | 136 | <item>4</item> |
| 129 | <item>0</item> | 137 | <item>3</item> |
| 130 | </integer-array> | 138 | </integer-array> |
| 131 | 139 | ||
| 132 | <string-array name="rendererAspectRatioNames"> | 140 | <string-array name="rendererAspectRatioNames"> |
| @@ -212,19 +220,19 @@ | |||
| 212 | <item>B</item> | 220 | <item>B</item> |
| 213 | <item>X</item> | 221 | <item>X</item> |
| 214 | <item>Y</item> | 222 | <item>Y</item> |
| 223 | <item>+</item> | ||
| 224 | <item>-</item> | ||
| 225 | <item>@string/gamepad_home</item> | ||
| 226 | <item>@string/gamepad_screenshot</item> | ||
| 215 | <item>L</item> | 227 | <item>L</item> |
| 216 | <item>R</item> | 228 | <item>R</item> |
| 217 | <item>ZL</item> | 229 | <item>ZL</item> |
| 218 | <item>ZR</item> | 230 | <item>ZR</item> |
| 219 | <item>+</item> | ||
| 220 | <item>-</item> | ||
| 221 | <item>@string/gamepad_d_pad</item> | ||
| 222 | <item>@string/gamepad_left_stick</item> | 231 | <item>@string/gamepad_left_stick</item> |
| 223 | <item>@string/gamepad_right_stick</item> | 232 | <item>@string/gamepad_right_stick</item> |
| 224 | <item>L3</item> | 233 | <item>L3</item> |
| 225 | <item>R3</item> | 234 | <item>R3</item> |
| 226 | <item>@string/gamepad_home</item> | 235 | <item>@string/gamepad_d_pad</item> |
| 227 | <item>@string/gamepad_screenshot</item> | ||
| 228 | </string-array> | 236 | </string-array> |
| 229 | 237 | ||
| 230 | <string-array name="themeEntries"> | 238 | <string-array name="themeEntries"> |
| @@ -267,4 +275,21 @@ | |||
| 267 | <item>3</item> | 275 | <item>3</item> |
| 268 | </integer-array> | 276 | </integer-array> |
| 269 | 277 | ||
| 278 | <string-array name="anisoEntries"> | ||
| 279 | <item>@string/auto</item> | ||
| 280 | <item>@string/slider_default</item> | ||
| 281 | <item>@string/multiplier_two</item> | ||
| 282 | <item>@string/multiplier_four</item> | ||
| 283 | <item>@string/multiplier_eight</item> | ||
| 284 | <item>@string/multiplier_sixteen</item> | ||
| 285 | </string-array> | ||
| 286 | <integer-array name="anisoValues"> | ||
| 287 | <item>0</item> | ||
| 288 | <item>1</item> | ||
| 289 | <item>2</item> | ||
| 290 | <item>3</item> | ||
| 291 | <item>4</item> | ||
| 292 | <item>5</item> | ||
| 293 | </integer-array> | ||
| 294 | |||
| 270 | </resources> | 295 | </resources> |
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 0b80b04a4..83aa1b781 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml | |||
| @@ -225,6 +225,8 @@ | |||
| 225 | <string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string> | 225 | <string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string> |
| 226 | <string name="use_disk_shader_cache">Disk shader cache</string> | 226 | <string name="use_disk_shader_cache">Disk shader cache</string> |
| 227 | <string name="use_disk_shader_cache_description">Reduces stuttering by locally storing and loading generated shaders.</string> | 227 | <string name="use_disk_shader_cache_description">Reduces stuttering by locally storing and loading generated shaders.</string> |
| 228 | <string name="anisotropic_filtering">Anisotropic filtering</string> | ||
| 229 | <string name="anisotropic_filtering_description">Improves the quality of textures when viewed at oblique angles</string> | ||
| 228 | 230 | ||
| 229 | <!-- Debug settings strings --> | 231 | <!-- Debug settings strings --> |
| 230 | <string name="cpu">CPU</string> | 232 | <string name="cpu">CPU</string> |
| @@ -364,6 +366,7 @@ | |||
| 364 | <string name="emulation_pause">Pause emulation</string> | 366 | <string name="emulation_pause">Pause emulation</string> |
| 365 | <string name="emulation_unpause">Unpause emulation</string> | 367 | <string name="emulation_unpause">Unpause emulation</string> |
| 366 | <string name="emulation_input_overlay">Overlay options</string> | 368 | <string name="emulation_input_overlay">Overlay options</string> |
| 369 | <string name="touchscreen">Touchscreen</string> | ||
| 367 | 370 | ||
| 368 | <string name="load_settings">Loading settings…</string> | 371 | <string name="load_settings">Loading settings…</string> |
| 369 | 372 | ||
| @@ -460,9 +463,13 @@ | |||
| 460 | <string name="anti_aliasing_smaa">SMAA</string> | 463 | <string name="anti_aliasing_smaa">SMAA</string> |
| 461 | 464 | ||
| 462 | <!-- Screen Layouts --> | 465 | <!-- Screen Layouts --> |
| 466 | <string name="screen_layout_auto">Auto</string> | ||
| 467 | <string name="screen_layout_sensor_landscape">Sensor landscape</string> | ||
| 463 | <string name="screen_layout_landscape">Landscape</string> | 468 | <string name="screen_layout_landscape">Landscape</string> |
| 469 | <string name="screen_layout_reverse_landscape">Reverse landscape</string> | ||
| 470 | <string name="screen_layout_sensor_portrait">Sensor portrait</string> | ||
| 464 | <string name="screen_layout_portrait">Portrait</string> | 471 | <string name="screen_layout_portrait">Portrait</string> |
| 465 | <string name="screen_layout_auto">Auto</string> | 472 | <string name="screen_layout_reverse_portrait">Reverse portrait</string> |
| 466 | 473 | ||
| 467 | <!-- Aspect Ratios --> | 474 | <!-- Aspect Ratios --> |
| 468 | <string name="ratio_default">Default (16:9)</string> | 475 | <string name="ratio_default">Default (16:9)</string> |
| @@ -506,6 +513,12 @@ | |||
| 506 | <string name="oboe">oboe</string> | 513 | <string name="oboe">oboe</string> |
| 507 | <string name="cubeb">cubeb</string> | 514 | <string name="cubeb">cubeb</string> |
| 508 | 515 | ||
| 516 | <!-- Anisotropic filtering options --> | ||
| 517 | <string name="multiplier_two">2x</string> | ||
| 518 | <string name="multiplier_four">4x</string> | ||
| 519 | <string name="multiplier_eight">8x</string> | ||
| 520 | <string name="multiplier_sixteen">16x</string> | ||
| 521 | |||
| 509 | <!-- Black backgrounds theme --> | 522 | <!-- Black backgrounds theme --> |
| 510 | <string name="use_black_backgrounds">Black backgrounds</string> | 523 | <string name="use_black_backgrounds">Black backgrounds</string> |
| 511 | <string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string> | 524 | <string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string> |
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/assert.cpp b/src/common/assert.cpp index 6026b7dc2..e2c2cade3 100644 --- a/src/common/assert.cpp +++ b/src/common/assert.cpp | |||
| @@ -3,16 +3,19 @@ | |||
| 3 | 3 | ||
| 4 | #include "common/assert.h" | 4 | #include "common/assert.h" |
| 5 | #include "common/common_funcs.h" | 5 | #include "common/common_funcs.h" |
| 6 | #include "common/logging/backend.h" | ||
| 6 | 7 | ||
| 7 | #include "common/settings.h" | 8 | #include "common/settings.h" |
| 8 | 9 | ||
| 9 | void assert_fail_impl() { | 10 | void assert_fail_impl() { |
| 10 | if (Settings::values.use_debug_asserts) { | 11 | if (Settings::values.use_debug_asserts) { |
| 12 | Common::Log::Stop(); | ||
| 11 | Crash(); | 13 | Crash(); |
| 12 | } | 14 | } |
| 13 | } | 15 | } |
| 14 | 16 | ||
| 15 | [[noreturn]] void unreachable_impl() { | 17 | [[noreturn]] void unreachable_impl() { |
| 18 | Common::Log::Stop(); | ||
| 16 | Crash(); | 19 | Crash(); |
| 17 | throw std::runtime_error("Unreachable code"); | 20 | throw std::runtime_error("Unreachable code"); |
| 18 | } | 21 | } |
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/logging/backend.cpp b/src/common/logging/backend.cpp index d4f27197c..7a267f8c0 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp | |||
| @@ -208,6 +208,10 @@ public: | |||
| 208 | instance->StartBackendThread(); | 208 | instance->StartBackendThread(); |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | static void Stop() { | ||
| 212 | instance->StopBackendThread(); | ||
| 213 | } | ||
| 214 | |||
| 211 | Impl(const Impl&) = delete; | 215 | Impl(const Impl&) = delete; |
| 212 | Impl& operator=(const Impl&) = delete; | 216 | Impl& operator=(const Impl&) = delete; |
| 213 | 217 | ||
| @@ -259,6 +263,15 @@ private: | |||
| 259 | }); | 263 | }); |
| 260 | } | 264 | } |
| 261 | 265 | ||
| 266 | void StopBackendThread() { | ||
| 267 | backend_thread.request_stop(); | ||
| 268 | if (backend_thread.joinable()) { | ||
| 269 | backend_thread.join(); | ||
| 270 | } | ||
| 271 | |||
| 272 | ForEachBackend([](Backend& backend) { backend.Flush(); }); | ||
| 273 | } | ||
| 274 | |||
| 262 | Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr, | 275 | Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr, |
| 263 | const char* function, std::string&& message) const { | 276 | const char* function, std::string&& message) const { |
| 264 | using std::chrono::duration_cast; | 277 | using std::chrono::duration_cast; |
| @@ -313,6 +326,10 @@ void Start() { | |||
| 313 | Impl::Start(); | 326 | Impl::Start(); |
| 314 | } | 327 | } |
| 315 | 328 | ||
| 329 | void Stop() { | ||
| 330 | Impl::Stop(); | ||
| 331 | } | ||
| 332 | |||
| 316 | void DisableLoggingInTests() { | 333 | void DisableLoggingInTests() { |
| 317 | initialization_in_progress_suppress_logging = true; | 334 | initialization_in_progress_suppress_logging = true; |
| 318 | } | 335 | } |
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h index 12e5e2498..2a9926e9e 100644 --- a/src/common/logging/backend.h +++ b/src/common/logging/backend.h | |||
| @@ -14,6 +14,9 @@ void Initialize(); | |||
| 14 | 14 | ||
| 15 | void Start(); | 15 | void Start(); |
| 16 | 16 | ||
| 17 | /// Explicitly stops the logger thread and flushes the buffers | ||
| 18 | void Stop(); | ||
| 19 | |||
| 17 | void DisableLoggingInTests(); | 20 | void DisableLoggingInTests(); |
| 18 | 21 | ||
| 19 | /** | 22 | /** |
diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h index 5c961b202..e7e9fdb38 100644 --- a/src/common/ring_buffer.h +++ b/src/common/ring_buffer.h | |||
| @@ -103,7 +103,7 @@ private: | |||
| 103 | // Having them on the same cache-line would result in false-sharing between them. | 103 | // Having them on the same cache-line would result in false-sharing between them. |
| 104 | // TODO: Remove this ifdef whenever clang and GCC support | 104 | // TODO: Remove this ifdef whenever clang and GCC support |
| 105 | // std::hardware_destructive_interference_size. | 105 | // std::hardware_destructive_interference_size. |
| 106 | #if defined(_MSC_VER) && _MSC_VER >= 1911 | 106 | #ifdef __cpp_lib_hardware_interference_size |
| 107 | alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0}; | 107 | alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0}; |
| 108 | alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0}; | 108 | alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0}; |
| 109 | #else | 109 | #else |
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..e2ec2164c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -549,21 +549,34 @@ add_library(core STATIC | |||
| 549 | hle/service/hid/xcd.cpp | 549 | hle/service/hid/xcd.cpp |
| 550 | hle/service/hid/xcd.h | 550 | hle/service/hid/xcd.h |
| 551 | hle/service/hid/errors.h | 551 | hle/service/hid/errors.h |
| 552 | hle/service/hid/controllers/npad/npad_data.cpp | ||
| 553 | hle/service/hid/controllers/npad/npad_data.h | ||
| 554 | hle/service/hid/controllers/npad/npad_resource.cpp | ||
| 555 | hle/service/hid/controllers/npad/npad_resource.h | ||
| 552 | hle/service/hid/controllers/types/debug_pad_types.h | 556 | hle/service/hid/controllers/types/debug_pad_types.h |
| 553 | hle/service/hid/controllers/types/keyboard_types.h | 557 | hle/service/hid/controllers/types/keyboard_types.h |
| 554 | hle/service/hid/controllers/types/mouse_types.h | 558 | hle/service/hid/controllers/types/mouse_types.h |
| 555 | hle/service/hid/controllers/types/npad_types.h | 559 | hle/service/hid/controllers/types/npad_types.h |
| 560 | hle/service/hid/controllers/types/shared_memory_format.h | ||
| 556 | hle/service/hid/controllers/types/touch_types.h | 561 | hle/service/hid/controllers/types/touch_types.h |
| 557 | hle/service/hid/controllers/applet_resource.cpp | 562 | hle/service/hid/controllers/applet_resource.cpp |
| 558 | hle/service/hid/controllers/applet_resource.h | 563 | hle/service/hid/controllers/applet_resource.h |
| 564 | hle/service/hid/controllers/capture_button.cpp | ||
| 565 | hle/service/hid/controllers/capture_button.h | ||
| 559 | hle/service/hid/controllers/console_six_axis.cpp | 566 | hle/service/hid/controllers/console_six_axis.cpp |
| 560 | hle/service/hid/controllers/console_six_axis.h | 567 | hle/service/hid/controllers/console_six_axis.h |
| 561 | hle/service/hid/controllers/controller_base.cpp | 568 | hle/service/hid/controllers/controller_base.cpp |
| 562 | hle/service/hid/controllers/controller_base.h | 569 | hle/service/hid/controllers/controller_base.h |
| 570 | hle/service/hid/controllers/debug_mouse.cpp | ||
| 571 | hle/service/hid/controllers/debug_mouse.h | ||
| 563 | hle/service/hid/controllers/debug_pad.cpp | 572 | hle/service/hid/controllers/debug_pad.cpp |
| 564 | hle/service/hid/controllers/debug_pad.h | 573 | hle/service/hid/controllers/debug_pad.h |
| 574 | hle/service/hid/controllers/digitizer.cpp | ||
| 575 | hle/service/hid/controllers/digitizer.h | ||
| 565 | hle/service/hid/controllers/gesture.cpp | 576 | hle/service/hid/controllers/gesture.cpp |
| 566 | hle/service/hid/controllers/gesture.h | 577 | hle/service/hid/controllers/gesture.h |
| 578 | hle/service/hid/controllers/home_button.cpp | ||
| 579 | hle/service/hid/controllers/home_button.h | ||
| 567 | hle/service/hid/controllers/keyboard.cpp | 580 | hle/service/hid/controllers/keyboard.cpp |
| 568 | hle/service/hid/controllers/keyboard.h | 581 | hle/service/hid/controllers/keyboard.h |
| 569 | hle/service/hid/controllers/mouse.cpp | 582 | hle/service/hid/controllers/mouse.cpp |
| @@ -574,15 +587,16 @@ add_library(core STATIC | |||
| 574 | hle/service/hid/controllers/palma.h | 587 | hle/service/hid/controllers/palma.h |
| 575 | hle/service/hid/controllers/seven_six_axis.cpp | 588 | hle/service/hid/controllers/seven_six_axis.cpp |
| 576 | hle/service/hid/controllers/seven_six_axis.h | 589 | 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 | 590 | hle/service/hid/controllers/shared_memory_holder.cpp |
| 579 | hle/service/hid/controllers/shared_memory_holder.h | 591 | hle/service/hid/controllers/shared_memory_holder.h |
| 580 | hle/service/hid/controllers/six_axis.cpp | 592 | hle/service/hid/controllers/six_axis.cpp |
| 581 | hle/service/hid/controllers/six_axis.h | 593 | hle/service/hid/controllers/six_axis.h |
| 582 | hle/service/hid/controllers/stubbed.cpp | 594 | hle/service/hid/controllers/sleep_button.cpp |
| 583 | hle/service/hid/controllers/stubbed.h | 595 | hle/service/hid/controllers/sleep_button.h |
| 584 | hle/service/hid/controllers/touchscreen.cpp | 596 | hle/service/hid/controllers/touchscreen.cpp |
| 585 | hle/service/hid/controllers/touchscreen.h | 597 | hle/service/hid/controllers/touchscreen.h |
| 598 | hle/service/hid/controllers/unique_pad.cpp | ||
| 599 | hle/service/hid/controllers/unique_pad.h | ||
| 586 | hle/service/hid/hidbus/hidbus_base.cpp | 600 | hle/service/hid/hidbus/hidbus_base.cpp |
| 587 | hle/service/hid/hidbus/hidbus_base.h | 601 | hle/service/hid/hidbus/hidbus_base.h |
| 588 | hle/service/hid/hidbus/ringcon.cpp | 602 | hle/service/hid/hidbus/ringcon.cpp |
| @@ -978,6 +992,7 @@ endif() | |||
| 978 | 992 | ||
| 979 | if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) | 993 | if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) |
| 980 | target_sources(core PRIVATE | 994 | target_sources(core PRIVATE |
| 995 | arm/dynarmic/arm_dynarmic.cpp | ||
| 981 | arm/dynarmic/arm_dynarmic.h | 996 | arm/dynarmic/arm_dynarmic.h |
| 982 | arm/dynarmic/arm_dynarmic_64.cpp | 997 | arm/dynarmic/arm_dynarmic_64.cpp |
| 983 | arm/dynarmic/arm_dynarmic_64.h | 998 | arm/dynarmic/arm_dynarmic_64.h |
| @@ -987,6 +1002,8 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) | |||
| 987 | arm/dynarmic/dynarmic_cp15.h | 1002 | arm/dynarmic/dynarmic_cp15.h |
| 988 | arm/dynarmic/dynarmic_exclusive_monitor.cpp | 1003 | arm/dynarmic/dynarmic_exclusive_monitor.cpp |
| 989 | arm/dynarmic/dynarmic_exclusive_monitor.h | 1004 | arm/dynarmic/dynarmic_exclusive_monitor.h |
| 1005 | hle/service/jit/jit_code_memory.cpp | ||
| 1006 | hle/service/jit/jit_code_memory.h | ||
| 990 | hle/service/jit/jit_context.cpp | 1007 | hle/service/jit/jit_context.cpp |
| 991 | hle/service/jit/jit_context.h | 1008 | hle/service/jit/jit_context.h |
| 992 | hle/service/jit/jit.cpp | 1009 | hle/service/jit/jit.cpp |
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index 698c9c8ad..5dc7e5d59 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | namespace Core { | 10 | namespace Core { |
| 11 | 11 | ||
| 12 | void ArmInterface::LogBacktrace(const Kernel::KProcess* process) const { | 12 | void ArmInterface::LogBacktrace(Kernel::KProcess* process) const { |
| 13 | Kernel::Svc::ThreadContext ctx; | 13 | Kernel::Svc::ThreadContext ctx; |
| 14 | this->GetContext(ctx); | 14 | this->GetContext(ctx); |
| 15 | 15 | ||
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 806c7c9e9..495963eef 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h | |||
| @@ -95,7 +95,7 @@ public: | |||
| 95 | virtual void SignalInterrupt(Kernel::KThread* thread) = 0; | 95 | virtual void SignalInterrupt(Kernel::KThread* thread) = 0; |
| 96 | 96 | ||
| 97 | // Stack trace generation. | 97 | // Stack trace generation. |
| 98 | void LogBacktrace(const Kernel::KProcess* process) const; | 98 | void LogBacktrace(Kernel::KProcess* process) const; |
| 99 | 99 | ||
| 100 | // Debug functionality. | 100 | // Debug functionality. |
| 101 | virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0; | 101 | virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0; |
diff --git a/src/core/arm/debug.cpp b/src/core/arm/debug.cpp index af1c34bc3..854509463 100644 --- a/src/core/arm/debug.cpp +++ b/src/core/arm/debug.cpp | |||
| @@ -79,7 +79,7 @@ constexpr std::array<u64, 2> SegmentBases{ | |||
| 79 | 0x7100000000ULL, | 79 | 0x7100000000ULL, |
| 80 | }; | 80 | }; |
| 81 | 81 | ||
| 82 | void SymbolicateBacktrace(const Kernel::KProcess* process, std::vector<BacktraceEntry>& out) { | 82 | void SymbolicateBacktrace(Kernel::KProcess* process, std::vector<BacktraceEntry>& out) { |
| 83 | auto modules = FindModules(process); | 83 | auto modules = FindModules(process); |
| 84 | 84 | ||
| 85 | const bool is_64 = process->Is64Bit(); | 85 | const bool is_64 = process->Is64Bit(); |
| @@ -118,7 +118,7 @@ void SymbolicateBacktrace(const Kernel::KProcess* process, std::vector<Backtrace | |||
| 118 | } | 118 | } |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | std::vector<BacktraceEntry> GetAArch64Backtrace(const Kernel::KProcess* process, | 121 | std::vector<BacktraceEntry> GetAArch64Backtrace(Kernel::KProcess* process, |
| 122 | const Kernel::Svc::ThreadContext& ctx) { | 122 | const Kernel::Svc::ThreadContext& ctx) { |
| 123 | std::vector<BacktraceEntry> out; | 123 | std::vector<BacktraceEntry> out; |
| 124 | auto& memory = process->GetMemory(); | 124 | auto& memory = process->GetMemory(); |
| @@ -144,7 +144,7 @@ std::vector<BacktraceEntry> GetAArch64Backtrace(const Kernel::KProcess* process, | |||
| 144 | return out; | 144 | return out; |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | std::vector<BacktraceEntry> GetAArch32Backtrace(const Kernel::KProcess* process, | 147 | std::vector<BacktraceEntry> GetAArch32Backtrace(Kernel::KProcess* process, |
| 148 | const Kernel::Svc::ThreadContext& ctx) { | 148 | const Kernel::Svc::ThreadContext& ctx) { |
| 149 | std::vector<BacktraceEntry> out; | 149 | std::vector<BacktraceEntry> out; |
| 150 | auto& memory = process->GetMemory(); | 150 | auto& memory = process->GetMemory(); |
| @@ -173,7 +173,7 @@ std::vector<BacktraceEntry> GetAArch32Backtrace(const Kernel::KProcess* process, | |||
| 173 | } // namespace | 173 | } // namespace |
| 174 | 174 | ||
| 175 | std::optional<std::string> GetThreadName(const Kernel::KThread* thread) { | 175 | std::optional<std::string> GetThreadName(const Kernel::KThread* thread) { |
| 176 | const auto* process = thread->GetOwnerProcess(); | 176 | auto* process = thread->GetOwnerProcess(); |
| 177 | if (process->Is64Bit()) { | 177 | if (process->Is64Bit()) { |
| 178 | return GetNameFromThreadType64(process->GetMemory(), *thread); | 178 | return GetNameFromThreadType64(process->GetMemory(), *thread); |
| 179 | } else { | 179 | } else { |
| @@ -248,7 +248,7 @@ Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process, | |||
| 248 | return cur_addr - 1; | 248 | return cur_addr - 1; |
| 249 | } | 249 | } |
| 250 | 250 | ||
| 251 | Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process) { | 251 | Loader::AppLoader::Modules FindModules(Kernel::KProcess* process) { |
| 252 | Loader::AppLoader::Modules modules; | 252 | Loader::AppLoader::Modules modules; |
| 253 | 253 | ||
| 254 | auto& page_table = process->GetPageTable(); | 254 | auto& page_table = process->GetPageTable(); |
| @@ -312,7 +312,7 @@ Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process) { | |||
| 312 | return modules; | 312 | return modules; |
| 313 | } | 313 | } |
| 314 | 314 | ||
| 315 | Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process) { | 315 | Kernel::KProcessAddress FindMainModuleEntrypoint(Kernel::KProcess* process) { |
| 316 | // Do we have any loaded executable sections? | 316 | // Do we have any loaded executable sections? |
| 317 | auto modules = FindModules(process); | 317 | auto modules = FindModules(process); |
| 318 | 318 | ||
| @@ -337,7 +337,7 @@ void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 addres | |||
| 337 | } | 337 | } |
| 338 | } | 338 | } |
| 339 | 339 | ||
| 340 | std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process, | 340 | std::vector<BacktraceEntry> GetBacktraceFromContext(Kernel::KProcess* process, |
| 341 | const Kernel::Svc::ThreadContext& ctx) { | 341 | const Kernel::Svc::ThreadContext& ctx) { |
| 342 | if (process->Is64Bit()) { | 342 | if (process->Is64Bit()) { |
| 343 | return GetAArch64Backtrace(process, ctx); | 343 | return GetAArch64Backtrace(process, ctx); |
diff --git a/src/core/arm/debug.h b/src/core/arm/debug.h index c542633db..3cd671365 100644 --- a/src/core/arm/debug.h +++ b/src/core/arm/debug.h | |||
| @@ -14,9 +14,9 @@ std::optional<std::string> GetThreadName(const Kernel::KThread* thread); | |||
| 14 | std::string_view GetThreadWaitReason(const Kernel::KThread* thread); | 14 | std::string_view GetThreadWaitReason(const Kernel::KThread* thread); |
| 15 | std::string GetThreadState(const Kernel::KThread* thread); | 15 | std::string GetThreadState(const Kernel::KThread* thread); |
| 16 | 16 | ||
| 17 | Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process); | 17 | Loader::AppLoader::Modules FindModules(Kernel::KProcess* process); |
| 18 | Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process, Kernel::KProcessAddress base); | 18 | Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process, Kernel::KProcessAddress base); |
| 19 | Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process); | 19 | Kernel::KProcessAddress FindMainModuleEntrypoint(Kernel::KProcess* process); |
| 20 | 20 | ||
| 21 | void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 address, u64 size); | 21 | void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 address, u64 size); |
| 22 | 22 | ||
| @@ -28,7 +28,7 @@ struct BacktraceEntry { | |||
| 28 | std::string name; | 28 | std::string name; |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process, | 31 | std::vector<BacktraceEntry> GetBacktraceFromContext(Kernel::KProcess* process, |
| 32 | const Kernel::Svc::ThreadContext& ctx); | 32 | const Kernel::Svc::ThreadContext& ctx); |
| 33 | std::vector<BacktraceEntry> GetBacktrace(const Kernel::KThread* thread); | 33 | std::vector<BacktraceEntry> GetBacktrace(const Kernel::KThread* thread); |
| 34 | 34 | ||
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 f34865e26..36478f722 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp | |||
| @@ -15,7 +15,7 @@ using namespace Common::Literals; | |||
| 15 | 15 | ||
| 16 | class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { | 16 | class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { |
| 17 | public: | 17 | public: |
| 18 | explicit DynarmicCallbacks32(ArmDynarmic32& parent, const Kernel::KProcess* process) | 18 | explicit DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess* process) |
| 19 | : m_parent{parent}, m_memory(process->GetMemory()), | 19 | : m_parent{parent}, m_memory(process->GetMemory()), |
| 20 | m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()}, | 20 | m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()}, |
| 21 | m_check_memory_access{m_debugger_enabled || | 21 | m_check_memory_access{m_debugger_enabled || |
| @@ -169,7 +169,7 @@ public: | |||
| 169 | 169 | ||
| 170 | ArmDynarmic32& m_parent; | 170 | ArmDynarmic32& m_parent; |
| 171 | Core::Memory::Memory& m_memory; | 171 | Core::Memory::Memory& m_memory; |
| 172 | const Kernel::KProcess* m_process{}; | 172 | Kernel::KProcess* m_process{}; |
| 173 | const bool m_debugger_enabled{}; | 173 | const bool m_debugger_enabled{}; |
| 174 | const bool m_check_memory_access{}; | 174 | const bool m_check_memory_access{}; |
| 175 | static constexpr u64 MinimumRunCycles = 10000U; | 175 | static constexpr u64 MinimumRunCycles = 10000U; |
| @@ -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 | } |
| @@ -370,13 +374,14 @@ void ArmDynarmic32::RewindBreakpointInstruction() { | |||
| 370 | this->SetContext(m_breakpoint_context); | 374 | this->SetContext(m_breakpoint_context); |
| 371 | } | 375 | } |
| 372 | 376 | ||
| 373 | ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process, | 377 | ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProcess* process, |
| 374 | DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index) | 378 | DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index) |
| 375 | : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor}, | 379 | : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor}, |
| 376 | m_cb(std::make_unique<DynarmicCallbacks32>(*this, process)), | 380 | m_cb(std::make_unique<DynarmicCallbacks32>(*this, process)), |
| 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_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 185ac7cbf..b580efe61 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h | |||
| @@ -20,7 +20,7 @@ class System; | |||
| 20 | 20 | ||
| 21 | class ArmDynarmic32 final : public ArmInterface { | 21 | class ArmDynarmic32 final : public ArmInterface { |
| 22 | public: | 22 | public: |
| 23 | ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process, | 23 | ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProcess* process, |
| 24 | DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index); | 24 | DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index); |
| 25 | ~ArmDynarmic32() override; | 25 | ~ArmDynarmic32() override; |
| 26 | 26 | ||
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index dff14756e..c811c8ad5 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp | |||
| @@ -15,7 +15,7 @@ using namespace Common::Literals; | |||
| 15 | 15 | ||
| 16 | class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { | 16 | class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { |
| 17 | public: | 17 | public: |
| 18 | explicit DynarmicCallbacks64(ArmDynarmic64& parent, const Kernel::KProcess* process) | 18 | explicit DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess* process) |
| 19 | : m_parent{parent}, m_memory(process->GetMemory()), | 19 | : m_parent{parent}, m_memory(process->GetMemory()), |
| 20 | m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()}, | 20 | m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()}, |
| 21 | m_check_memory_access{m_debugger_enabled || | 21 | m_check_memory_access{m_debugger_enabled || |
| @@ -216,7 +216,7 @@ public: | |||
| 216 | Core::Memory::Memory& m_memory; | 216 | Core::Memory::Memory& m_memory; |
| 217 | u64 m_tpidrro_el0{}; | 217 | u64 m_tpidrro_el0{}; |
| 218 | u64 m_tpidr_el0{}; | 218 | u64 m_tpidr_el0{}; |
| 219 | const Kernel::KProcess* m_process{}; | 219 | Kernel::KProcess* m_process{}; |
| 220 | const bool m_debugger_enabled{}; | 220 | const bool m_debugger_enabled{}; |
| 221 | const bool m_check_memory_access{}; | 221 | const bool m_check_memory_access{}; |
| 222 | static constexpr u64 MinimumRunCycles = 10000U; | 222 | static constexpr u64 MinimumRunCycles = 10000U; |
| @@ -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 | } |
| @@ -399,13 +403,14 @@ void ArmDynarmic64::RewindBreakpointInstruction() { | |||
| 399 | this->SetContext(m_breakpoint_context); | 403 | this->SetContext(m_breakpoint_context); |
| 400 | } | 404 | } |
| 401 | 405 | ||
| 402 | ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process, | 406 | ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProcess* process, |
| 403 | DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index) | 407 | DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index) |
| 404 | : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor}, | 408 | : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor}, |
| 405 | m_cb(std::make_unique<DynarmicCallbacks64>(*this, process)), m_core_index{core_index} { | 409 | m_cb(std::make_unique<DynarmicCallbacks64>(*this, process)), m_core_index{core_index} { |
| 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/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 4f3dd026f..08cd982b3 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h | |||
| @@ -25,7 +25,7 @@ class System; | |||
| 25 | 25 | ||
| 26 | class ArmDynarmic64 final : public ArmInterface { | 26 | class ArmDynarmic64 final : public ArmInterface { |
| 27 | public: | 27 | public: |
| 28 | ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process, | 28 | ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProcess* process, |
| 29 | DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index); | 29 | DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index); |
| 30 | ~ArmDynarmic64() override; | 30 | ~ArmDynarmic64() override; |
| 31 | 31 | ||
diff --git a/src/core/arm/nce/arm_nce.cpp b/src/core/arm/nce/arm_nce.cpp index 1311e66a9..123b3da7e 100644 --- a/src/core/arm/nce/arm_nce.cpp +++ b/src/core/arm/nce/arm_nce.cpp | |||
| @@ -39,7 +39,7 @@ fpsimd_context* GetFloatingPointState(mcontext_t& host_ctx) { | |||
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | using namespace Common::Literals; | 41 | using namespace Common::Literals; |
| 42 | constexpr u32 StackSize = 32_KiB; | 42 | constexpr u32 StackSize = 128_KiB; |
| 43 | 43 | ||
| 44 | } // namespace | 44 | } // namespace |
| 45 | 45 | ||
diff --git a/src/core/arm/nce/interpreter_visitor.cpp b/src/core/arm/nce/interpreter_visitor.cpp index 8e81c66a5..def888d15 100644 --- a/src/core/arm/nce/interpreter_visitor.cpp +++ b/src/core/arm/nce/interpreter_visitor.cpp | |||
| @@ -5,8 +5,6 @@ | |||
| 5 | #include "common/bit_cast.h" | 5 | #include "common/bit_cast.h" |
| 6 | #include "core/arm/nce/interpreter_visitor.h" | 6 | #include "core/arm/nce/interpreter_visitor.h" |
| 7 | 7 | ||
| 8 | #include <dynarmic/frontend/A64/decoder/a64.h> | ||
| 9 | |||
| 10 | namespace Core { | 8 | namespace Core { |
| 11 | 9 | ||
| 12 | template <u32 BitSize> | 10 | template <u32 BitSize> |
| @@ -249,6 +247,7 @@ bool InterpreterVisitor::LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) { | |||
| 249 | return false; | 247 | return false; |
| 250 | } | 248 | } |
| 251 | 249 | ||
| 250 | // Size in bytes | ||
| 252 | const u64 size = 4 << opc.ZeroExtend(); | 251 | const u64 size = 4 << opc.ZeroExtend(); |
| 253 | const u64 offset = imm19.SignExtend<u64>() << 2; | 252 | const u64 offset = imm19.SignExtend<u64>() << 2; |
| 254 | const u64 address = this->GetPc() + offset; | 253 | const u64 address = this->GetPc() + offset; |
| @@ -530,7 +529,7 @@ bool InterpreterVisitor::SIMDImmediate(bool wback, bool postindex, size_t scale, | |||
| 530 | } | 529 | } |
| 531 | case MemOp::Load: { | 530 | case MemOp::Load: { |
| 532 | u128 data{}; | 531 | u128 data{}; |
| 533 | m_memory.ReadBlock(address, &data, datasize); | 532 | m_memory.ReadBlock(address, &data, datasize / 8); |
| 534 | this->SetVec(Vt, data); | 533 | this->SetVec(Vt, data); |
| 535 | break; | 534 | break; |
| 536 | } | 535 | } |
diff --git a/src/core/arm/nce/visitor_base.h b/src/core/arm/nce/visitor_base.h index 8fb032912..6a2be3d9b 100644 --- a/src/core/arm/nce/visitor_base.h +++ b/src/core/arm/nce/visitor_base.h | |||
| @@ -4,9 +4,15 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #pragma GCC diagnostic push | ||
| 8 | #pragma GCC diagnostic ignored "-Wshadow" | ||
| 9 | |||
| 7 | #include <dynarmic/frontend/A64/a64_types.h> | 10 | #include <dynarmic/frontend/A64/a64_types.h> |
| 11 | #include <dynarmic/frontend/A64/decoder/a64.h> | ||
| 8 | #include <dynarmic/frontend/imm.h> | 12 | #include <dynarmic/frontend/imm.h> |
| 9 | 13 | ||
| 14 | #pragma GCC diagnostic pop | ||
| 15 | |||
| 10 | namespace Core { | 16 | namespace Core { |
| 11 | 17 | ||
| 12 | class VisitorBase { | 18 | class VisitorBase { |
diff --git a/src/core/core.cpp b/src/core/core.cpp index b14f74976..66f444d39 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -28,7 +28,6 @@ | |||
| 28 | #include "core/file_sys/savedata_factory.h" | 28 | #include "core/file_sys/savedata_factory.h" |
| 29 | #include "core/file_sys/vfs_concat.h" | 29 | #include "core/file_sys/vfs_concat.h" |
| 30 | #include "core/file_sys/vfs_real.h" | 30 | #include "core/file_sys/vfs_real.h" |
| 31 | #include "core/gpu_dirty_memory_manager.h" | ||
| 32 | #include "core/hid/hid_core.h" | 31 | #include "core/hid/hid_core.h" |
| 33 | #include "core/hle/kernel/k_memory_manager.h" | 32 | #include "core/hle/kernel/k_memory_manager.h" |
| 34 | #include "core/hle/kernel/k_process.h" | 33 | #include "core/hle/kernel/k_process.h" |
| @@ -130,11 +129,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, | |||
| 130 | 129 | ||
| 131 | struct System::Impl { | 130 | struct System::Impl { |
| 132 | explicit Impl(System& system) | 131 | explicit Impl(System& system) |
| 133 | : kernel{system}, fs_controller{system}, memory{system}, hid_core{}, room_network{}, | 132 | : kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system}, |
| 134 | cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{}, | 133 | reporter{system}, applet_manager{system}, profile_manager{}, time_manager{system} {} |
| 135 | time_manager{system}, gpu_dirty_memory_write_manager{} { | ||
| 136 | memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager); | ||
| 137 | } | ||
| 138 | 134 | ||
| 139 | void Initialize(System& system) { | 135 | void Initialize(System& system) { |
| 140 | device_memory = std::make_unique<Core::DeviceMemory>(); | 136 | device_memory = std::make_unique<Core::DeviceMemory>(); |
| @@ -241,17 +237,17 @@ struct System::Impl { | |||
| 241 | debugger = std::make_unique<Debugger>(system, port); | 237 | debugger = std::make_unique<Debugger>(system, port); |
| 242 | } | 238 | } |
| 243 | 239 | ||
| 244 | SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) { | 240 | void InitializeKernel(System& system) { |
| 245 | LOG_DEBUG(Core, "initialized OK"); | 241 | LOG_DEBUG(Core, "initialized OK"); |
| 246 | 242 | ||
| 247 | // Setting changes may require a full system reinitialization (e.g., disabling multicore). | 243 | // Setting changes may require a full system reinitialization (e.g., disabling multicore). |
| 248 | ReinitializeIfNecessary(system); | 244 | ReinitializeIfNecessary(system); |
| 249 | 245 | ||
| 250 | memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager); | ||
| 251 | |||
| 252 | kernel.Initialize(); | 246 | kernel.Initialize(); |
| 253 | cpu_manager.Initialize(); | 247 | cpu_manager.Initialize(); |
| 248 | } | ||
| 254 | 249 | ||
| 250 | SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) { | ||
| 255 | /// Reset all glue registrations | 251 | /// Reset all glue registrations |
| 256 | arp_manager.ResetAll(); | 252 | arp_manager.ResetAll(); |
| 257 | 253 | ||
| @@ -300,17 +296,9 @@ struct System::Impl { | |||
| 300 | return SystemResultStatus::ErrorGetLoader; | 296 | return SystemResultStatus::ErrorGetLoader; |
| 301 | } | 297 | } |
| 302 | 298 | ||
| 303 | SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)}; | 299 | InitializeKernel(system); |
| 304 | if (init_result != SystemResultStatus::Success) { | ||
| 305 | LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", | ||
| 306 | static_cast<int>(init_result)); | ||
| 307 | ShutdownMainProcess(); | ||
| 308 | return init_result; | ||
| 309 | } | ||
| 310 | |||
| 311 | telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider); | ||
| 312 | 300 | ||
| 313 | // Create the process. | 301 | // Create the application process. |
| 314 | auto main_process = Kernel::KProcess::Create(system.Kernel()); | 302 | auto main_process = Kernel::KProcess::Create(system.Kernel()); |
| 315 | Kernel::KProcess::Register(system.Kernel(), main_process); | 303 | Kernel::KProcess::Register(system.Kernel(), main_process); |
| 316 | kernel.AppendNewProcess(main_process); | 304 | kernel.AppendNewProcess(main_process); |
| @@ -323,7 +311,18 @@ struct System::Impl { | |||
| 323 | return static_cast<SystemResultStatus>( | 311 | return static_cast<SystemResultStatus>( |
| 324 | static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result)); | 312 | static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result)); |
| 325 | } | 313 | } |
| 314 | |||
| 315 | // Set up the rest of the system. | ||
| 316 | SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)}; | ||
| 317 | if (init_result != SystemResultStatus::Success) { | ||
| 318 | LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", | ||
| 319 | static_cast<int>(init_result)); | ||
| 320 | ShutdownMainProcess(); | ||
| 321 | return init_result; | ||
| 322 | } | ||
| 323 | |||
| 326 | AddGlueRegistrationForProcess(*app_loader, *main_process); | 324 | AddGlueRegistrationForProcess(*app_loader, *main_process); |
| 325 | telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider); | ||
| 327 | 326 | ||
| 328 | // Initialize cheat engine | 327 | // Initialize cheat engine |
| 329 | if (cheat_engine) { | 328 | if (cheat_engine) { |
| @@ -426,7 +425,6 @@ struct System::Impl { | |||
| 426 | cpu_manager.Shutdown(); | 425 | cpu_manager.Shutdown(); |
| 427 | debugger.reset(); | 426 | debugger.reset(); |
| 428 | kernel.Shutdown(); | 427 | kernel.Shutdown(); |
| 429 | memory.Reset(); | ||
| 430 | Network::RestartSocketOperations(); | 428 | Network::RestartSocketOperations(); |
| 431 | 429 | ||
| 432 | if (auto room_member = room_network.GetRoomMember().lock()) { | 430 | if (auto room_member = room_network.GetRoomMember().lock()) { |
| @@ -507,7 +505,6 @@ struct System::Impl { | |||
| 507 | std::unique_ptr<Tegra::Host1x::Host1x> host1x_core; | 505 | std::unique_ptr<Tegra::Host1x::Host1x> host1x_core; |
| 508 | std::unique_ptr<Core::DeviceMemory> device_memory; | 506 | std::unique_ptr<Core::DeviceMemory> device_memory; |
| 509 | std::unique_ptr<AudioCore::AudioCore> audio_core; | 507 | std::unique_ptr<AudioCore::AudioCore> audio_core; |
| 510 | Core::Memory::Memory memory; | ||
| 511 | Core::HID::HIDCore hid_core; | 508 | Core::HID::HIDCore hid_core; |
| 512 | Network::RoomNetwork room_network; | 509 | Network::RoomNetwork room_network; |
| 513 | 510 | ||
| @@ -567,9 +564,6 @@ struct System::Impl { | |||
| 567 | std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; | 564 | std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; |
| 568 | std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{}; | 565 | std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{}; |
| 569 | 566 | ||
| 570 | std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES> | ||
| 571 | gpu_dirty_memory_write_manager{}; | ||
| 572 | |||
| 573 | std::deque<std::vector<u8>> user_channel; | 567 | std::deque<std::vector<u8>> user_channel; |
| 574 | }; | 568 | }; |
| 575 | 569 | ||
| @@ -652,29 +646,12 @@ void System::PrepareReschedule(const u32 core_index) { | |||
| 652 | impl->kernel.PrepareReschedule(core_index); | 646 | impl->kernel.PrepareReschedule(core_index); |
| 653 | } | 647 | } |
| 654 | 648 | ||
| 655 | Core::GPUDirtyMemoryManager& System::CurrentGPUDirtyMemoryManager() { | ||
| 656 | const std::size_t core = impl->kernel.GetCurrentHostThreadID(); | ||
| 657 | return impl->gpu_dirty_memory_write_manager[core < Core::Hardware::NUM_CPU_CORES | ||
| 658 | ? core | ||
| 659 | : Core::Hardware::NUM_CPU_CORES - 1]; | ||
| 660 | } | ||
| 661 | |||
| 662 | /// Provides a constant reference to the current gou dirty memory manager. | ||
| 663 | const Core::GPUDirtyMemoryManager& System::CurrentGPUDirtyMemoryManager() const { | ||
| 664 | const std::size_t core = impl->kernel.GetCurrentHostThreadID(); | ||
| 665 | return impl->gpu_dirty_memory_write_manager[core < Core::Hardware::NUM_CPU_CORES | ||
| 666 | ? core | ||
| 667 | : Core::Hardware::NUM_CPU_CORES - 1]; | ||
| 668 | } | ||
| 669 | |||
| 670 | size_t System::GetCurrentHostThreadID() const { | 649 | size_t System::GetCurrentHostThreadID() const { |
| 671 | return impl->kernel.GetCurrentHostThreadID(); | 650 | return impl->kernel.GetCurrentHostThreadID(); |
| 672 | } | 651 | } |
| 673 | 652 | ||
| 674 | void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) { | 653 | void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) { |
| 675 | for (auto& manager : impl->gpu_dirty_memory_write_manager) { | 654 | return this->ApplicationProcess()->GatherGPUDirtyMemory(callback); |
| 676 | manager.Gather(callback); | ||
| 677 | } | ||
| 678 | } | 655 | } |
| 679 | 656 | ||
| 680 | PerfStatsResults System::GetAndResetPerfStats() { | 657 | PerfStatsResults System::GetAndResetPerfStats() { |
| @@ -723,20 +700,12 @@ const Kernel::KProcess* System::ApplicationProcess() const { | |||
| 723 | return impl->kernel.ApplicationProcess(); | 700 | return impl->kernel.ApplicationProcess(); |
| 724 | } | 701 | } |
| 725 | 702 | ||
| 726 | ExclusiveMonitor& System::Monitor() { | ||
| 727 | return impl->kernel.GetExclusiveMonitor(); | ||
| 728 | } | ||
| 729 | |||
| 730 | const ExclusiveMonitor& System::Monitor() const { | ||
| 731 | return impl->kernel.GetExclusiveMonitor(); | ||
| 732 | } | ||
| 733 | |||
| 734 | Memory::Memory& System::ApplicationMemory() { | 703 | Memory::Memory& System::ApplicationMemory() { |
| 735 | return impl->memory; | 704 | return impl->kernel.ApplicationProcess()->GetMemory(); |
| 736 | } | 705 | } |
| 737 | 706 | ||
| 738 | const Core::Memory::Memory& System::ApplicationMemory() const { | 707 | const Core::Memory::Memory& System::ApplicationMemory() const { |
| 739 | return impl->memory; | 708 | return impl->kernel.ApplicationProcess()->GetMemory(); |
| 740 | } | 709 | } |
| 741 | 710 | ||
| 742 | Tegra::GPU& System::GPU() { | 711 | Tegra::GPU& System::GPU() { |
diff --git a/src/core/core.h b/src/core/core.h index 473204db7..ba5add0dc 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -116,7 +116,6 @@ class CpuManager; | |||
| 116 | class Debugger; | 116 | class Debugger; |
| 117 | class DeviceMemory; | 117 | class DeviceMemory; |
| 118 | class ExclusiveMonitor; | 118 | class ExclusiveMonitor; |
| 119 | class GPUDirtyMemoryManager; | ||
| 120 | class PerfStats; | 119 | class PerfStats; |
| 121 | class Reporter; | 120 | class Reporter; |
| 122 | class SpeedLimiter; | 121 | class SpeedLimiter; |
| @@ -225,12 +224,6 @@ public: | |||
| 225 | /// Prepare the core emulation for a reschedule | 224 | /// Prepare the core emulation for a reschedule |
| 226 | void PrepareReschedule(u32 core_index); | 225 | void PrepareReschedule(u32 core_index); |
| 227 | 226 | ||
| 228 | /// Provides a reference to the gou dirty memory manager. | ||
| 229 | [[nodiscard]] Core::GPUDirtyMemoryManager& CurrentGPUDirtyMemoryManager(); | ||
| 230 | |||
| 231 | /// Provides a constant reference to the current gou dirty memory manager. | ||
| 232 | [[nodiscard]] const Core::GPUDirtyMemoryManager& CurrentGPUDirtyMemoryManager() const; | ||
| 233 | |||
| 234 | void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback); | 227 | void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback); |
| 235 | 228 | ||
| 236 | [[nodiscard]] size_t GetCurrentHostThreadID() const; | 229 | [[nodiscard]] size_t GetCurrentHostThreadID() const; |
| @@ -250,12 +243,6 @@ public: | |||
| 250 | /// Gets a const reference to the underlying CPU manager | 243 | /// Gets a const reference to the underlying CPU manager |
| 251 | [[nodiscard]] const CpuManager& GetCpuManager() const; | 244 | [[nodiscard]] const CpuManager& GetCpuManager() const; |
| 252 | 245 | ||
| 253 | /// Gets a reference to the exclusive monitor | ||
| 254 | [[nodiscard]] ExclusiveMonitor& Monitor(); | ||
| 255 | |||
| 256 | /// Gets a constant reference to the exclusive monitor | ||
| 257 | [[nodiscard]] const ExclusiveMonitor& Monitor() const; | ||
| 258 | |||
| 259 | /// Gets a mutable reference to the system memory instance. | 246 | /// Gets a mutable reference to the system memory instance. |
| 260 | [[nodiscard]] Core::Memory::Memory& ApplicationMemory(); | 247 | [[nodiscard]] Core::Memory::Memory& ApplicationMemory(); |
| 261 | 248 | ||
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/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp index 763a44fee..539c7f7af 100644 --- a/src/core/file_sys/program_metadata.cpp +++ b/src/core/file_sys/program_metadata.cpp | |||
| @@ -166,6 +166,10 @@ u32 ProgramMetadata::GetSystemResourceSize() const { | |||
| 166 | return npdm_header.system_resource_size; | 166 | return npdm_header.system_resource_size; |
| 167 | } | 167 | } |
| 168 | 168 | ||
| 169 | PoolPartition ProgramMetadata::GetPoolPartition() const { | ||
| 170 | return acid_header.pool_partition; | ||
| 171 | } | ||
| 172 | |||
| 169 | const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const { | 173 | const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const { |
| 170 | return aci_kernel_capabilities; | 174 | return aci_kernel_capabilities; |
| 171 | } | 175 | } |
| @@ -201,7 +205,7 @@ void ProgramMetadata::Print() const { | |||
| 201 | // Begin ACID printing (potential perms, signed) | 205 | // Begin ACID printing (potential perms, signed) |
| 202 | LOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data()); | 206 | LOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data()); |
| 203 | LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags); | 207 | LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags); |
| 204 | LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.is_retail ? "YES" : "NO"); | 208 | LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.production_flag ? "YES" : "NO"); |
| 205 | LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min); | 209 | LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min); |
| 206 | LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max); | 210 | LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max); |
| 207 | LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions); | 211 | LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions); |
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h index 76ee97d78..a53092b87 100644 --- a/src/core/file_sys/program_metadata.h +++ b/src/core/file_sys/program_metadata.h | |||
| @@ -34,6 +34,13 @@ enum class ProgramFilePermission : u64 { | |||
| 34 | Everything = 1ULL << 63, | 34 | Everything = 1ULL << 63, |
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | enum class PoolPartition : u32 { | ||
| 38 | Application = 0, | ||
| 39 | Applet = 1, | ||
| 40 | System = 2, | ||
| 41 | SystemNonSecure = 3, | ||
| 42 | }; | ||
| 43 | |||
| 37 | /** | 44 | /** |
| 38 | * Helper which implements an interface to parse Program Description Metadata (NPDM) | 45 | * Helper which implements an interface to parse Program Description Metadata (NPDM) |
| 39 | * Data can either be loaded from a file path or with data and an offset into it. | 46 | * Data can either be loaded from a file path or with data and an offset into it. |
| @@ -72,6 +79,7 @@ public: | |||
| 72 | u64 GetTitleID() const; | 79 | u64 GetTitleID() const; |
| 73 | u64 GetFilesystemPermissions() const; | 80 | u64 GetFilesystemPermissions() const; |
| 74 | u32 GetSystemResourceSize() const; | 81 | u32 GetSystemResourceSize() const; |
| 82 | PoolPartition GetPoolPartition() const; | ||
| 75 | const KernelCapabilityDescriptors& GetKernelCapabilities() const; | 83 | const KernelCapabilityDescriptors& GetKernelCapabilities() const; |
| 76 | const std::array<u8, 0x10>& GetName() const { | 84 | const std::array<u8, 0x10>& GetName() const { |
| 77 | return npdm_header.application_name; | 85 | return npdm_header.application_name; |
| @@ -116,8 +124,9 @@ private: | |||
| 116 | union { | 124 | union { |
| 117 | u32 flags; | 125 | u32 flags; |
| 118 | 126 | ||
| 119 | BitField<0, 1, u32> is_retail; | 127 | BitField<0, 1, u32> production_flag; |
| 120 | BitField<1, 31, u32> flags_unk; | 128 | BitField<1, 1, u32> unqualified_approval; |
| 129 | BitField<2, 4, PoolPartition> pool_partition; | ||
| 121 | }; | 130 | }; |
| 122 | u64_le title_id_min; | 131 | u64_le title_id_min; |
| 123 | u64_le title_id_max; | 132 | u64_le title_id_max; |
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index 4bf285f36..a81ed6af0 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h | |||
| @@ -267,6 +267,7 @@ enum class NpadStyleSet : u32 { | |||
| 267 | All = 0xFFFFFFFFU, | 267 | All = 0xFFFFFFFFU, |
| 268 | }; | 268 | }; |
| 269 | static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size"); | 269 | static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size"); |
| 270 | DECLARE_ENUM_FLAG_OPERATORS(NpadStyleSet) | ||
| 270 | 271 | ||
| 271 | // This is nn::hid::VibrationDevicePosition | 272 | // This is nn::hid::VibrationDevicePosition |
| 272 | enum class VibrationDevicePosition : u32 { | 273 | enum class VibrationDevicePosition : u32 { |
diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index 78d43d729..48889253d 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #include "core/arm/exclusive_monitor.h" | 4 | #include "core/arm/exclusive_monitor.h" |
| 5 | #include "core/core.h" | 5 | #include "core/core.h" |
| 6 | #include "core/hle/kernel/k_address_arbiter.h" | 6 | #include "core/hle/kernel/k_address_arbiter.h" |
| 7 | #include "core/hle/kernel/k_process.h" | ||
| 7 | #include "core/hle/kernel/k_scheduler.h" | 8 | #include "core/hle/kernel/k_scheduler.h" |
| 8 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 9 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 9 | #include "core/hle/kernel/k_thread.h" | 10 | #include "core/hle/kernel/k_thread.h" |
| @@ -26,9 +27,9 @@ bool ReadFromUser(KernelCore& kernel, s32* out, KProcessAddress address) { | |||
| 26 | return true; | 27 | return true; |
| 27 | } | 28 | } |
| 28 | 29 | ||
| 29 | bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address, s32 value) { | 30 | bool DecrementIfLessThan(KernelCore& kernel, s32* out, KProcessAddress address, s32 value) { |
| 30 | auto& monitor = system.Monitor(); | 31 | auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor(); |
| 31 | const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); | 32 | const auto current_core = kernel.CurrentPhysicalCoreIndex(); |
| 32 | 33 | ||
| 33 | // NOTE: If scheduler lock is not held here, interrupt disable is required. | 34 | // NOTE: If scheduler lock is not held here, interrupt disable is required. |
| 34 | // KScopedInterruptDisable di; | 35 | // KScopedInterruptDisable di; |
| @@ -66,10 +67,10 @@ bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address | |||
| 66 | return true; | 67 | return true; |
| 67 | } | 68 | } |
| 68 | 69 | ||
| 69 | bool UpdateIfEqual(Core::System& system, s32* out, KProcessAddress address, s32 value, | 70 | bool UpdateIfEqual(KernelCore& kernel, s32* out, KProcessAddress address, s32 value, |
| 70 | s32 new_value) { | 71 | s32 new_value) { |
| 71 | auto& monitor = system.Monitor(); | 72 | auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor(); |
| 72 | const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); | 73 | const auto current_core = kernel.CurrentPhysicalCoreIndex(); |
| 73 | 74 | ||
| 74 | // NOTE: If scheduler lock is not held here, interrupt disable is required. | 75 | // NOTE: If scheduler lock is not held here, interrupt disable is required. |
| 75 | // KScopedInterruptDisable di; | 76 | // KScopedInterruptDisable di; |
| @@ -159,7 +160,7 @@ Result KAddressArbiter::SignalAndIncrementIfEqual(uint64_t addr, s32 value, s32 | |||
| 159 | 160 | ||
| 160 | // Check the userspace value. | 161 | // Check the userspace value. |
| 161 | s32 user_value{}; | 162 | s32 user_value{}; |
| 162 | R_UNLESS(UpdateIfEqual(m_system, std::addressof(user_value), addr, value, value + 1), | 163 | R_UNLESS(UpdateIfEqual(m_kernel, std::addressof(user_value), addr, value, value + 1), |
| 163 | ResultInvalidCurrentMemory); | 164 | ResultInvalidCurrentMemory); |
| 164 | R_UNLESS(user_value == value, ResultInvalidState); | 165 | R_UNLESS(user_value == value, ResultInvalidState); |
| 165 | 166 | ||
| @@ -219,7 +220,7 @@ Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(uint64_t addr, s32 | |||
| 219 | s32 user_value{}; | 220 | s32 user_value{}; |
| 220 | bool succeeded{}; | 221 | bool succeeded{}; |
| 221 | if (value != new_value) { | 222 | if (value != new_value) { |
| 222 | succeeded = UpdateIfEqual(m_system, std::addressof(user_value), addr, value, new_value); | 223 | succeeded = UpdateIfEqual(m_kernel, std::addressof(user_value), addr, value, new_value); |
| 223 | } else { | 224 | } else { |
| 224 | succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr); | 225 | succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr); |
| 225 | } | 226 | } |
| @@ -262,7 +263,7 @@ Result KAddressArbiter::WaitIfLessThan(uint64_t addr, s32 value, bool decrement, | |||
| 262 | s32 user_value{}; | 263 | s32 user_value{}; |
| 263 | bool succeeded{}; | 264 | bool succeeded{}; |
| 264 | if (decrement) { | 265 | if (decrement) { |
| 265 | succeeded = DecrementIfLessThan(m_system, std::addressof(user_value), addr, value); | 266 | succeeded = DecrementIfLessThan(m_kernel, std::addressof(user_value), addr, value); |
| 266 | } else { | 267 | } else { |
| 267 | succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr); | 268 | succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr); |
| 268 | } | 269 | } |
diff --git a/src/core/hle/kernel/k_auto_object_container.cpp b/src/core/hle/kernel/k_auto_object_container.cpp index 636b3f993..7bea1a1c2 100644 --- a/src/core/hle/kernel/k_auto_object_container.cpp +++ b/src/core/hle/kernel/k_auto_object_container.cpp | |||
| @@ -8,19 +8,22 @@ | |||
| 8 | namespace Kernel { | 8 | namespace Kernel { |
| 9 | 9 | ||
| 10 | void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) { | 10 | void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) { |
| 11 | KScopedLightLock lk(m_lock); | 11 | // KScopedInterruptDisable di; |
| 12 | KScopedSpinLock lk(m_lock); | ||
| 12 | 13 | ||
| 13 | m_object_list.insert_unique(*obj); | 14 | m_object_list.insert_unique(*obj); |
| 14 | } | 15 | } |
| 15 | 16 | ||
| 16 | void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) { | 17 | void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) { |
| 17 | KScopedLightLock lk(m_lock); | 18 | // KScopedInterruptDisable di; |
| 19 | KScopedSpinLock lk(m_lock); | ||
| 18 | 20 | ||
| 19 | m_object_list.erase(*obj); | 21 | m_object_list.erase(*obj); |
| 20 | } | 22 | } |
| 21 | 23 | ||
| 22 | size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) { | 24 | size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) { |
| 23 | KScopedLightLock lk(m_lock); | 25 | // KScopedInterruptDisable di; |
| 26 | KScopedSpinLock lk(m_lock); | ||
| 24 | 27 | ||
| 25 | return std::count_if(m_object_list.begin(), m_object_list.end(), | 28 | return std::count_if(m_object_list.begin(), m_object_list.end(), |
| 26 | [&](const auto& obj) { return obj.GetOwner() == owner; }); | 29 | [&](const auto& obj) { return obj.GetOwner() == owner; }); |
diff --git a/src/core/hle/kernel/k_auto_object_container.h b/src/core/hle/kernel/k_auto_object_container.h index badd75d2a..770743d21 100644 --- a/src/core/hle/kernel/k_auto_object_container.h +++ b/src/core/hle/kernel/k_auto_object_container.h | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | #include "common/common_funcs.h" | 8 | #include "common/common_funcs.h" |
| 9 | #include "core/hle/kernel/k_auto_object.h" | 9 | #include "core/hle/kernel/k_auto_object.h" |
| 10 | #include "core/hle/kernel/k_light_lock.h" | 10 | #include "core/hle/kernel/k_spin_lock.h" |
| 11 | 11 | ||
| 12 | namespace Kernel { | 12 | namespace Kernel { |
| 13 | 13 | ||
| @@ -21,32 +21,7 @@ public: | |||
| 21 | 21 | ||
| 22 | using ListType = boost::intrusive::rbtree<KAutoObjectWithList>; | 22 | using ListType = boost::intrusive::rbtree<KAutoObjectWithList>; |
| 23 | 23 | ||
| 24 | class ListAccessor : public KScopedLightLock { | 24 | KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(), m_object_list() {} |
| 25 | public: | ||
| 26 | explicit ListAccessor(KAutoObjectWithListContainer* container) | ||
| 27 | : KScopedLightLock(container->m_lock), m_list(container->m_object_list) {} | ||
| 28 | explicit ListAccessor(KAutoObjectWithListContainer& container) | ||
| 29 | : KScopedLightLock(container.m_lock), m_list(container.m_object_list) {} | ||
| 30 | |||
| 31 | typename ListType::iterator begin() const { | ||
| 32 | return m_list.begin(); | ||
| 33 | } | ||
| 34 | |||
| 35 | typename ListType::iterator end() const { | ||
| 36 | return m_list.end(); | ||
| 37 | } | ||
| 38 | |||
| 39 | typename ListType::iterator find(typename ListType::const_reference ref) const { | ||
| 40 | return m_list.find(ref); | ||
| 41 | } | ||
| 42 | |||
| 43 | private: | ||
| 44 | ListType& m_list; | ||
| 45 | }; | ||
| 46 | |||
| 47 | friend class ListAccessor; | ||
| 48 | |||
| 49 | KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(kernel), m_object_list() {} | ||
| 50 | 25 | ||
| 51 | void Initialize() {} | 26 | void Initialize() {} |
| 52 | void Finalize() {} | 27 | void Finalize() {} |
| @@ -56,7 +31,7 @@ public: | |||
| 56 | size_t GetOwnedCount(KProcess* owner); | 31 | size_t GetOwnedCount(KProcess* owner); |
| 57 | 32 | ||
| 58 | private: | 33 | private: |
| 59 | KLightLock m_lock; | 34 | KSpinLock m_lock; |
| 60 | ListType m_object_list; | 35 | ListType m_object_list; |
| 61 | }; | 36 | }; |
| 62 | 37 | ||
diff --git a/src/core/hle/kernel/k_capabilities.cpp b/src/core/hle/kernel/k_capabilities.cpp index 274fee493..d2288c30d 100644 --- a/src/core/hle/kernel/k_capabilities.cpp +++ b/src/core/hle/kernel/k_capabilities.cpp | |||
| @@ -185,6 +185,10 @@ Result KCapabilities::ProcessMapRegionCapability(const u32 cap, F f) { | |||
| 185 | case RegionType::NoMapping: | 185 | case RegionType::NoMapping: |
| 186 | break; | 186 | break; |
| 187 | case RegionType::KernelTraceBuffer: | 187 | case RegionType::KernelTraceBuffer: |
| 188 | if constexpr (!IsKTraceEnabled) { | ||
| 189 | break; | ||
| 190 | } | ||
| 191 | [[fallthrough]]; | ||
| 188 | case RegionType::OnMemoryBootImage: | 192 | case RegionType::OnMemoryBootImage: |
| 189 | case RegionType::DTB: | 193 | case RegionType::DTB: |
| 190 | R_TRY(f(MemoryRegions[static_cast<u32>(type)], perm)); | 194 | R_TRY(f(MemoryRegions[static_cast<u32>(type)], perm)); |
| @@ -330,8 +334,6 @@ Result KCapabilities::SetCapabilities(std::span<const u32> caps, KProcessPageTab | |||
| 330 | 334 | ||
| 331 | // Map the range. | 335 | // Map the range. |
| 332 | R_TRY(this->MapRange_(cap, size_cap, page_table)); | 336 | R_TRY(this->MapRange_(cap, size_cap, page_table)); |
| 333 | } else if (GetCapabilityType(cap) == CapabilityType::MapRegion && !IsKTraceEnabled) { | ||
| 334 | continue; | ||
| 335 | } else { | 337 | } else { |
| 336 | R_TRY(this->SetCapability(cap, set_flags, set_svc, page_table)); | 338 | R_TRY(this->SetCapability(cap, set_flags, set_svc, page_table)); |
| 337 | } | 339 | } |
diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp index 11b1b977e..68cea978a 100644 --- a/src/core/hle/kernel/k_client_port.cpp +++ b/src/core/hle/kernel/k_client_port.cpp | |||
| @@ -58,9 +58,8 @@ Result KClientPort::CreateSession(KClientSession** out) { | |||
| 58 | KSession* session{}; | 58 | KSession* session{}; |
| 59 | 59 | ||
| 60 | // Reserve a new session from the resource limit. | 60 | // Reserve a new session from the resource limit. |
| 61 | //! FIXME: we are reserving this from the wrong resource limit! | 61 | KScopedResourceReservation session_reservation(GetCurrentProcessPointer(m_kernel), |
| 62 | KScopedResourceReservation session_reservation( | 62 | LimitableResource::SessionCountMax); |
| 63 | m_kernel.ApplicationProcess()->GetResourceLimit(), LimitableResource::SessionCountMax); | ||
| 64 | R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); | 63 | R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); |
| 65 | 64 | ||
| 66 | // Allocate a session normally. | 65 | // Allocate a session normally. |
diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index 7633a51fb..94ea3527a 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp | |||
| @@ -28,10 +28,10 @@ bool WriteToUser(KernelCore& kernel, KProcessAddress address, const u32* p) { | |||
| 28 | return true; | 28 | return true; |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | bool UpdateLockAtomic(Core::System& system, u32* out, KProcessAddress address, u32 if_zero, | 31 | bool UpdateLockAtomic(KernelCore& kernel, u32* out, KProcessAddress address, u32 if_zero, |
| 32 | u32 new_orr_mask) { | 32 | u32 new_orr_mask) { |
| 33 | auto& monitor = system.Monitor(); | 33 | auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor(); |
| 34 | const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); | 34 | const auto current_core = kernel.CurrentPhysicalCoreIndex(); |
| 35 | 35 | ||
| 36 | u32 expected{}; | 36 | u32 expected{}; |
| 37 | 37 | ||
| @@ -208,7 +208,7 @@ void KConditionVariable::SignalImpl(KThread* thread) { | |||
| 208 | // TODO(bunnei): We should call CanAccessAtomic(..) here. | 208 | // TODO(bunnei): We should call CanAccessAtomic(..) here. |
| 209 | can_access = true; | 209 | can_access = true; |
| 210 | if (can_access) [[likely]] { | 210 | if (can_access) [[likely]] { |
| 211 | UpdateLockAtomic(m_system, std::addressof(prev_tag), address, own_tag, | 211 | UpdateLockAtomic(m_kernel, std::addressof(prev_tag), address, own_tag, |
| 212 | Svc::HandleWaitMask); | 212 | Svc::HandleWaitMask); |
| 213 | } | 213 | } |
| 214 | } | 214 | } |
diff --git a/src/core/hle/kernel/k_handle_table.h b/src/core/hle/kernel/k_handle_table.h index d7660630c..1bf68e6b0 100644 --- a/src/core/hle/kernel/k_handle_table.h +++ b/src/core/hle/kernel/k_handle_table.h | |||
| @@ -90,8 +90,7 @@ public: | |||
| 90 | // Handle pseudo-handles. | 90 | // Handle pseudo-handles. |
| 91 | if constexpr (std::derived_from<KProcess, T>) { | 91 | if constexpr (std::derived_from<KProcess, T>) { |
| 92 | if (handle == Svc::PseudoHandle::CurrentProcess) { | 92 | if (handle == Svc::PseudoHandle::CurrentProcess) { |
| 93 | //! FIXME: this is the wrong process! | 93 | auto* const cur_process = GetCurrentProcessPointer(m_kernel); |
| 94 | auto* const cur_process = m_kernel.ApplicationProcess(); | ||
| 95 | ASSERT(cur_process != nullptr); | 94 | ASSERT(cur_process != nullptr); |
| 96 | return cur_process; | 95 | return cur_process; |
| 97 | } | 96 | } |
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 3a2635e1f..068e71dff 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -306,12 +306,16 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params, const KPa | |||
| 306 | False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge); | 306 | False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge); |
| 307 | R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, | 307 | R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, |
| 308 | params.code_address, params.code_num_pages * PageSize, | 308 | params.code_address, params.code_num_pages * PageSize, |
| 309 | m_system_resource, res_limit, this->GetMemory(), 0)); | 309 | m_system_resource, res_limit, m_memory, 0)); |
| 310 | } | 310 | } |
| 311 | ON_RESULT_FAILURE_2 { | 311 | ON_RESULT_FAILURE_2 { |
| 312 | m_page_table.Finalize(); | 312 | m_page_table.Finalize(); |
| 313 | }; | 313 | }; |
| 314 | 314 | ||
| 315 | // Ensure our memory is initialized. | ||
| 316 | m_memory.SetCurrentPageTable(*this); | ||
| 317 | m_memory.SetGPUDirtyManagers(m_dirty_memory_managers); | ||
| 318 | |||
| 315 | // Ensure we can insert the code region. | 319 | // Ensure we can insert the code region. |
| 316 | R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize, | 320 | R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize, |
| 317 | KMemoryState::Code), | 321 | KMemoryState::Code), |
| @@ -399,12 +403,16 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params, | |||
| 399 | False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge); | 403 | False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge); |
| 400 | R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, | 404 | R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, |
| 401 | params.code_address, code_size, m_system_resource, res_limit, | 405 | params.code_address, code_size, m_system_resource, res_limit, |
| 402 | this->GetMemory(), aslr_space_start)); | 406 | m_memory, aslr_space_start)); |
| 403 | } | 407 | } |
| 404 | ON_RESULT_FAILURE_2 { | 408 | ON_RESULT_FAILURE_2 { |
| 405 | m_page_table.Finalize(); | 409 | m_page_table.Finalize(); |
| 406 | }; | 410 | }; |
| 407 | 411 | ||
| 412 | // Ensure our memory is initialized. | ||
| 413 | m_memory.SetCurrentPageTable(*this); | ||
| 414 | m_memory.SetGPUDirtyManagers(m_dirty_memory_managers); | ||
| 415 | |||
| 408 | // Ensure we can insert the code region. | 416 | // Ensure we can insert the code region. |
| 409 | R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState::Code), | 417 | R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState::Code), |
| 410 | ResultInvalidMemoryRegion); | 418 | ResultInvalidMemoryRegion); |
| @@ -1094,8 +1102,7 @@ void KProcess::UnpinThread(KThread* thread) { | |||
| 1094 | 1102 | ||
| 1095 | Result KProcess::GetThreadList(s32* out_num_threads, KProcessAddress out_thread_ids, | 1103 | Result KProcess::GetThreadList(s32* out_num_threads, KProcessAddress out_thread_ids, |
| 1096 | s32 max_out_count) { | 1104 | s32 max_out_count) { |
| 1097 | // TODO: use current memory reference | 1105 | auto& memory = this->GetMemory(); |
| 1098 | auto& memory = m_kernel.System().ApplicationMemory(); | ||
| 1099 | 1106 | ||
| 1100 | // Lock the list. | 1107 | // Lock the list. |
| 1101 | KScopedLightLock lk(m_list_lock); | 1108 | KScopedLightLock lk(m_list_lock); |
| @@ -1128,14 +1135,15 @@ void KProcess::Switch(KProcess* cur_process, KProcess* next_process) {} | |||
| 1128 | KProcess::KProcess(KernelCore& kernel) | 1135 | KProcess::KProcess(KernelCore& kernel) |
| 1129 | : KAutoObjectWithSlabHeapAndContainer(kernel), m_page_table{kernel}, m_state_lock{kernel}, | 1136 | : KAutoObjectWithSlabHeapAndContainer(kernel), m_page_table{kernel}, m_state_lock{kernel}, |
| 1130 | m_list_lock{kernel}, m_cond_var{kernel.System()}, m_address_arbiter{kernel.System()}, | 1137 | m_list_lock{kernel}, m_cond_var{kernel.System()}, m_address_arbiter{kernel.System()}, |
| 1131 | m_handle_table{kernel} {} | 1138 | m_handle_table{kernel}, m_dirty_memory_managers{}, |
| 1139 | m_exclusive_monitor{}, m_memory{kernel.System()} {} | ||
| 1132 | KProcess::~KProcess() = default; | 1140 | KProcess::~KProcess() = default; |
| 1133 | 1141 | ||
| 1134 | Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size, | 1142 | Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size, |
| 1135 | KProcessAddress aslr_space_start, bool is_hbl) { | 1143 | KProcessAddress aslr_space_start, bool is_hbl) { |
| 1136 | // Create a resource limit for the process. | 1144 | // Create a resource limit for the process. |
| 1137 | const auto physical_memory_size = | 1145 | const auto pool = static_cast<KMemoryManager::Pool>(metadata.GetPoolPartition()); |
| 1138 | m_kernel.MemoryManager().GetSize(Kernel::KMemoryManager::Pool::Application); | 1146 | const auto physical_memory_size = m_kernel.MemoryManager().GetSize(pool); |
| 1139 | auto* res_limit = | 1147 | auto* res_limit = |
| 1140 | Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size); | 1148 | Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size); |
| 1141 | 1149 | ||
| @@ -1146,8 +1154,10 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std: | |||
| 1146 | Svc::CreateProcessFlag flag{}; | 1154 | Svc::CreateProcessFlag flag{}; |
| 1147 | u64 code_address{}; | 1155 | u64 code_address{}; |
| 1148 | 1156 | ||
| 1149 | // We are an application. | 1157 | // Determine if we are an application. |
| 1150 | flag |= Svc::CreateProcessFlag::IsApplication; | 1158 | if (pool == KMemoryManager::Pool::Application) { |
| 1159 | flag |= Svc::CreateProcessFlag::IsApplication; | ||
| 1160 | } | ||
| 1151 | 1161 | ||
| 1152 | // If we are 64-bit, create as such. | 1162 | // If we are 64-bit, create as such. |
| 1153 | if (metadata.Is64BitProgram()) { | 1163 | if (metadata.Is64BitProgram()) { |
| @@ -1196,8 +1206,8 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std: | |||
| 1196 | std::memcpy(params.name.data(), name.data(), sizeof(params.name)); | 1206 | std::memcpy(params.name.data(), name.data(), sizeof(params.name)); |
| 1197 | 1207 | ||
| 1198 | // Initialize for application process. | 1208 | // Initialize for application process. |
| 1199 | R_TRY(this->Initialize(params, metadata.GetKernelCapabilities(), res_limit, | 1209 | R_TRY(this->Initialize(params, metadata.GetKernelCapabilities(), res_limit, pool, |
| 1200 | KMemoryManager::Pool::Application, aslr_space_start)); | 1210 | aslr_space_start)); |
| 1201 | 1211 | ||
| 1202 | // Assign remaining properties. | 1212 | // Assign remaining properties. |
| 1203 | m_is_hbl = is_hbl; | 1213 | m_is_hbl = is_hbl; |
| @@ -1223,22 +1233,25 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) { | |||
| 1223 | ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite); | 1233 | ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite); |
| 1224 | 1234 | ||
| 1225 | #ifdef HAS_NCE | 1235 | #ifdef HAS_NCE |
| 1226 | if (Settings::IsNceEnabled()) { | 1236 | if (this->IsApplication() && Settings::IsNceEnabled()) { |
| 1227 | auto& buffer = m_kernel.System().DeviceMemory().buffer; | 1237 | auto& buffer = m_kernel.System().DeviceMemory().buffer; |
| 1228 | const auto& code = code_set.CodeSegment(); | 1238 | const auto& code = code_set.CodeSegment(); |
| 1229 | const auto& patch = code_set.PatchSegment(); | 1239 | const auto& patch = code_set.PatchSegment(); |
| 1230 | buffer.Protect(GetInteger(base_addr + code.addr), code.size, true, true, true); | 1240 | buffer.Protect(GetInteger(base_addr + code.addr), code.size, |
| 1231 | 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); | ||
| 1232 | ReprotectSegment(code_set.PatchSegment(), Svc::MemoryPermission::None); | 1244 | ReprotectSegment(code_set.PatchSegment(), Svc::MemoryPermission::None); |
| 1233 | } | 1245 | } |
| 1234 | #endif | 1246 | #endif |
| 1235 | } | 1247 | } |
| 1236 | 1248 | ||
| 1237 | void KProcess::InitializeInterfaces() { | 1249 | void KProcess::InitializeInterfaces() { |
| 1238 | this->GetMemory().SetCurrentPageTable(*this); | 1250 | m_exclusive_monitor = |
| 1251 | Core::MakeExclusiveMonitor(this->GetMemory(), Core::Hardware::NUM_CPU_CORES); | ||
| 1239 | 1252 | ||
| 1240 | #ifdef HAS_NCE | 1253 | #ifdef HAS_NCE |
| 1241 | if (this->Is64Bit() && Settings::IsNceEnabled()) { | 1254 | if (this->IsApplication() && Settings::IsNceEnabled()) { |
| 1242 | for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { | 1255 | for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { |
| 1243 | m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i); | 1256 | m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i); |
| 1244 | } | 1257 | } |
| @@ -1248,13 +1261,13 @@ void KProcess::InitializeInterfaces() { | |||
| 1248 | for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { | 1261 | for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { |
| 1249 | m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic64>( | 1262 | m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic64>( |
| 1250 | m_kernel.System(), m_kernel.IsMulticore(), this, | 1263 | m_kernel.System(), m_kernel.IsMulticore(), this, |
| 1251 | static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i); | 1264 | static_cast<Core::DynarmicExclusiveMonitor&>(*m_exclusive_monitor), i); |
| 1252 | } | 1265 | } |
| 1253 | } else { | 1266 | } else { |
| 1254 | for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { | 1267 | for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { |
| 1255 | m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic32>( | 1268 | m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic32>( |
| 1256 | m_kernel.System(), m_kernel.IsMulticore(), this, | 1269 | m_kernel.System(), m_kernel.IsMulticore(), this, |
| 1257 | static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i); | 1270 | static_cast<Core::DynarmicExclusiveMonitor&>(*m_exclusive_monitor), i); |
| 1258 | } | 1271 | } |
| 1259 | } | 1272 | } |
| 1260 | } | 1273 | } |
| @@ -1305,9 +1318,10 @@ bool KProcess::RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointT | |||
| 1305 | return true; | 1318 | return true; |
| 1306 | } | 1319 | } |
| 1307 | 1320 | ||
| 1308 | Core::Memory::Memory& KProcess::GetMemory() const { | 1321 | void KProcess::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) { |
| 1309 | // TODO: per-process memory | 1322 | for (auto& manager : m_dirty_memory_managers) { |
| 1310 | return m_kernel.System().ApplicationMemory(); | 1323 | manager.Gather(callback); |
| 1324 | } | ||
| 1311 | } | 1325 | } |
| 1312 | 1326 | ||
| 1313 | } // namespace Kernel | 1327 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index 4b114e39b..53c0e3316 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | #include "core/arm/arm_interface.h" | 8 | #include "core/arm/arm_interface.h" |
| 9 | #include "core/file_sys/program_metadata.h" | 9 | #include "core/file_sys/program_metadata.h" |
| 10 | #include "core/gpu_dirty_memory_manager.h" | ||
| 10 | #include "core/hle/kernel/code_set.h" | 11 | #include "core/hle/kernel/code_set.h" |
| 11 | #include "core/hle/kernel/k_address_arbiter.h" | 12 | #include "core/hle/kernel/k_address_arbiter.h" |
| 12 | #include "core/hle/kernel/k_capabilities.h" | 13 | #include "core/hle/kernel/k_capabilities.h" |
| @@ -17,6 +18,7 @@ | |||
| 17 | #include "core/hle/kernel/k_system_resource.h" | 18 | #include "core/hle/kernel/k_system_resource.h" |
| 18 | #include "core/hle/kernel/k_thread.h" | 19 | #include "core/hle/kernel/k_thread.h" |
| 19 | #include "core/hle/kernel/k_thread_local_page.h" | 20 | #include "core/hle/kernel/k_thread_local_page.h" |
| 21 | #include "core/memory.h" | ||
| 20 | 22 | ||
| 21 | namespace Kernel { | 23 | namespace Kernel { |
| 22 | 24 | ||
| @@ -126,6 +128,9 @@ private: | |||
| 126 | #ifdef HAS_NCE | 128 | #ifdef HAS_NCE |
| 127 | std::unordered_map<u64, u64> m_post_handlers{}; | 129 | std::unordered_map<u64, u64> m_post_handlers{}; |
| 128 | #endif | 130 | #endif |
| 131 | std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES> m_dirty_memory_managers; | ||
| 132 | std::unique_ptr<Core::ExclusiveMonitor> m_exclusive_monitor; | ||
| 133 | Core::Memory::Memory m_memory; | ||
| 129 | 134 | ||
| 130 | private: | 135 | private: |
| 131 | Result StartTermination(); | 136 | Result StartTermination(); |
| @@ -502,7 +507,15 @@ public: | |||
| 502 | 507 | ||
| 503 | void InitializeInterfaces(); | 508 | void InitializeInterfaces(); |
| 504 | 509 | ||
| 505 | Core::Memory::Memory& GetMemory() const; | 510 | Core::Memory::Memory& GetMemory() { |
| 511 | return m_memory; | ||
| 512 | } | ||
| 513 | |||
| 514 | void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback); | ||
| 515 | |||
| 516 | Core::ExclusiveMonitor& GetExclusiveMonitor() const { | ||
| 517 | return *m_exclusive_monitor; | ||
| 518 | } | ||
| 506 | 519 | ||
| 507 | public: | 520 | public: |
| 508 | // Overridden parent functions. | 521 | // Overridden parent functions. |
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index e33a88e24..adaabdd6d 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "common/scope_exit.h" | 10 | #include "common/scope_exit.h" |
| 11 | #include "common/scratch_buffer.h" | ||
| 11 | #include "core/core.h" | 12 | #include "core/core.h" |
| 12 | #include "core/core_timing.h" | 13 | #include "core/core_timing.h" |
| 13 | #include "core/hle/kernel/k_client_port.h" | 14 | #include "core/hle/kernel/k_client_port.h" |
| @@ -29,12 +30,138 @@ namespace Kernel { | |||
| 29 | 30 | ||
| 30 | namespace { | 31 | namespace { |
| 31 | 32 | ||
| 33 | constexpr inline size_t PointerTransferBufferAlignment = 0x10; | ||
| 34 | constexpr inline size_t ReceiveListDataSize = | ||
| 35 | MessageBuffer::MessageHeader::ReceiveListCountType_CountMax * | ||
| 36 | MessageBuffer::ReceiveListEntry::GetDataSize() / sizeof(u32); | ||
| 37 | |||
| 38 | using ThreadQueueImplForKServerSessionRequest = KThreadQueue; | ||
| 39 | |||
| 40 | class ReceiveList { | ||
| 41 | public: | ||
| 42 | static constexpr int GetEntryCount(const MessageBuffer::MessageHeader& header) { | ||
| 43 | const auto count = header.GetReceiveListCount(); | ||
| 44 | switch (count) { | ||
| 45 | case MessageBuffer::MessageHeader::ReceiveListCountType_None: | ||
| 46 | return 0; | ||
| 47 | case MessageBuffer::MessageHeader::ReceiveListCountType_ToMessageBuffer: | ||
| 48 | return 0; | ||
| 49 | case MessageBuffer::MessageHeader::ReceiveListCountType_ToSingleBuffer: | ||
| 50 | return 1; | ||
| 51 | default: | ||
| 52 | return count - MessageBuffer::MessageHeader::ReceiveListCountType_CountOffset; | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | explicit ReceiveList(const u32* dst_msg, uint64_t dst_address, | ||
| 57 | KProcessPageTable& dst_page_table, | ||
| 58 | const MessageBuffer::MessageHeader& dst_header, | ||
| 59 | const MessageBuffer::SpecialHeader& dst_special_header, size_t msg_size, | ||
| 60 | size_t out_offset, s32 dst_recv_list_idx, bool is_tls) { | ||
| 61 | m_recv_list_count = dst_header.GetReceiveListCount(); | ||
| 62 | m_msg_buffer_end = dst_address + sizeof(u32) * out_offset; | ||
| 63 | m_msg_buffer_space_end = dst_address + msg_size; | ||
| 64 | |||
| 65 | // NOTE: Nintendo calculates the receive list index here using the special header. | ||
| 66 | // We pre-calculate it in the caller, and pass it as a parameter. | ||
| 67 | (void)dst_special_header; | ||
| 68 | |||
| 69 | const u32* recv_list = dst_msg + dst_recv_list_idx; | ||
| 70 | const auto entry_count = GetEntryCount(dst_header); | ||
| 71 | |||
| 72 | if (is_tls) { | ||
| 73 | // Messages from TLS to TLS are contained within one page. | ||
| 74 | std::memcpy(m_data.data(), recv_list, | ||
| 75 | entry_count * MessageBuffer::ReceiveListEntry::GetDataSize()); | ||
| 76 | } else { | ||
| 77 | // If any buffer is not from TLS, perform a normal read instead. | ||
| 78 | uint64_t cur_addr = dst_address + dst_recv_list_idx * sizeof(u32); | ||
| 79 | dst_page_table.GetMemory().ReadBlock( | ||
| 80 | cur_addr, m_data.data(), | ||
| 81 | entry_count * MessageBuffer::ReceiveListEntry::GetDataSize()); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | bool IsIndex() const { | ||
| 86 | return m_recv_list_count > | ||
| 87 | static_cast<s32>(MessageBuffer::MessageHeader::ReceiveListCountType_CountOffset); | ||
| 88 | } | ||
| 89 | |||
| 90 | bool IsToMessageBuffer() const { | ||
| 91 | return m_recv_list_count == | ||
| 92 | MessageBuffer::MessageHeader::ReceiveListCountType_ToMessageBuffer; | ||
| 93 | } | ||
| 94 | |||
| 95 | void GetBuffer(uint64_t& out, size_t size, int& key) const { | ||
| 96 | switch (m_recv_list_count) { | ||
| 97 | case MessageBuffer::MessageHeader::ReceiveListCountType_None: { | ||
| 98 | out = 0; | ||
| 99 | break; | ||
| 100 | } | ||
| 101 | case MessageBuffer::MessageHeader::ReceiveListCountType_ToMessageBuffer: { | ||
| 102 | const uint64_t buf = | ||
| 103 | Common::AlignUp(m_msg_buffer_end + key, PointerTransferBufferAlignment); | ||
| 104 | |||
| 105 | if ((buf < buf + size) && (buf + size <= m_msg_buffer_space_end)) { | ||
| 106 | out = buf; | ||
| 107 | key = static_cast<int>(buf + size - m_msg_buffer_end); | ||
| 108 | } else { | ||
| 109 | out = 0; | ||
| 110 | } | ||
| 111 | break; | ||
| 112 | } | ||
| 113 | case MessageBuffer::MessageHeader::ReceiveListCountType_ToSingleBuffer: { | ||
| 114 | const MessageBuffer::ReceiveListEntry entry(m_data[0], m_data[1]); | ||
| 115 | const uint64_t buf = | ||
| 116 | Common::AlignUp(entry.GetAddress() + key, PointerTransferBufferAlignment); | ||
| 117 | |||
| 118 | const uint64_t entry_addr = entry.GetAddress(); | ||
| 119 | const size_t entry_size = entry.GetSize(); | ||
| 120 | |||
| 121 | if ((buf < buf + size) && (entry_addr < entry_addr + entry_size) && | ||
| 122 | (buf + size <= entry_addr + entry_size)) { | ||
| 123 | out = buf; | ||
| 124 | key = static_cast<int>(buf + size - entry_addr); | ||
| 125 | } else { | ||
| 126 | out = 0; | ||
| 127 | } | ||
| 128 | break; | ||
| 129 | } | ||
| 130 | default: { | ||
| 131 | if (key < m_recv_list_count - | ||
| 132 | static_cast<s32>( | ||
| 133 | MessageBuffer::MessageHeader::ReceiveListCountType_CountOffset)) { | ||
| 134 | const MessageBuffer::ReceiveListEntry entry(m_data[2 * key + 0], | ||
| 135 | m_data[2 * key + 1]); | ||
| 136 | |||
| 137 | const uintptr_t entry_addr = entry.GetAddress(); | ||
| 138 | const size_t entry_size = entry.GetSize(); | ||
| 139 | |||
| 140 | if ((entry_addr < entry_addr + entry_size) && (entry_size >= size)) { | ||
| 141 | out = entry_addr; | ||
| 142 | } | ||
| 143 | } else { | ||
| 144 | out = 0; | ||
| 145 | } | ||
| 146 | break; | ||
| 147 | } | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | private: | ||
| 152 | std::array<u32, ReceiveListDataSize> m_data; | ||
| 153 | s32 m_recv_list_count; | ||
| 154 | uint64_t m_msg_buffer_end; | ||
| 155 | uint64_t m_msg_buffer_space_end; | ||
| 156 | }; | ||
| 157 | |||
| 32 | template <bool MoveHandleAllowed> | 158 | template <bool MoveHandleAllowed> |
| 33 | Result ProcessMessageSpecialData(KProcess& dst_process, KProcess& src_process, KThread& src_thread, | 159 | Result ProcessMessageSpecialData(s32& offset, KProcess& dst_process, KProcess& src_process, |
| 34 | MessageBuffer& dst_msg, const MessageBuffer& src_msg, | 160 | KThread& src_thread, const MessageBuffer& dst_msg, |
| 35 | MessageBuffer::SpecialHeader& src_special_header) { | 161 | const MessageBuffer& src_msg, |
| 162 | const MessageBuffer::SpecialHeader& src_special_header) { | ||
| 36 | // Copy the special header to the destination. | 163 | // Copy the special header to the destination. |
| 37 | s32 offset = dst_msg.Set(src_special_header); | 164 | offset = dst_msg.Set(src_special_header); |
| 38 | 165 | ||
| 39 | // Copy the process ID. | 166 | // Copy the process ID. |
| 40 | if (src_special_header.GetHasProcessId()) { | 167 | if (src_special_header.GetHasProcessId()) { |
| @@ -110,6 +237,102 @@ Result ProcessMessageSpecialData(KProcess& dst_process, KProcess& src_process, K | |||
| 110 | R_RETURN(result); | 237 | R_RETURN(result); |
| 111 | } | 238 | } |
| 112 | 239 | ||
| 240 | Result ProcessReceiveMessagePointerDescriptors(int& offset, int& pointer_key, | ||
| 241 | KProcessPageTable& dst_page_table, | ||
| 242 | KProcessPageTable& src_page_table, | ||
| 243 | const MessageBuffer& dst_msg, | ||
| 244 | const MessageBuffer& src_msg, | ||
| 245 | const ReceiveList& dst_recv_list, bool dst_user) { | ||
| 246 | // Get the offset at the start of processing. | ||
| 247 | const int cur_offset = offset; | ||
| 248 | |||
| 249 | // Get the pointer desc. | ||
| 250 | MessageBuffer::PointerDescriptor src_desc(src_msg, cur_offset); | ||
| 251 | offset += static_cast<int>(MessageBuffer::PointerDescriptor::GetDataSize() / sizeof(u32)); | ||
| 252 | |||
| 253 | // Extract address/size. | ||
| 254 | const uint64_t src_pointer = src_desc.GetAddress(); | ||
| 255 | const size_t recv_size = src_desc.GetSize(); | ||
| 256 | uint64_t recv_pointer = 0; | ||
| 257 | |||
| 258 | // Process the buffer, if it has a size. | ||
| 259 | if (recv_size > 0) { | ||
| 260 | // If using indexing, set index. | ||
| 261 | if (dst_recv_list.IsIndex()) { | ||
| 262 | pointer_key = src_desc.GetIndex(); | ||
| 263 | } | ||
| 264 | |||
| 265 | // Get the buffer. | ||
| 266 | dst_recv_list.GetBuffer(recv_pointer, recv_size, pointer_key); | ||
| 267 | R_UNLESS(recv_pointer != 0, ResultOutOfResource); | ||
| 268 | |||
| 269 | // Perform the pointer data copy. | ||
| 270 | if (dst_user) { | ||
| 271 | R_TRY(src_page_table.CopyMemoryFromHeapToHeapWithoutCheckDestination( | ||
| 272 | dst_page_table, recv_pointer, recv_size, KMemoryState::FlagReferenceCounted, | ||
| 273 | KMemoryState::FlagReferenceCounted, | ||
| 274 | KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite, | ||
| 275 | KMemoryAttribute::Uncached | KMemoryAttribute::Locked, KMemoryAttribute::Locked, | ||
| 276 | src_pointer, KMemoryState::FlagLinearMapped, KMemoryState::FlagLinearMapped, | ||
| 277 | KMemoryPermission::UserRead, KMemoryAttribute::Uncached, KMemoryAttribute::None)); | ||
| 278 | } else { | ||
| 279 | R_TRY(src_page_table.CopyMemoryFromLinearToUser( | ||
| 280 | recv_pointer, recv_size, src_pointer, KMemoryState::FlagLinearMapped, | ||
| 281 | KMemoryState::FlagLinearMapped, KMemoryPermission::UserRead, | ||
| 282 | KMemoryAttribute::Uncached, KMemoryAttribute::None)); | ||
| 283 | } | ||
| 284 | } | ||
| 285 | |||
| 286 | // Set the output descriptor. | ||
| 287 | dst_msg.Set(cur_offset, MessageBuffer::PointerDescriptor(reinterpret_cast<void*>(recv_pointer), | ||
| 288 | recv_size, src_desc.GetIndex())); | ||
| 289 | |||
| 290 | R_SUCCEED(); | ||
| 291 | } | ||
| 292 | |||
| 293 | constexpr Result GetMapAliasMemoryState(KMemoryState& out, | ||
| 294 | MessageBuffer::MapAliasDescriptor::Attribute attr) { | ||
| 295 | switch (attr) { | ||
| 296 | case MessageBuffer::MapAliasDescriptor::Attribute::Ipc: | ||
| 297 | out = KMemoryState::Ipc; | ||
| 298 | break; | ||
| 299 | case MessageBuffer::MapAliasDescriptor::Attribute::NonSecureIpc: | ||
| 300 | out = KMemoryState::NonSecureIpc; | ||
| 301 | break; | ||
| 302 | case MessageBuffer::MapAliasDescriptor::Attribute::NonDeviceIpc: | ||
| 303 | out = KMemoryState::NonDeviceIpc; | ||
| 304 | break; | ||
| 305 | default: | ||
| 306 | R_THROW(ResultInvalidCombination); | ||
| 307 | } | ||
| 308 | |||
| 309 | R_SUCCEED(); | ||
| 310 | } | ||
| 311 | |||
| 312 | constexpr Result GetMapAliasTestStateAndAttributeMask(KMemoryState& out_state, | ||
| 313 | KMemoryAttribute& out_attr_mask, | ||
| 314 | KMemoryState state) { | ||
| 315 | switch (state) { | ||
| 316 | case KMemoryState::Ipc: | ||
| 317 | out_state = KMemoryState::FlagCanUseIpc; | ||
| 318 | out_attr_mask = | ||
| 319 | KMemoryAttribute::Uncached | KMemoryAttribute::DeviceShared | KMemoryAttribute::Locked; | ||
| 320 | break; | ||
| 321 | case KMemoryState::NonSecureIpc: | ||
| 322 | out_state = KMemoryState::FlagCanUseNonSecureIpc; | ||
| 323 | out_attr_mask = KMemoryAttribute::Uncached | KMemoryAttribute::Locked; | ||
| 324 | break; | ||
| 325 | case KMemoryState::NonDeviceIpc: | ||
| 326 | out_state = KMemoryState::FlagCanUseNonDeviceIpc; | ||
| 327 | out_attr_mask = KMemoryAttribute::Uncached | KMemoryAttribute::Locked; | ||
| 328 | break; | ||
| 329 | default: | ||
| 330 | R_THROW(ResultInvalidCombination); | ||
| 331 | } | ||
| 332 | |||
| 333 | R_SUCCEED(); | ||
| 334 | } | ||
| 335 | |||
| 113 | void CleanupSpecialData(KProcess& dst_process, u32* dst_msg_ptr, size_t dst_buffer_size) { | 336 | void CleanupSpecialData(KProcess& dst_process, u32* dst_msg_ptr, size_t dst_buffer_size) { |
| 114 | // Parse the message. | 337 | // Parse the message. |
| 115 | const MessageBuffer dst_msg(dst_msg_ptr, dst_buffer_size); | 338 | const MessageBuffer dst_msg(dst_msg_ptr, dst_buffer_size); |
| @@ -144,166 +367,855 @@ void CleanupSpecialData(KProcess& dst_process, u32* dst_msg_ptr, size_t dst_buff | |||
| 144 | } | 367 | } |
| 145 | } | 368 | } |
| 146 | 369 | ||
| 147 | } // namespace | 370 | Result CleanupServerHandles(KernelCore& kernel, uint64_t message, size_t buffer_size, |
| 371 | KPhysicalAddress message_paddr) { | ||
| 372 | // Server is assumed to be current thread. | ||
| 373 | KThread& thread = GetCurrentThread(kernel); | ||
| 148 | 374 | ||
| 149 | using ThreadQueueImplForKServerSessionRequest = KThreadQueue; | 375 | // Get the linear message pointer. |
| 376 | u32* msg_ptr; | ||
| 377 | if (message) { | ||
| 378 | msg_ptr = kernel.System().DeviceMemory().GetPointer<u32>(message_paddr); | ||
| 379 | } else { | ||
| 380 | msg_ptr = GetCurrentMemory(kernel).GetPointer<u32>(thread.GetTlsAddress()); | ||
| 381 | buffer_size = MessageBufferSize; | ||
| 382 | message = GetInteger(thread.GetTlsAddress()); | ||
| 383 | } | ||
| 150 | 384 | ||
| 151 | KServerSession::KServerSession(KernelCore& kernel) | 385 | // Parse the message. |
| 152 | : KSynchronizationObject{kernel}, m_lock{m_kernel} {} | 386 | const MessageBuffer msg(msg_ptr, buffer_size); |
| 387 | const MessageBuffer::MessageHeader header(msg); | ||
| 388 | const MessageBuffer::SpecialHeader special_header(msg, header); | ||
| 153 | 389 | ||
| 154 | KServerSession::~KServerSession() = default; | 390 | // Check that the size is big enough. |
| 391 | R_UNLESS(MessageBuffer::GetMessageBufferSize(header, special_header) <= buffer_size, | ||
| 392 | ResultInvalidCombination); | ||
| 393 | |||
| 394 | // If there's a special header, there may be move handles we need to close. | ||
| 395 | if (header.GetHasSpecialHeader()) { | ||
| 396 | // Determine the offset to the start of handles. | ||
| 397 | auto offset = msg.GetSpecialDataIndex(header, special_header); | ||
| 398 | if (special_header.GetHasProcessId()) { | ||
| 399 | offset += static_cast<int>(sizeof(u64) / sizeof(u32)); | ||
| 400 | } | ||
| 401 | if (auto copy_count = special_header.GetCopyHandleCount(); copy_count > 0) { | ||
| 402 | offset += static_cast<int>((sizeof(Svc::Handle) * copy_count) / sizeof(u32)); | ||
| 403 | } | ||
| 155 | 404 | ||
| 156 | void KServerSession::Destroy() { | 405 | // Get the handle table. |
| 157 | m_parent->OnServerClosed(); | 406 | auto& handle_table = thread.GetOwnerProcess()->GetHandleTable(); |
| 158 | 407 | ||
| 159 | this->CleanupRequests(); | 408 | // Close the handles. |
| 409 | for (auto i = 0; i < special_header.GetMoveHandleCount(); ++i) { | ||
| 410 | handle_table.Remove(msg.GetHandle(offset)); | ||
| 411 | offset += static_cast<int>(sizeof(Svc::Handle) / sizeof(u32)); | ||
| 412 | } | ||
| 413 | } | ||
| 160 | 414 | ||
| 161 | m_parent->Close(); | 415 | R_SUCCEED(); |
| 162 | } | 416 | } |
| 163 | 417 | ||
| 164 | void KServerSession::OnClientClosed() { | 418 | Result CleanupServerMap(KSessionRequest* request, KProcess* server_process) { |
| 165 | KScopedLightLock lk{m_lock}; | 419 | // If there's no server process, there's nothing to clean up. |
| 420 | R_SUCCEED_IF(server_process == nullptr); | ||
| 166 | 421 | ||
| 167 | // Handle any pending requests. | 422 | // Get the page table. |
| 168 | KSessionRequest* prev_request = nullptr; | 423 | auto& server_page_table = server_process->GetPageTable(); |
| 169 | while (true) { | ||
| 170 | // Declare variables for processing the request. | ||
| 171 | KSessionRequest* request = nullptr; | ||
| 172 | KEvent* event = nullptr; | ||
| 173 | KThread* thread = nullptr; | ||
| 174 | bool cur_request = false; | ||
| 175 | bool terminate = false; | ||
| 176 | 424 | ||
| 177 | // Get the next request. | 425 | // Cleanup Send mappings. |
| 178 | { | 426 | for (size_t i = 0; i < request->GetSendCount(); ++i) { |
| 179 | KScopedSchedulerLock sl{m_kernel}; | 427 | R_TRY(server_page_table.CleanupForIpcServer(request->GetSendServerAddress(i), |
| 428 | request->GetSendSize(i), | ||
| 429 | request->GetSendMemoryState(i))); | ||
| 430 | } | ||
| 180 | 431 | ||
| 181 | if (m_current_request != nullptr && m_current_request != prev_request) { | 432 | // Cleanup Receive mappings. |
| 182 | // Set the request, open a reference as we process it. | 433 | for (size_t i = 0; i < request->GetReceiveCount(); ++i) { |
| 183 | request = m_current_request; | 434 | R_TRY(server_page_table.CleanupForIpcServer(request->GetReceiveServerAddress(i), |
| 184 | request->Open(); | 435 | request->GetReceiveSize(i), |
| 185 | cur_request = true; | 436 | request->GetReceiveMemoryState(i))); |
| 437 | } | ||
| 186 | 438 | ||
| 187 | // Get thread and event for the request. | 439 | // Cleanup Exchange mappings. |
| 188 | thread = request->GetThread(); | 440 | for (size_t i = 0; i < request->GetExchangeCount(); ++i) { |
| 189 | event = request->GetEvent(); | 441 | R_TRY(server_page_table.CleanupForIpcServer(request->GetExchangeServerAddress(i), |
| 442 | request->GetExchangeSize(i), | ||
| 443 | request->GetExchangeMemoryState(i))); | ||
| 444 | } | ||
| 190 | 445 | ||
| 191 | // If the thread is terminating, handle that. | 446 | R_SUCCEED(); |
| 192 | if (thread->IsTerminationRequested()) { | 447 | } |
| 193 | request->ClearThread(); | ||
| 194 | request->ClearEvent(); | ||
| 195 | terminate = true; | ||
| 196 | } | ||
| 197 | 448 | ||
| 198 | prev_request = request; | 449 | Result CleanupClientMap(KSessionRequest* request, KProcessPageTable* client_page_table) { |
| 199 | } else if (!m_request_list.empty()) { | 450 | // If there's no client page table, there's nothing to clean up. |
| 200 | // Pop the request from the front of the list. | 451 | R_SUCCEED_IF(client_page_table == nullptr); |
| 201 | request = std::addressof(m_request_list.front()); | ||
| 202 | m_request_list.pop_front(); | ||
| 203 | 452 | ||
| 204 | // Get thread and event for the request. | 453 | // Cleanup Send mappings. |
| 205 | thread = request->GetThread(); | 454 | for (size_t i = 0; i < request->GetSendCount(); ++i) { |
| 206 | event = request->GetEvent(); | 455 | R_TRY(client_page_table->CleanupForIpcClient(request->GetSendClientAddress(i), |
| 207 | } | 456 | request->GetSendSize(i), |
| 457 | request->GetSendMemoryState(i))); | ||
| 458 | } | ||
| 459 | |||
| 460 | // Cleanup Receive mappings. | ||
| 461 | for (size_t i = 0; i < request->GetReceiveCount(); ++i) { | ||
| 462 | R_TRY(client_page_table->CleanupForIpcClient(request->GetReceiveClientAddress(i), | ||
| 463 | request->GetReceiveSize(i), | ||
| 464 | request->GetReceiveMemoryState(i))); | ||
| 465 | } | ||
| 466 | |||
| 467 | // Cleanup Exchange mappings. | ||
| 468 | for (size_t i = 0; i < request->GetExchangeCount(); ++i) { | ||
| 469 | R_TRY(client_page_table->CleanupForIpcClient(request->GetExchangeClientAddress(i), | ||
| 470 | request->GetExchangeSize(i), | ||
| 471 | request->GetExchangeMemoryState(i))); | ||
| 472 | } | ||
| 473 | |||
| 474 | R_SUCCEED(); | ||
| 475 | } | ||
| 476 | |||
| 477 | Result CleanupMap(KSessionRequest* request, KProcess* server_process, | ||
| 478 | KProcessPageTable* client_page_table) { | ||
| 479 | // Cleanup the server map. | ||
| 480 | R_TRY(CleanupServerMap(request, server_process)); | ||
| 481 | |||
| 482 | // Cleanup the client map. | ||
| 483 | R_TRY(CleanupClientMap(request, client_page_table)); | ||
| 484 | |||
| 485 | R_SUCCEED(); | ||
| 486 | } | ||
| 487 | |||
| 488 | Result ProcessReceiveMessageMapAliasDescriptors(int& offset, KProcessPageTable& dst_page_table, | ||
| 489 | KProcessPageTable& src_page_table, | ||
| 490 | const MessageBuffer& dst_msg, | ||
| 491 | const MessageBuffer& src_msg, | ||
| 492 | KSessionRequest* request, KMemoryPermission perm, | ||
| 493 | bool send) { | ||
| 494 | // Get the offset at the start of processing. | ||
| 495 | const int cur_offset = offset; | ||
| 496 | |||
| 497 | // Get the map alias descriptor. | ||
| 498 | MessageBuffer::MapAliasDescriptor src_desc(src_msg, cur_offset); | ||
| 499 | offset += static_cast<int>(MessageBuffer::MapAliasDescriptor::GetDataSize() / sizeof(u32)); | ||
| 500 | |||
| 501 | // Extract address/size. | ||
| 502 | const KProcessAddress src_address = src_desc.GetAddress(); | ||
| 503 | const size_t size = src_desc.GetSize(); | ||
| 504 | KProcessAddress dst_address = 0; | ||
| 505 | |||
| 506 | // Determine the result memory state. | ||
| 507 | KMemoryState dst_state; | ||
| 508 | R_TRY(GetMapAliasMemoryState(dst_state, src_desc.GetAttribute())); | ||
| 509 | |||
| 510 | // Process the buffer, if it has a size. | ||
| 511 | if (size > 0) { | ||
| 512 | // Set up the source pages for ipc. | ||
| 513 | R_TRY(dst_page_table.SetupForIpc(std::addressof(dst_address), size, src_address, | ||
| 514 | src_page_table, perm, dst_state, send)); | ||
| 515 | |||
| 516 | // Ensure that we clean up on failure. | ||
| 517 | ON_RESULT_FAILURE { | ||
| 518 | dst_page_table.CleanupForIpcServer(dst_address, size, dst_state); | ||
| 519 | src_page_table.CleanupForIpcClient(src_address, size, dst_state); | ||
| 520 | }; | ||
| 521 | |||
| 522 | // Push the appropriate mapping. | ||
| 523 | if (perm == KMemoryPermission::UserRead) { | ||
| 524 | R_TRY(request->PushSend(src_address, dst_address, size, dst_state)); | ||
| 525 | } else if (send) { | ||
| 526 | R_TRY(request->PushExchange(src_address, dst_address, size, dst_state)); | ||
| 527 | } else { | ||
| 528 | R_TRY(request->PushReceive(src_address, dst_address, size, dst_state)); | ||
| 208 | } | 529 | } |
| 530 | } | ||
| 209 | 531 | ||
| 210 | // If there are no requests, we're done. | 532 | // Set the output descriptor. |
| 211 | if (request == nullptr) { | 533 | dst_msg.Set(cur_offset, |
| 212 | break; | 534 | MessageBuffer::MapAliasDescriptor(reinterpret_cast<void*>(GetInteger(dst_address)), |
| 535 | size, src_desc.GetAttribute())); | ||
| 536 | |||
| 537 | R_SUCCEED(); | ||
| 538 | } | ||
| 539 | |||
| 540 | Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_message_buffer, | ||
| 541 | size_t dst_buffer_size, KPhysicalAddress dst_message_paddr, | ||
| 542 | KThread& src_thread, uint64_t src_message_buffer, size_t src_buffer_size, | ||
| 543 | KServerSession* session, KSessionRequest* request) { | ||
| 544 | // Prepare variables for receive. | ||
| 545 | KThread& dst_thread = GetCurrentThread(kernel); | ||
| 546 | KProcess& dst_process = *(dst_thread.GetOwnerProcess()); | ||
| 547 | KProcess& src_process = *(src_thread.GetOwnerProcess()); | ||
| 548 | auto& dst_page_table = dst_process.GetPageTable(); | ||
| 549 | auto& src_page_table = src_process.GetPageTable(); | ||
| 550 | |||
| 551 | // NOTE: Session is used only for debugging, and so may go unused. | ||
| 552 | (void)session; | ||
| 553 | |||
| 554 | // The receive list is initially not broken. | ||
| 555 | recv_list_broken = false; | ||
| 556 | |||
| 557 | // Set the server process for the request. | ||
| 558 | request->SetServerProcess(std::addressof(dst_process)); | ||
| 559 | |||
| 560 | // Determine the message buffers. | ||
| 561 | u32 *dst_msg_ptr, *src_msg_ptr; | ||
| 562 | bool dst_user, src_user; | ||
| 563 | |||
| 564 | if (dst_message_buffer) { | ||
| 565 | dst_msg_ptr = kernel.System().DeviceMemory().GetPointer<u32>(dst_message_paddr); | ||
| 566 | dst_user = true; | ||
| 567 | } else { | ||
| 568 | dst_msg_ptr = dst_page_table.GetMemory().GetPointer<u32>(dst_thread.GetTlsAddress()); | ||
| 569 | dst_buffer_size = MessageBufferSize; | ||
| 570 | dst_message_buffer = GetInteger(dst_thread.GetTlsAddress()); | ||
| 571 | dst_user = false; | ||
| 572 | } | ||
| 573 | |||
| 574 | if (src_message_buffer) { | ||
| 575 | // NOTE: Nintendo does not check the result of this GetPhysicalAddress call. | ||
| 576 | src_msg_ptr = src_page_table.GetMemory().GetPointer<u32>(src_message_buffer); | ||
| 577 | src_user = true; | ||
| 578 | } else { | ||
| 579 | src_msg_ptr = src_page_table.GetMemory().GetPointer<u32>(src_thread.GetTlsAddress()); | ||
| 580 | src_buffer_size = MessageBufferSize; | ||
| 581 | src_message_buffer = GetInteger(src_thread.GetTlsAddress()); | ||
| 582 | src_user = false; | ||
| 583 | } | ||
| 584 | |||
| 585 | // Parse the headers. | ||
| 586 | const MessageBuffer dst_msg(dst_msg_ptr, dst_buffer_size); | ||
| 587 | const MessageBuffer src_msg(src_msg_ptr, src_buffer_size); | ||
| 588 | const MessageBuffer::MessageHeader dst_header(dst_msg); | ||
| 589 | const MessageBuffer::MessageHeader src_header(src_msg); | ||
| 590 | const MessageBuffer::SpecialHeader dst_special_header(dst_msg, dst_header); | ||
| 591 | const MessageBuffer::SpecialHeader src_special_header(src_msg, src_header); | ||
| 592 | |||
| 593 | // Get the end of the source message. | ||
| 594 | const size_t src_end_offset = | ||
| 595 | MessageBuffer::GetRawDataIndex(src_header, src_special_header) + src_header.GetRawCount(); | ||
| 596 | |||
| 597 | // Ensure that the headers fit. | ||
| 598 | R_UNLESS(MessageBuffer::GetMessageBufferSize(dst_header, dst_special_header) <= dst_buffer_size, | ||
| 599 | ResultInvalidCombination); | ||
| 600 | R_UNLESS(MessageBuffer::GetMessageBufferSize(src_header, src_special_header) <= src_buffer_size, | ||
| 601 | ResultInvalidCombination); | ||
| 602 | |||
| 603 | // Ensure the receive list offset is after the end of raw data. | ||
| 604 | if (dst_header.GetReceiveListOffset()) { | ||
| 605 | R_UNLESS(dst_header.GetReceiveListOffset() >= | ||
| 606 | MessageBuffer::GetRawDataIndex(dst_header, dst_special_header) + | ||
| 607 | dst_header.GetRawCount(), | ||
| 608 | ResultInvalidCombination); | ||
| 609 | } | ||
| 610 | |||
| 611 | // Ensure that the destination buffer is big enough to receive the source. | ||
| 612 | R_UNLESS(dst_buffer_size >= src_end_offset * sizeof(u32), ResultMessageTooLarge); | ||
| 613 | |||
| 614 | // Get the receive list. | ||
| 615 | const s32 dst_recv_list_idx = | ||
| 616 | MessageBuffer::GetReceiveListIndex(dst_header, dst_special_header); | ||
| 617 | ReceiveList dst_recv_list(dst_msg_ptr, dst_message_buffer, dst_page_table, dst_header, | ||
| 618 | dst_special_header, dst_buffer_size, src_end_offset, | ||
| 619 | dst_recv_list_idx, !dst_user); | ||
| 620 | |||
| 621 | // Ensure that the source special header isn't invalid. | ||
| 622 | const bool src_has_special_header = src_header.GetHasSpecialHeader(); | ||
| 623 | if (src_has_special_header) { | ||
| 624 | // Sending move handles from client -> server is not allowed. | ||
| 625 | R_UNLESS(src_special_header.GetMoveHandleCount() == 0, ResultInvalidCombination); | ||
| 626 | } | ||
| 627 | |||
| 628 | // Prepare for further processing. | ||
| 629 | int pointer_key = 0; | ||
| 630 | int offset = dst_msg.Set(src_header); | ||
| 631 | |||
| 632 | // Set up a guard to make sure that we end up in a clean state on error. | ||
| 633 | ON_RESULT_FAILURE { | ||
| 634 | // Cleanup mappings. | ||
| 635 | CleanupMap(request, std::addressof(dst_process), std::addressof(src_page_table)); | ||
| 636 | |||
| 637 | // Cleanup special data. | ||
| 638 | if (src_header.GetHasSpecialHeader()) { | ||
| 639 | CleanupSpecialData(dst_process, dst_msg_ptr, dst_buffer_size); | ||
| 213 | } | 640 | } |
| 214 | 641 | ||
| 215 | // All requests must have threads. | 642 | // Cleanup the header if the receive list isn't broken. |
| 216 | ASSERT(thread != nullptr); | 643 | if (!recv_list_broken) { |
| 644 | dst_msg.Set(dst_header); | ||
| 645 | if (dst_header.GetHasSpecialHeader()) { | ||
| 646 | dst_msg.Set(dst_special_header); | ||
| 647 | } | ||
| 648 | } | ||
| 649 | }; | ||
| 650 | |||
| 651 | // Process any special data. | ||
| 652 | if (src_header.GetHasSpecialHeader()) { | ||
| 653 | // After we process, make sure we track whether the receive list is broken. | ||
| 654 | SCOPE_EXIT({ | ||
| 655 | if (offset > dst_recv_list_idx) { | ||
| 656 | recv_list_broken = true; | ||
| 657 | } | ||
| 658 | }); | ||
| 217 | 659 | ||
| 218 | // Ensure that we close the request when done. | 660 | // Process special data. |
| 219 | SCOPE_EXIT({ request->Close(); }); | 661 | R_TRY(ProcessMessageSpecialData<false>(offset, dst_process, src_process, src_thread, |
| 662 | dst_msg, src_msg, src_special_header)); | ||
| 663 | } | ||
| 220 | 664 | ||
| 221 | // If we're terminating, close a reference to the thread and event. | 665 | // Process any pointer buffers. |
| 222 | if (terminate) { | 666 | for (auto i = 0; i < src_header.GetPointerCount(); ++i) { |
| 223 | thread->Close(); | 667 | // After we process, make sure we track whether the receive list is broken. |
| 224 | if (event != nullptr) { | 668 | SCOPE_EXIT({ |
| 225 | event->Close(); | 669 | if (offset > dst_recv_list_idx) { |
| 670 | recv_list_broken = true; | ||
| 671 | } | ||
| 672 | }); | ||
| 673 | |||
| 674 | R_TRY(ProcessReceiveMessagePointerDescriptors( | ||
| 675 | offset, pointer_key, dst_page_table, src_page_table, dst_msg, src_msg, dst_recv_list, | ||
| 676 | dst_user && dst_header.GetReceiveListCount() == | ||
| 677 | MessageBuffer::MessageHeader::ReceiveListCountType_ToMessageBuffer)); | ||
| 678 | } | ||
| 679 | |||
| 680 | // Process any map alias buffers. | ||
| 681 | for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) { | ||
| 682 | // After we process, make sure we track whether the receive list is broken. | ||
| 683 | SCOPE_EXIT({ | ||
| 684 | if (offset > dst_recv_list_idx) { | ||
| 685 | recv_list_broken = true; | ||
| 226 | } | 686 | } |
| 687 | }); | ||
| 688 | |||
| 689 | // We process in order send, recv, exch. Buffers after send (recv/exch) are ReadWrite. | ||
| 690 | const KMemoryPermission perm = (i >= src_header.GetSendCount()) | ||
| 691 | ? KMemoryPermission::UserReadWrite | ||
| 692 | : KMemoryPermission::UserRead; | ||
| 693 | |||
| 694 | // Buffer is send if it is send or exch. | ||
| 695 | const bool send = (i < src_header.GetSendCount()) || | ||
| 696 | (i >= src_header.GetSendCount() + src_header.GetReceiveCount()); | ||
| 697 | |||
| 698 | R_TRY(ProcessReceiveMessageMapAliasDescriptors(offset, dst_page_table, src_page_table, | ||
| 699 | dst_msg, src_msg, request, perm, send)); | ||
| 700 | } | ||
| 701 | |||
| 702 | // Process any raw data. | ||
| 703 | if (const auto raw_count = src_header.GetRawCount(); raw_count != 0) { | ||
| 704 | // After we process, make sure we track whether the receive list is broken. | ||
| 705 | SCOPE_EXIT({ | ||
| 706 | if (offset + raw_count > dst_recv_list_idx) { | ||
| 707 | recv_list_broken = true; | ||
| 708 | } | ||
| 709 | }); | ||
| 710 | |||
| 711 | // Get the offset and size. | ||
| 712 | const size_t offset_words = offset * sizeof(u32); | ||
| 713 | const size_t raw_size = raw_count * sizeof(u32); | ||
| 714 | |||
| 715 | if (!dst_user && !src_user) { | ||
| 716 | // Fast case is TLS -> TLS, do raw memcpy if we can. | ||
| 717 | std::memcpy(dst_msg_ptr + offset, src_msg_ptr + offset, raw_size); | ||
| 718 | } else if (dst_user) { | ||
| 719 | // Determine how much fast size we can copy. | ||
| 720 | const size_t max_fast_size = std::min<size_t>(offset_words + raw_size, PageSize); | ||
| 721 | const size_t fast_size = max_fast_size - offset_words; | ||
| 722 | |||
| 723 | // Determine source state; if user buffer, we require heap, and otherwise only linear | ||
| 724 | // mapped (to enable tls use). | ||
| 725 | const auto src_state = | ||
| 726 | src_user ? KMemoryState::FlagReferenceCounted : KMemoryState::FlagLinearMapped; | ||
| 727 | |||
| 728 | // Determine the source permission. User buffer should be unmapped + read, TLS should be | ||
| 729 | // user readable. | ||
| 730 | const KMemoryPermission src_perm = static_cast<KMemoryPermission>( | ||
| 731 | src_user ? KMemoryPermission::NotMapped | KMemoryPermission::KernelRead | ||
| 732 | : KMemoryPermission::UserRead); | ||
| 733 | |||
| 734 | // Perform the fast part of the copy. | ||
| 735 | R_TRY(src_page_table.CopyMemoryFromLinearToKernel( | ||
| 736 | dst_msg_ptr + offset, fast_size, src_message_buffer + offset_words, src_state, | ||
| 737 | src_state, src_perm, KMemoryAttribute::Uncached, KMemoryAttribute::None)); | ||
| 738 | |||
| 739 | // If the fast part of the copy didn't get everything, perform the slow part of the | ||
| 740 | // copy. | ||
| 741 | if (fast_size < raw_size) { | ||
| 742 | R_TRY(src_page_table.CopyMemoryFromHeapToHeap( | ||
| 743 | dst_page_table, dst_message_buffer + max_fast_size, raw_size - fast_size, | ||
| 744 | KMemoryState::FlagReferenceCounted, KMemoryState::FlagReferenceCounted, | ||
| 745 | KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite, | ||
| 746 | KMemoryAttribute::Uncached | KMemoryAttribute::Locked, KMemoryAttribute::Locked, | ||
| 747 | src_message_buffer + max_fast_size, src_state, src_state, src_perm, | ||
| 748 | KMemoryAttribute::Uncached, KMemoryAttribute::None)); | ||
| 749 | } | ||
| 750 | } else /* if (src_user) */ { | ||
| 751 | // The source is a user buffer, so it should be unmapped + readable. | ||
| 752 | constexpr KMemoryPermission SourcePermission = static_cast<KMemoryPermission>( | ||
| 753 | KMemoryPermission::NotMapped | KMemoryPermission::KernelRead); | ||
| 754 | |||
| 755 | // Copy the memory. | ||
| 756 | R_TRY(src_page_table.CopyMemoryFromLinearToUser( | ||
| 757 | dst_message_buffer + offset_words, raw_size, src_message_buffer + offset_words, | ||
| 758 | KMemoryState::FlagReferenceCounted, KMemoryState::FlagReferenceCounted, | ||
| 759 | SourcePermission, KMemoryAttribute::Uncached, KMemoryAttribute::None)); | ||
| 227 | } | 760 | } |
| 761 | } | ||
| 228 | 762 | ||
| 229 | // If we need to, reply. | 763 | // We succeeded! |
| 230 | if (event != nullptr && !cur_request) { | 764 | R_SUCCEED(); |
| 231 | // There must be no mappings. | 765 | } |
| 232 | ASSERT(request->GetSendCount() == 0); | ||
| 233 | ASSERT(request->GetReceiveCount() == 0); | ||
| 234 | ASSERT(request->GetExchangeCount() == 0); | ||
| 235 | 766 | ||
| 236 | // // Get the process and page table. | 767 | Result ProcessSendMessageReceiveMapping(KProcessPageTable& src_page_table, |
| 237 | // KProcess *client_process = thread->GetOwnerProcess(); | 768 | KProcessPageTable& dst_page_table, |
| 238 | // auto& client_pt = client_process->GetPageTable(); | 769 | KProcessAddress client_address, |
| 770 | KProcessAddress server_address, size_t size, | ||
| 771 | KMemoryState src_state) { | ||
| 772 | // If the size is zero, there's nothing to process. | ||
| 773 | R_SUCCEED_IF(size == 0); | ||
| 774 | |||
| 775 | // Get the memory state and attribute mask to test. | ||
| 776 | KMemoryState test_state; | ||
| 777 | KMemoryAttribute test_attr_mask; | ||
| 778 | R_TRY(GetMapAliasTestStateAndAttributeMask(test_state, test_attr_mask, src_state)); | ||
| 779 | |||
| 780 | // Determine buffer extents. | ||
| 781 | KProcessAddress aligned_dst_start = Common::AlignDown(GetInteger(client_address), PageSize); | ||
| 782 | KProcessAddress aligned_dst_end = Common::AlignUp(GetInteger(client_address) + size, PageSize); | ||
| 783 | KProcessAddress mapping_dst_start = Common::AlignUp(GetInteger(client_address), PageSize); | ||
| 784 | KProcessAddress mapping_dst_end = | ||
| 785 | Common::AlignDown(GetInteger(client_address) + size, PageSize); | ||
| 786 | |||
| 787 | KProcessAddress mapping_src_end = | ||
| 788 | Common::AlignDown(GetInteger(server_address) + size, PageSize); | ||
| 789 | |||
| 790 | // If the start of the buffer is unaligned, handle that. | ||
| 791 | if (aligned_dst_start != mapping_dst_start) { | ||
| 792 | ASSERT(client_address < mapping_dst_start); | ||
| 793 | const size_t copy_size = std::min<size_t>(size, mapping_dst_start - client_address); | ||
| 794 | R_TRY(dst_page_table.CopyMemoryFromUserToLinear( | ||
| 795 | client_address, copy_size, test_state, test_state, KMemoryPermission::UserReadWrite, | ||
| 796 | test_attr_mask, KMemoryAttribute::None, server_address)); | ||
| 797 | } | ||
| 239 | 798 | ||
| 240 | // // Reply to the request. | 799 | // If the end of the buffer is unaligned, handle that. |
| 241 | // ReplyAsyncError(client_process, request->GetAddress(), request->GetSize(), | 800 | if (mapping_dst_end < aligned_dst_end && |
| 242 | // ResultSessionClosed); | 801 | (aligned_dst_start == mapping_dst_start || aligned_dst_start < mapping_dst_end)) { |
| 802 | const size_t copy_size = client_address + size - mapping_dst_end; | ||
| 803 | R_TRY(dst_page_table.CopyMemoryFromUserToLinear( | ||
| 804 | mapping_dst_end, copy_size, test_state, test_state, KMemoryPermission::UserReadWrite, | ||
| 805 | test_attr_mask, KMemoryAttribute::None, mapping_src_end)); | ||
| 806 | } | ||
| 243 | 807 | ||
| 244 | // // Unlock the buffer. | 808 | R_SUCCEED(); |
| 245 | // // NOTE: Nintendo does not check the result of this. | 809 | } |
| 246 | // client_pt.UnlockForIpcUserBuffer(request->GetAddress(), request->GetSize()); | ||
| 247 | 810 | ||
| 248 | // Signal the event. | 811 | Result ProcessSendMessagePointerDescriptors(int& offset, int& pointer_key, |
| 249 | event->Signal(); | 812 | KProcessPageTable& src_page_table, |
| 813 | KProcessPageTable& dst_page_table, | ||
| 814 | const MessageBuffer& dst_msg, | ||
| 815 | const MessageBuffer& src_msg, | ||
| 816 | const ReceiveList& dst_recv_list, bool dst_user) { | ||
| 817 | // Get the offset at the start of processing. | ||
| 818 | const int cur_offset = offset; | ||
| 819 | |||
| 820 | // Get the pointer desc. | ||
| 821 | MessageBuffer::PointerDescriptor src_desc(src_msg, cur_offset); | ||
| 822 | offset += static_cast<int>(MessageBuffer::PointerDescriptor::GetDataSize() / sizeof(u32)); | ||
| 823 | |||
| 824 | // Extract address/size. | ||
| 825 | const uint64_t src_pointer = src_desc.GetAddress(); | ||
| 826 | const size_t recv_size = src_desc.GetSize(); | ||
| 827 | uint64_t recv_pointer = 0; | ||
| 828 | |||
| 829 | // Process the buffer, if it has a size. | ||
| 830 | if (recv_size > 0) { | ||
| 831 | // If using indexing, set index. | ||
| 832 | if (dst_recv_list.IsIndex()) { | ||
| 833 | pointer_key = src_desc.GetIndex(); | ||
| 250 | } | 834 | } |
| 835 | |||
| 836 | // Get the buffer. | ||
| 837 | dst_recv_list.GetBuffer(recv_pointer, recv_size, pointer_key); | ||
| 838 | R_UNLESS(recv_pointer != 0, ResultOutOfResource); | ||
| 839 | |||
| 840 | // Perform the pointer data copy. | ||
| 841 | const bool dst_heap = dst_user && dst_recv_list.IsToMessageBuffer(); | ||
| 842 | const auto dst_state = | ||
| 843 | dst_heap ? KMemoryState::FlagReferenceCounted : KMemoryState::FlagLinearMapped; | ||
| 844 | const KMemoryPermission dst_perm = | ||
| 845 | dst_heap ? KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite | ||
| 846 | : KMemoryPermission::UserReadWrite; | ||
| 847 | R_TRY(dst_page_table.CopyMemoryFromUserToLinear( | ||
| 848 | recv_pointer, recv_size, dst_state, dst_state, dst_perm, KMemoryAttribute::Uncached, | ||
| 849 | KMemoryAttribute::None, src_pointer)); | ||
| 251 | } | 850 | } |
| 252 | 851 | ||
| 253 | // Notify. | 852 | // Set the output descriptor. |
| 254 | this->NotifyAvailable(ResultSessionClosed); | 853 | dst_msg.Set(cur_offset, MessageBuffer::PointerDescriptor(reinterpret_cast<void*>(recv_pointer), |
| 854 | recv_size, src_desc.GetIndex())); | ||
| 855 | |||
| 856 | R_SUCCEED(); | ||
| 255 | } | 857 | } |
| 256 | 858 | ||
| 257 | bool KServerSession::IsSignaled() const { | 859 | Result SendMessage(KernelCore& kernel, uint64_t src_message_buffer, size_t src_buffer_size, |
| 258 | ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel)); | 860 | KPhysicalAddress src_message_paddr, KThread& dst_thread, |
| 861 | uint64_t dst_message_buffer, size_t dst_buffer_size, KServerSession* session, | ||
| 862 | KSessionRequest* request) { | ||
| 863 | // Prepare variables for send. | ||
| 864 | KThread& src_thread = GetCurrentThread(kernel); | ||
| 865 | KProcess& dst_process = *(dst_thread.GetOwnerProcess()); | ||
| 866 | KProcess& src_process = *(src_thread.GetOwnerProcess()); | ||
| 867 | auto& dst_page_table = dst_process.GetPageTable(); | ||
| 868 | auto& src_page_table = src_process.GetPageTable(); | ||
| 869 | |||
| 870 | // NOTE: Session is used only for debugging, and so may go unused. | ||
| 871 | (void)session; | ||
| 872 | |||
| 873 | // Determine the message buffers. | ||
| 874 | u32 *dst_msg_ptr, *src_msg_ptr; | ||
| 875 | bool dst_user, src_user; | ||
| 876 | |||
| 877 | if (dst_message_buffer) { | ||
| 878 | // NOTE: Nintendo does not check the result of this GetPhysicalAddress call. | ||
| 879 | dst_msg_ptr = dst_page_table.GetMemory().GetPointer<u32>(dst_message_buffer); | ||
| 880 | dst_user = true; | ||
| 881 | } else { | ||
| 882 | dst_msg_ptr = dst_page_table.GetMemory().GetPointer<u32>(dst_thread.GetTlsAddress()); | ||
| 883 | dst_buffer_size = MessageBufferSize; | ||
| 884 | dst_message_buffer = GetInteger(dst_thread.GetTlsAddress()); | ||
| 885 | dst_user = false; | ||
| 886 | } | ||
| 259 | 887 | ||
| 260 | // If the client is closed, we're always signaled. | 888 | if (src_message_buffer) { |
| 261 | if (m_parent->IsClientClosed()) { | 889 | src_msg_ptr = src_page_table.GetMemory().GetPointer<u32>(src_message_buffer); |
| 262 | return true; | 890 | src_user = true; |
| 891 | } else { | ||
| 892 | src_msg_ptr = src_page_table.GetMemory().GetPointer<u32>(src_thread.GetTlsAddress()); | ||
| 893 | src_buffer_size = MessageBufferSize; | ||
| 894 | src_message_buffer = GetInteger(src_thread.GetTlsAddress()); | ||
| 895 | src_user = false; | ||
| 263 | } | 896 | } |
| 264 | 897 | ||
| 265 | // Otherwise, we're signaled if we have a request and aren't handling one. | 898 | // Parse the headers. |
| 266 | return !m_request_list.empty() && m_current_request == nullptr; | 899 | const MessageBuffer dst_msg(dst_msg_ptr, dst_buffer_size); |
| 900 | const MessageBuffer src_msg(src_msg_ptr, src_buffer_size); | ||
| 901 | const MessageBuffer::MessageHeader dst_header(dst_msg); | ||
| 902 | const MessageBuffer::MessageHeader src_header(src_msg); | ||
| 903 | const MessageBuffer::SpecialHeader dst_special_header(dst_msg, dst_header); | ||
| 904 | const MessageBuffer::SpecialHeader src_special_header(src_msg, src_header); | ||
| 905 | |||
| 906 | // Get the end of the source message. | ||
| 907 | const size_t src_end_offset = | ||
| 908 | MessageBuffer::GetRawDataIndex(src_header, src_special_header) + src_header.GetRawCount(); | ||
| 909 | |||
| 910 | // Declare variables for processing. | ||
| 911 | int offset = 0; | ||
| 912 | int pointer_key = 0; | ||
| 913 | bool processed_special_data = false; | ||
| 914 | |||
| 915 | // Send the message. | ||
| 916 | { | ||
| 917 | // Make sure that we end up in a clean state on error. | ||
| 918 | ON_RESULT_FAILURE { | ||
| 919 | // Cleanup special data. | ||
| 920 | if (processed_special_data) { | ||
| 921 | if (src_header.GetHasSpecialHeader()) { | ||
| 922 | CleanupSpecialData(dst_process, dst_msg_ptr, dst_buffer_size); | ||
| 923 | } | ||
| 924 | } else { | ||
| 925 | CleanupServerHandles(kernel, src_user ? src_message_buffer : 0, src_buffer_size, | ||
| 926 | src_message_paddr); | ||
| 927 | } | ||
| 928 | |||
| 929 | // Cleanup mappings. | ||
| 930 | CleanupMap(request, std::addressof(src_process), std::addressof(dst_page_table)); | ||
| 931 | }; | ||
| 932 | |||
| 933 | // Ensure that the headers fit. | ||
| 934 | R_UNLESS(MessageBuffer::GetMessageBufferSize(src_header, src_special_header) <= | ||
| 935 | src_buffer_size, | ||
| 936 | ResultInvalidCombination); | ||
| 937 | R_UNLESS(MessageBuffer::GetMessageBufferSize(dst_header, dst_special_header) <= | ||
| 938 | dst_buffer_size, | ||
| 939 | ResultInvalidCombination); | ||
| 940 | |||
| 941 | // Ensure the receive list offset is after the end of raw data. | ||
| 942 | if (dst_header.GetReceiveListOffset()) { | ||
| 943 | R_UNLESS(dst_header.GetReceiveListOffset() >= | ||
| 944 | MessageBuffer::GetRawDataIndex(dst_header, dst_special_header) + | ||
| 945 | dst_header.GetRawCount(), | ||
| 946 | ResultInvalidCombination); | ||
| 947 | } | ||
| 948 | |||
| 949 | // Ensure that the destination buffer is big enough to receive the source. | ||
| 950 | R_UNLESS(dst_buffer_size >= src_end_offset * sizeof(u32), ResultMessageTooLarge); | ||
| 951 | |||
| 952 | // Replies must have no buffers. | ||
| 953 | R_UNLESS(src_header.GetSendCount() == 0, ResultInvalidCombination); | ||
| 954 | R_UNLESS(src_header.GetReceiveCount() == 0, ResultInvalidCombination); | ||
| 955 | R_UNLESS(src_header.GetExchangeCount() == 0, ResultInvalidCombination); | ||
| 956 | |||
| 957 | // Get the receive list. | ||
| 958 | const s32 dst_recv_list_idx = | ||
| 959 | MessageBuffer::GetReceiveListIndex(dst_header, dst_special_header); | ||
| 960 | ReceiveList dst_recv_list(dst_msg_ptr, dst_message_buffer, dst_page_table, dst_header, | ||
| 961 | dst_special_header, dst_buffer_size, src_end_offset, | ||
| 962 | dst_recv_list_idx, !dst_user); | ||
| 963 | |||
| 964 | // Handle any receive buffers. | ||
| 965 | for (size_t i = 0; i < request->GetReceiveCount(); ++i) { | ||
| 966 | R_TRY(ProcessSendMessageReceiveMapping( | ||
| 967 | src_page_table, dst_page_table, request->GetReceiveClientAddress(i), | ||
| 968 | request->GetReceiveServerAddress(i), request->GetReceiveSize(i), | ||
| 969 | request->GetReceiveMemoryState(i))); | ||
| 970 | } | ||
| 971 | |||
| 972 | // Handle any exchange buffers. | ||
| 973 | for (size_t i = 0; i < request->GetExchangeCount(); ++i) { | ||
| 974 | R_TRY(ProcessSendMessageReceiveMapping( | ||
| 975 | src_page_table, dst_page_table, request->GetExchangeClientAddress(i), | ||
| 976 | request->GetExchangeServerAddress(i), request->GetExchangeSize(i), | ||
| 977 | request->GetExchangeMemoryState(i))); | ||
| 978 | } | ||
| 979 | |||
| 980 | // Set the header. | ||
| 981 | offset = dst_msg.Set(src_header); | ||
| 982 | |||
| 983 | // Process any special data. | ||
| 984 | ASSERT(GetCurrentThreadPointer(kernel) == std::addressof(src_thread)); | ||
| 985 | processed_special_data = true; | ||
| 986 | if (src_header.GetHasSpecialHeader()) { | ||
| 987 | R_TRY(ProcessMessageSpecialData<true>(offset, dst_process, src_process, src_thread, | ||
| 988 | dst_msg, src_msg, src_special_header)); | ||
| 989 | } | ||
| 990 | |||
| 991 | // Process any pointer buffers. | ||
| 992 | for (auto i = 0; i < src_header.GetPointerCount(); ++i) { | ||
| 993 | R_TRY(ProcessSendMessagePointerDescriptors( | ||
| 994 | offset, pointer_key, src_page_table, dst_page_table, dst_msg, src_msg, | ||
| 995 | dst_recv_list, | ||
| 996 | dst_user && | ||
| 997 | dst_header.GetReceiveListCount() == | ||
| 998 | MessageBuffer::MessageHeader::ReceiveListCountType_ToMessageBuffer)); | ||
| 999 | } | ||
| 1000 | |||
| 1001 | // Clear any map alias buffers. | ||
| 1002 | for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) { | ||
| 1003 | offset = dst_msg.Set(offset, MessageBuffer::MapAliasDescriptor()); | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | // Process any raw data. | ||
| 1007 | if (const auto raw_count = src_header.GetRawCount(); raw_count != 0) { | ||
| 1008 | // Get the offset and size. | ||
| 1009 | const size_t offset_words = offset * sizeof(u32); | ||
| 1010 | const size_t raw_size = raw_count * sizeof(u32); | ||
| 1011 | |||
| 1012 | if (!dst_user && !src_user) { | ||
| 1013 | // Fast case is TLS -> TLS, do raw memcpy if we can. | ||
| 1014 | std::memcpy(dst_msg_ptr + offset, src_msg_ptr + offset, raw_size); | ||
| 1015 | } else if (src_user) { | ||
| 1016 | // Determine how much fast size we can copy. | ||
| 1017 | const size_t max_fast_size = std::min<size_t>(offset_words + raw_size, PageSize); | ||
| 1018 | const size_t fast_size = max_fast_size - offset_words; | ||
| 1019 | |||
| 1020 | // Determine dst state; if user buffer, we require heap, and otherwise only linear | ||
| 1021 | // mapped (to enable tls use). | ||
| 1022 | const auto dst_state = | ||
| 1023 | dst_user ? KMemoryState::FlagReferenceCounted : KMemoryState::FlagLinearMapped; | ||
| 1024 | |||
| 1025 | // Determine the dst permission. User buffer should be unmapped + read, TLS should | ||
| 1026 | // be user readable. | ||
| 1027 | const KMemoryPermission dst_perm = | ||
| 1028 | dst_user ? KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite | ||
| 1029 | : KMemoryPermission::UserReadWrite; | ||
| 1030 | |||
| 1031 | // Perform the fast part of the copy. | ||
| 1032 | R_TRY(dst_page_table.CopyMemoryFromKernelToLinear( | ||
| 1033 | dst_message_buffer + offset_words, fast_size, dst_state, dst_state, dst_perm, | ||
| 1034 | KMemoryAttribute::Uncached, KMemoryAttribute::None, src_msg_ptr + offset)); | ||
| 1035 | |||
| 1036 | // If the fast part of the copy didn't get everything, perform the slow part of the | ||
| 1037 | // copy. | ||
| 1038 | if (fast_size < raw_size) { | ||
| 1039 | R_TRY(dst_page_table.CopyMemoryFromHeapToHeap( | ||
| 1040 | dst_page_table, dst_message_buffer + max_fast_size, raw_size - fast_size, | ||
| 1041 | dst_state, dst_state, dst_perm, KMemoryAttribute::Uncached, | ||
| 1042 | KMemoryAttribute::None, src_message_buffer + max_fast_size, | ||
| 1043 | KMemoryState::FlagReferenceCounted, KMemoryState::FlagReferenceCounted, | ||
| 1044 | KMemoryPermission::NotMapped | KMemoryPermission::KernelRead, | ||
| 1045 | KMemoryAttribute::Uncached | KMemoryAttribute::Locked, | ||
| 1046 | KMemoryAttribute::Locked)); | ||
| 1047 | } | ||
| 1048 | } else /* if (dst_user) */ { | ||
| 1049 | // The destination is a user buffer, so it should be unmapped + readable. | ||
| 1050 | constexpr KMemoryPermission DestinationPermission = | ||
| 1051 | KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite; | ||
| 1052 | |||
| 1053 | // Copy the memory. | ||
| 1054 | R_TRY(dst_page_table.CopyMemoryFromUserToLinear( | ||
| 1055 | dst_message_buffer + offset_words, raw_size, KMemoryState::FlagReferenceCounted, | ||
| 1056 | KMemoryState::FlagReferenceCounted, DestinationPermission, | ||
| 1057 | KMemoryAttribute::Uncached, KMemoryAttribute::None, | ||
| 1058 | src_message_buffer + offset_words)); | ||
| 1059 | } | ||
| 1060 | } | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | // Perform (and validate) any remaining cleanup. | ||
| 1064 | R_RETURN(CleanupMap(request, std::addressof(src_process), std::addressof(dst_page_table))); | ||
| 267 | } | 1065 | } |
| 268 | 1066 | ||
| 269 | Result KServerSession::OnRequest(KSessionRequest* request) { | 1067 | void ReplyAsyncError(KProcess* to_process, uint64_t to_msg_buf, size_t to_msg_buf_size, |
| 270 | // Create the wait queue. | 1068 | Result result) { |
| 271 | ThreadQueueImplForKServerSessionRequest wait_queue{m_kernel}; | 1069 | // Convert the address to a linear pointer. |
| 1070 | u32* to_msg = to_process->GetMemory().GetPointer<u32>(to_msg_buf); | ||
| 1071 | |||
| 1072 | // Set the error. | ||
| 1073 | MessageBuffer msg(to_msg, to_msg_buf_size); | ||
| 1074 | msg.SetAsyncResult(result); | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | } // namespace | ||
| 1078 | |||
| 1079 | KServerSession::KServerSession(KernelCore& kernel) | ||
| 1080 | : KSynchronizationObject{kernel}, m_lock{m_kernel} {} | ||
| 1081 | |||
| 1082 | KServerSession::~KServerSession() = default; | ||
| 1083 | |||
| 1084 | void KServerSession::Destroy() { | ||
| 1085 | m_parent->OnServerClosed(); | ||
| 1086 | |||
| 1087 | this->CleanupRequests(); | ||
| 1088 | |||
| 1089 | m_parent->Close(); | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server_buffer_size, | ||
| 1093 | KPhysicalAddress server_message_paddr, | ||
| 1094 | std::shared_ptr<Service::HLERequestContext>* out_context, | ||
| 1095 | std::weak_ptr<Service::SessionRequestManager> manager) { | ||
| 1096 | // Lock the session. | ||
| 1097 | KScopedLightLock lk{m_lock}; | ||
| 1098 | |||
| 1099 | // Get the request and client thread. | ||
| 1100 | KSessionRequest* request; | ||
| 1101 | KThread* client_thread; | ||
| 272 | 1102 | ||
| 273 | { | 1103 | { |
| 274 | // Lock the scheduler. | ||
| 275 | KScopedSchedulerLock sl{m_kernel}; | 1104 | KScopedSchedulerLock sl{m_kernel}; |
| 276 | 1105 | ||
| 277 | // Ensure that we can handle new requests. | 1106 | // Ensure that we can service the request. |
| 278 | R_UNLESS(!m_parent->IsServerClosed(), ResultSessionClosed); | 1107 | R_UNLESS(!m_parent->IsClientClosed(), ResultSessionClosed); |
| 279 | 1108 | ||
| 280 | // Check that we're not terminating. | 1109 | // Ensure we aren't already servicing a request. |
| 281 | R_UNLESS(!GetCurrentThread(m_kernel).IsTerminationRequested(), ResultTerminationRequested); | 1110 | R_UNLESS(m_current_request == nullptr, ResultNotFound); |
| 282 | 1111 | ||
| 283 | // Get whether we're empty. | 1112 | // Ensure we have a request to service. |
| 284 | const bool was_empty = m_request_list.empty(); | 1113 | R_UNLESS(!m_request_list.empty(), ResultNotFound); |
| 285 | 1114 | ||
| 286 | // Add the request to the list. | 1115 | // Pop the first request from the list. |
| 287 | request->Open(); | 1116 | request = std::addressof(m_request_list.front()); |
| 288 | m_request_list.push_back(*request); | 1117 | m_request_list.pop_front(); |
| 289 | 1118 | ||
| 290 | // If we were empty, signal. | 1119 | // Get the thread for the request. |
| 291 | if (was_empty) { | 1120 | client_thread = request->GetThread(); |
| 292 | this->NotifyAvailable(); | 1121 | R_UNLESS(client_thread != nullptr, ResultSessionClosed); |
| 1122 | |||
| 1123 | // Open the client thread. | ||
| 1124 | client_thread->Open(); | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | SCOPE_EXIT({ client_thread->Close(); }); | ||
| 1128 | |||
| 1129 | // Set the request as our current. | ||
| 1130 | m_current_request = request; | ||
| 1131 | |||
| 1132 | // Get the client address. | ||
| 1133 | uint64_t client_message = request->GetAddress(); | ||
| 1134 | size_t client_buffer_size = request->GetSize(); | ||
| 1135 | bool recv_list_broken = false; | ||
| 1136 | |||
| 1137 | // Receive the message. | ||
| 1138 | Result result = ResultSuccess; | ||
| 1139 | |||
| 1140 | if (out_context != nullptr) { | ||
| 1141 | // HLE request. | ||
| 1142 | if (!client_message) { | ||
| 1143 | client_message = GetInteger(client_thread->GetTlsAddress()); | ||
| 293 | } | 1144 | } |
| 1145 | Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()}; | ||
| 1146 | u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(client_message))}; | ||
| 1147 | *out_context = | ||
| 1148 | std::make_shared<Service::HLERequestContext>(m_kernel, memory, this, client_thread); | ||
| 1149 | (*out_context)->SetSessionRequestManager(manager); | ||
| 1150 | (*out_context)->PopulateFromIncomingCommandBuffer(cmd_buf); | ||
| 1151 | // We succeeded. | ||
| 1152 | R_SUCCEED(); | ||
| 1153 | } else { | ||
| 1154 | result = ReceiveMessage(m_kernel, recv_list_broken, server_message, server_buffer_size, | ||
| 1155 | server_message_paddr, *client_thread, client_message, | ||
| 1156 | client_buffer_size, this, request); | ||
| 1157 | } | ||
| 294 | 1158 | ||
| 295 | // If we have a request event, this is asynchronous, and we don't need to wait. | 1159 | // Handle cleanup on receive failure. |
| 296 | R_SUCCEED_IF(request->GetEvent() != nullptr); | 1160 | if (R_FAILED(result)) { |
| 1161 | // Cache the result to return it to the client. | ||
| 1162 | const Result result_for_client = result; | ||
| 297 | 1163 | ||
| 298 | // This is a synchronous request, so we should wait for our request to complete. | 1164 | // Clear the current request. |
| 299 | GetCurrentThread(m_kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); | 1165 | { |
| 300 | GetCurrentThread(m_kernel).BeginWait(std::addressof(wait_queue)); | 1166 | KScopedSchedulerLock sl(m_kernel); |
| 1167 | ASSERT(m_current_request == request); | ||
| 1168 | m_current_request = nullptr; | ||
| 1169 | if (!m_request_list.empty()) { | ||
| 1170 | this->NotifyAvailable(); | ||
| 1171 | } | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | // Reply to the client. | ||
| 1175 | { | ||
| 1176 | // After we reply, close our reference to the request. | ||
| 1177 | SCOPE_EXIT({ request->Close(); }); | ||
| 1178 | |||
| 1179 | // Get the event to check whether the request is async. | ||
| 1180 | if (KEvent* event = request->GetEvent(); event != nullptr) { | ||
| 1181 | // The client sent an async request. | ||
| 1182 | KProcess* client = client_thread->GetOwnerProcess(); | ||
| 1183 | auto& client_pt = client->GetPageTable(); | ||
| 1184 | |||
| 1185 | // Send the async result. | ||
| 1186 | if (R_FAILED(result_for_client)) { | ||
| 1187 | ReplyAsyncError(client, client_message, client_buffer_size, result_for_client); | ||
| 1188 | } | ||
| 1189 | |||
| 1190 | // Unlock the client buffer. | ||
| 1191 | // NOTE: Nintendo does not check the result of this. | ||
| 1192 | client_pt.UnlockForIpcUserBuffer(client_message, client_buffer_size); | ||
| 1193 | |||
| 1194 | // Signal the event. | ||
| 1195 | event->Signal(); | ||
| 1196 | } else { | ||
| 1197 | // End the client thread's wait. | ||
| 1198 | KScopedSchedulerLock sl(m_kernel); | ||
| 1199 | |||
| 1200 | if (!client_thread->IsTerminationRequested()) { | ||
| 1201 | client_thread->EndWait(result_for_client); | ||
| 1202 | } | ||
| 1203 | } | ||
| 1204 | } | ||
| 1205 | |||
| 1206 | // Set the server result. | ||
| 1207 | if (recv_list_broken) { | ||
| 1208 | result = ResultReceiveListBroken; | ||
| 1209 | } else { | ||
| 1210 | result = ResultNotFound; | ||
| 1211 | } | ||
| 301 | } | 1212 | } |
| 302 | 1213 | ||
| 303 | return GetCurrentThread(m_kernel).GetWaitResult(); | 1214 | R_RETURN(result); |
| 304 | } | 1215 | } |
| 305 | 1216 | ||
| 306 | Result KServerSession::SendReply(bool is_hle) { | 1217 | Result KServerSession::SendReply(uintptr_t server_message, uintptr_t server_buffer_size, |
| 1218 | KPhysicalAddress server_message_paddr, bool is_hle) { | ||
| 307 | // Lock the session. | 1219 | // Lock the session. |
| 308 | KScopedLightLock lk{m_lock}; | 1220 | KScopedLightLock lk{m_lock}; |
| 309 | 1221 | ||
| @@ -327,7 +1239,7 @@ Result KServerSession::SendReply(bool is_hle) { | |||
| 327 | SCOPE_EXIT({ request->Close(); }); | 1239 | SCOPE_EXIT({ request->Close(); }); |
| 328 | 1240 | ||
| 329 | // Extract relevant information from the request. | 1241 | // Extract relevant information from the request. |
| 330 | const uintptr_t client_message = request->GetAddress(); | 1242 | const uint64_t client_message = request->GetAddress(); |
| 331 | const size_t client_buffer_size = request->GetSize(); | 1243 | const size_t client_buffer_size = request->GetSize(); |
| 332 | KThread* client_thread = request->GetThread(); | 1244 | KThread* client_thread = request->GetThread(); |
| 333 | KEvent* event = request->GetEvent(); | 1245 | KEvent* event = request->GetEvent(); |
| @@ -342,31 +1254,28 @@ Result KServerSession::SendReply(bool is_hle) { | |||
| 342 | // HLE servers write directly to a pointer to the thread command buffer. Therefore | 1254 | // HLE servers write directly to a pointer to the thread command buffer. Therefore |
| 343 | // the reply has already been written in this case. | 1255 | // the reply has already been written in this case. |
| 344 | } else { | 1256 | } else { |
| 345 | Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()}; | 1257 | result = SendMessage(m_kernel, server_message, server_buffer_size, server_message_paddr, |
| 346 | KThread* server_thread = GetCurrentThreadPointer(m_kernel); | 1258 | *client_thread, client_message, client_buffer_size, this, request); |
| 347 | KProcess& src_process = *client_thread->GetOwnerProcess(); | 1259 | } |
| 348 | KProcess& dst_process = *server_thread->GetOwnerProcess(); | 1260 | } else if (!is_hle) { |
| 349 | UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); | 1261 | // Otherwise, we'll need to do some cleanup. |
| 350 | 1262 | KProcess* server_process = request->GetServerProcess(); | |
| 351 | auto* src_msg_buffer = memory.GetPointer<u32>(server_thread->GetTlsAddress()); | 1263 | KProcess* client_process = |
| 352 | auto* dst_msg_buffer = memory.GetPointer<u32>(client_message); | 1264 | (client_thread != nullptr) ? client_thread->GetOwnerProcess() : nullptr; |
| 353 | std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); | 1265 | KProcessPageTable* client_page_table = |
| 354 | 1266 | (client_process != nullptr) ? std::addressof(client_process->GetPageTable()) : nullptr; | |
| 355 | // Translate special header ad-hoc. | 1267 | |
| 356 | MessageBuffer src_msg(src_msg_buffer, client_buffer_size); | 1268 | // Cleanup server handles. |
| 357 | MessageBuffer::MessageHeader src_header(src_msg); | 1269 | result = CleanupServerHandles(m_kernel, server_message, server_buffer_size, |
| 358 | MessageBuffer::SpecialHeader src_special_header(src_msg, src_header); | 1270 | server_message_paddr); |
| 359 | if (src_header.GetHasSpecialHeader()) { | 1271 | |
| 360 | MessageBuffer dst_msg(dst_msg_buffer, client_buffer_size); | 1272 | // Cleanup mappings. |
| 361 | result = ProcessMessageSpecialData<true>(dst_process, src_process, *server_thread, | 1273 | Result cleanup_map_result = CleanupMap(request, server_process, client_page_table); |
| 362 | dst_msg, src_msg, src_special_header); | 1274 | |
| 363 | if (R_FAILED(result)) { | 1275 | // If we successfully cleaned up handles, use the map cleanup result as our result. |
| 364 | CleanupSpecialData(dst_process, dst_msg_buffer, client_buffer_size); | 1276 | if (R_SUCCEEDED(result)) { |
| 365 | } | 1277 | result = cleanup_map_result; |
| 366 | } | ||
| 367 | } | 1278 | } |
| 368 | } else { | ||
| 369 | result = ResultSessionClosed; | ||
| 370 | } | 1279 | } |
| 371 | 1280 | ||
| 372 | // Select a result for the client. | 1281 | // Select a result for the client. |
| @@ -381,19 +1290,18 @@ Result KServerSession::SendReply(bool is_hle) { | |||
| 381 | // If there's a client thread, update it. | 1290 | // If there's a client thread, update it. |
| 382 | if (client_thread != nullptr) { | 1291 | if (client_thread != nullptr) { |
| 383 | if (event != nullptr) { | 1292 | if (event != nullptr) { |
| 384 | // // Get the client process/page table. | 1293 | // Get the client process/page table. |
| 385 | // KProcess *client_process = client_thread->GetOwnerProcess(); | 1294 | KProcess* client_process = client_thread->GetOwnerProcess(); |
| 386 | // KProcessPageTable *client_page_table = std::addressof(client_process->PageTable()); | 1295 | KProcessPageTable* client_page_table = std::addressof(client_process->GetPageTable()); |
| 387 | 1296 | ||
| 388 | // // If we need to, reply with an async error. | 1297 | // If we need to, reply with an async error. |
| 389 | // if (R_FAILED(client_result)) { | 1298 | if (R_FAILED(client_result)) { |
| 390 | // ReplyAsyncError(client_process, client_message, client_buffer_size, | 1299 | ReplyAsyncError(client_process, client_message, client_buffer_size, client_result); |
| 391 | // client_result); | 1300 | } |
| 392 | // } | ||
| 393 | 1301 | ||
| 394 | // // Unlock the client buffer. | 1302 | // Unlock the client buffer. |
| 395 | // // NOTE: Nintendo does not check the result of this. | 1303 | // NOTE: Nintendo does not check the result of this. |
| 396 | // client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size); | 1304 | client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size); |
| 397 | 1305 | ||
| 398 | // Signal the event. | 1306 | // Signal the event. |
| 399 | event->Signal(); | 1307 | event->Signal(); |
| @@ -410,91 +1318,53 @@ Result KServerSession::SendReply(bool is_hle) { | |||
| 410 | R_RETURN(result); | 1318 | R_RETURN(result); |
| 411 | } | 1319 | } |
| 412 | 1320 | ||
| 413 | Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext>* out_context, | 1321 | Result KServerSession::OnRequest(KSessionRequest* request) { |
| 414 | std::weak_ptr<Service::SessionRequestManager> manager) { | 1322 | // Create the wait queue. |
| 415 | // Lock the session. | 1323 | ThreadQueueImplForKServerSessionRequest wait_queue{m_kernel}; |
| 416 | KScopedLightLock lk{m_lock}; | ||
| 417 | |||
| 418 | // Get the request and client thread. | ||
| 419 | KSessionRequest* request; | ||
| 420 | KThread* client_thread; | ||
| 421 | 1324 | ||
| 422 | { | 1325 | { |
| 1326 | // Lock the scheduler. | ||
| 423 | KScopedSchedulerLock sl{m_kernel}; | 1327 | KScopedSchedulerLock sl{m_kernel}; |
| 424 | 1328 | ||
| 425 | // Ensure that we can service the request. | 1329 | // Ensure that we can handle new requests. |
| 426 | R_UNLESS(!m_parent->IsClientClosed(), ResultSessionClosed); | 1330 | R_UNLESS(!m_parent->IsServerClosed(), ResultSessionClosed); |
| 427 | |||
| 428 | // Ensure we aren't already servicing a request. | ||
| 429 | R_UNLESS(m_current_request == nullptr, ResultNotFound); | ||
| 430 | 1331 | ||
| 431 | // Ensure we have a request to service. | 1332 | // Check that we're not terminating. |
| 432 | R_UNLESS(!m_request_list.empty(), ResultNotFound); | 1333 | R_UNLESS(!GetCurrentThread(m_kernel).IsTerminationRequested(), ResultTerminationRequested); |
| 433 | 1334 | ||
| 434 | // Pop the first request from the list. | 1335 | // Get whether we're empty. |
| 435 | request = std::addressof(m_request_list.front()); | 1336 | const bool was_empty = m_request_list.empty(); |
| 436 | m_request_list.pop_front(); | ||
| 437 | 1337 | ||
| 438 | // Get the thread for the request. | 1338 | // Add the request to the list. |
| 439 | client_thread = request->GetThread(); | 1339 | request->Open(); |
| 440 | R_UNLESS(client_thread != nullptr, ResultSessionClosed); | 1340 | m_request_list.push_back(*request); |
| 441 | 1341 | ||
| 442 | // Open the client thread. | 1342 | // If we were empty, signal. |
| 443 | client_thread->Open(); | 1343 | if (was_empty) { |
| 444 | } | 1344 | this->NotifyAvailable(); |
| 1345 | } | ||
| 445 | 1346 | ||
| 446 | SCOPE_EXIT({ client_thread->Close(); }); | 1347 | // If we have a request event, this is asynchronous, and we don't need to wait. |
| 1348 | R_SUCCEED_IF(request->GetEvent() != nullptr); | ||
| 447 | 1349 | ||
| 448 | // Set the request as our current. | 1350 | // This is a synchronous request, so we should wait for our request to complete. |
| 449 | m_current_request = request; | 1351 | GetCurrentThread(m_kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); |
| 1352 | GetCurrentThread(m_kernel).BeginWait(std::addressof(wait_queue)); | ||
| 1353 | } | ||
| 450 | 1354 | ||
| 451 | // Get the client address. | 1355 | return GetCurrentThread(m_kernel).GetWaitResult(); |
| 452 | uintptr_t client_message = request->GetAddress(); | 1356 | } |
| 453 | size_t client_buffer_size = request->GetSize(); | ||
| 454 | // bool recv_list_broken = false; | ||
| 455 | 1357 | ||
| 456 | if (!client_message) { | 1358 | bool KServerSession::IsSignaled() const { |
| 457 | client_message = GetInteger(client_thread->GetTlsAddress()); | 1359 | ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel)); |
| 458 | client_buffer_size = MessageBufferSize; | ||
| 459 | } | ||
| 460 | 1360 | ||
| 461 | // Receive the message. | 1361 | // If the client is closed, we're always signaled. |
| 462 | Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()}; | 1362 | if (m_parent->IsClientClosed()) { |
| 463 | if (out_context != nullptr) { | 1363 | return true; |
| 464 | // HLE request. | ||
| 465 | u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(client_message))}; | ||
| 466 | *out_context = | ||
| 467 | std::make_shared<Service::HLERequestContext>(m_kernel, memory, this, client_thread); | ||
| 468 | (*out_context)->SetSessionRequestManager(manager); | ||
| 469 | (*out_context) | ||
| 470 | ->PopulateFromIncomingCommandBuffer(*client_thread->GetOwnerProcess(), cmd_buf); | ||
| 471 | } else { | ||
| 472 | KThread* server_thread = GetCurrentThreadPointer(m_kernel); | ||
| 473 | KProcess& src_process = *client_thread->GetOwnerProcess(); | ||
| 474 | KProcess& dst_process = *server_thread->GetOwnerProcess(); | ||
| 475 | UNIMPLEMENTED_IF(client_thread->GetOwnerProcess() != server_thread->GetOwnerProcess()); | ||
| 476 | |||
| 477 | auto* src_msg_buffer = memory.GetPointer<u32>(client_message); | ||
| 478 | auto* dst_msg_buffer = memory.GetPointer<u32>(server_thread->GetTlsAddress()); | ||
| 479 | std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); | ||
| 480 | |||
| 481 | // Translate special header ad-hoc. | ||
| 482 | // TODO: fix this mess | ||
| 483 | MessageBuffer src_msg(src_msg_buffer, client_buffer_size); | ||
| 484 | MessageBuffer::MessageHeader src_header(src_msg); | ||
| 485 | MessageBuffer::SpecialHeader src_special_header(src_msg, src_header); | ||
| 486 | if (src_header.GetHasSpecialHeader()) { | ||
| 487 | MessageBuffer dst_msg(dst_msg_buffer, client_buffer_size); | ||
| 488 | Result res = ProcessMessageSpecialData<false>(dst_process, src_process, *client_thread, | ||
| 489 | dst_msg, src_msg, src_special_header); | ||
| 490 | if (R_FAILED(res)) { | ||
| 491 | CleanupSpecialData(dst_process, dst_msg_buffer, client_buffer_size); | ||
| 492 | } | ||
| 493 | } | ||
| 494 | } | 1364 | } |
| 495 | 1365 | ||
| 496 | // We succeeded. | 1366 | // Otherwise, we're signaled if we have a request and aren't handling one. |
| 497 | R_SUCCEED(); | 1367 | return !m_request_list.empty() && m_current_request == nullptr; |
| 498 | } | 1368 | } |
| 499 | 1369 | ||
| 500 | void KServerSession::CleanupRequests() { | 1370 | void KServerSession::CleanupRequests() { |
| @@ -527,31 +1397,30 @@ void KServerSession::CleanupRequests() { | |||
| 527 | SCOPE_EXIT({ request->Close(); }); | 1397 | SCOPE_EXIT({ request->Close(); }); |
| 528 | 1398 | ||
| 529 | // Extract relevant information from the request. | 1399 | // Extract relevant information from the request. |
| 530 | // const uintptr_t client_message = request->GetAddress(); | 1400 | const uint64_t client_message = request->GetAddress(); |
| 531 | // const size_t client_buffer_size = request->GetSize(); | 1401 | const size_t client_buffer_size = request->GetSize(); |
| 532 | KThread* client_thread = request->GetThread(); | 1402 | KThread* client_thread = request->GetThread(); |
| 533 | KEvent* event = request->GetEvent(); | 1403 | KEvent* event = request->GetEvent(); |
| 534 | 1404 | ||
| 535 | // KProcess *server_process = request->GetServerProcess(); | 1405 | KProcess* server_process = request->GetServerProcess(); |
| 536 | // KProcess *client_process = (client_thread != nullptr) ? | 1406 | KProcess* client_process = |
| 537 | // client_thread->GetOwnerProcess() : nullptr; | 1407 | (client_thread != nullptr) ? client_thread->GetOwnerProcess() : nullptr; |
| 538 | // KProcessPageTable *client_page_table = (client_process != nullptr) ? | 1408 | KProcessPageTable* client_page_table = |
| 539 | // std::addressof(client_process->GetPageTable()) | 1409 | (client_process != nullptr) ? std::addressof(client_process->GetPageTable()) : nullptr; |
| 540 | // : nullptr; | ||
| 541 | 1410 | ||
| 542 | // Cleanup the mappings. | 1411 | // Cleanup the mappings. |
| 543 | // Result result = CleanupMap(request, server_process, client_page_table); | 1412 | Result result = CleanupMap(request, server_process, client_page_table); |
| 544 | 1413 | ||
| 545 | // If there's a client thread, update it. | 1414 | // If there's a client thread, update it. |
| 546 | if (client_thread != nullptr) { | 1415 | if (client_thread != nullptr) { |
| 547 | if (event != nullptr) { | 1416 | if (event != nullptr) { |
| 548 | // // We need to reply async. | 1417 | // We need to reply async. |
| 549 | // ReplyAsyncError(client_process, client_message, client_buffer_size, | 1418 | ReplyAsyncError(client_process, client_message, client_buffer_size, |
| 550 | // (R_SUCCEEDED(result) ? ResultSessionClosed : result)); | 1419 | (R_SUCCEEDED(result) ? ResultSessionClosed : result)); |
| 551 | 1420 | ||
| 552 | // // Unlock the client buffer. | 1421 | // Unlock the client buffer. |
| 553 | // NOTE: Nintendo does not check the result of this. | 1422 | // NOTE: Nintendo does not check the result of this. |
| 554 | // client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size); | 1423 | client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size); |
| 555 | 1424 | ||
| 556 | // Signal the event. | 1425 | // Signal the event. |
| 557 | event->Signal(); | 1426 | event->Signal(); |
| @@ -567,4 +1436,97 @@ void KServerSession::CleanupRequests() { | |||
| 567 | } | 1436 | } |
| 568 | } | 1437 | } |
| 569 | 1438 | ||
| 1439 | void KServerSession::OnClientClosed() { | ||
| 1440 | KScopedLightLock lk{m_lock}; | ||
| 1441 | |||
| 1442 | // Handle any pending requests. | ||
| 1443 | KSessionRequest* prev_request = nullptr; | ||
| 1444 | while (true) { | ||
| 1445 | // Declare variables for processing the request. | ||
| 1446 | KSessionRequest* request = nullptr; | ||
| 1447 | KEvent* event = nullptr; | ||
| 1448 | KThread* thread = nullptr; | ||
| 1449 | bool cur_request = false; | ||
| 1450 | bool terminate = false; | ||
| 1451 | |||
| 1452 | // Get the next request. | ||
| 1453 | { | ||
| 1454 | KScopedSchedulerLock sl{m_kernel}; | ||
| 1455 | |||
| 1456 | if (m_current_request != nullptr && m_current_request != prev_request) { | ||
| 1457 | // Set the request, open a reference as we process it. | ||
| 1458 | request = m_current_request; | ||
| 1459 | request->Open(); | ||
| 1460 | cur_request = true; | ||
| 1461 | |||
| 1462 | // Get thread and event for the request. | ||
| 1463 | thread = request->GetThread(); | ||
| 1464 | event = request->GetEvent(); | ||
| 1465 | |||
| 1466 | // If the thread is terminating, handle that. | ||
| 1467 | if (thread->IsTerminationRequested()) { | ||
| 1468 | request->ClearThread(); | ||
| 1469 | request->ClearEvent(); | ||
| 1470 | terminate = true; | ||
| 1471 | } | ||
| 1472 | |||
| 1473 | prev_request = request; | ||
| 1474 | } else if (!m_request_list.empty()) { | ||
| 1475 | // Pop the request from the front of the list. | ||
| 1476 | request = std::addressof(m_request_list.front()); | ||
| 1477 | m_request_list.pop_front(); | ||
| 1478 | |||
| 1479 | // Get thread and event for the request. | ||
| 1480 | thread = request->GetThread(); | ||
| 1481 | event = request->GetEvent(); | ||
| 1482 | } | ||
| 1483 | } | ||
| 1484 | |||
| 1485 | // If there are no requests, we're done. | ||
| 1486 | if (request == nullptr) { | ||
| 1487 | break; | ||
| 1488 | } | ||
| 1489 | |||
| 1490 | // All requests must have threads. | ||
| 1491 | ASSERT(thread != nullptr); | ||
| 1492 | |||
| 1493 | // Ensure that we close the request when done. | ||
| 1494 | SCOPE_EXIT({ request->Close(); }); | ||
| 1495 | |||
| 1496 | // If we're terminating, close a reference to the thread and event. | ||
| 1497 | if (terminate) { | ||
| 1498 | thread->Close(); | ||
| 1499 | if (event != nullptr) { | ||
| 1500 | event->Close(); | ||
| 1501 | } | ||
| 1502 | } | ||
| 1503 | |||
| 1504 | // If we need to, reply. | ||
| 1505 | if (event != nullptr && !cur_request) { | ||
| 1506 | // There must be no mappings. | ||
| 1507 | ASSERT(request->GetSendCount() == 0); | ||
| 1508 | ASSERT(request->GetReceiveCount() == 0); | ||
| 1509 | ASSERT(request->GetExchangeCount() == 0); | ||
| 1510 | |||
| 1511 | // Get the process and page table. | ||
| 1512 | KProcess* client_process = thread->GetOwnerProcess(); | ||
| 1513 | auto& client_pt = client_process->GetPageTable(); | ||
| 1514 | |||
| 1515 | // Reply to the request. | ||
| 1516 | ReplyAsyncError(client_process, request->GetAddress(), request->GetSize(), | ||
| 1517 | ResultSessionClosed); | ||
| 1518 | |||
| 1519 | // Unlock the buffer. | ||
| 1520 | // NOTE: Nintendo does not check the result of this. | ||
| 1521 | client_pt.UnlockForIpcUserBuffer(request->GetAddress(), request->GetSize()); | ||
| 1522 | |||
| 1523 | // Signal the event. | ||
| 1524 | event->Signal(); | ||
| 1525 | } | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | // Notify. | ||
| 1529 | this->NotifyAvailable(ResultSessionClosed); | ||
| 1530 | } | ||
| 1531 | |||
| 570 | } // namespace Kernel | 1532 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h index 403891919..2876c231b 100644 --- a/src/core/hle/kernel/k_server_session.h +++ b/src/core/hle/kernel/k_server_session.h | |||
| @@ -49,14 +49,21 @@ public: | |||
| 49 | bool IsSignaled() const override; | 49 | bool IsSignaled() const override; |
| 50 | void OnClientClosed(); | 50 | void OnClientClosed(); |
| 51 | 51 | ||
| 52 | /// TODO: flesh these out to match the real kernel | ||
| 53 | Result OnRequest(KSessionRequest* request); | 52 | Result OnRequest(KSessionRequest* request); |
| 54 | Result SendReply(bool is_hle = false); | 53 | Result SendReply(uintptr_t server_message, uintptr_t server_buffer_size, |
| 55 | Result ReceiveRequest(std::shared_ptr<Service::HLERequestContext>* out_context = nullptr, | 54 | KPhysicalAddress server_message_paddr, bool is_hle = false); |
| 55 | Result ReceiveRequest(uintptr_t server_message, uintptr_t server_buffer_size, | ||
| 56 | KPhysicalAddress server_message_paddr, | ||
| 57 | std::shared_ptr<Service::HLERequestContext>* out_context = nullptr, | ||
| 56 | std::weak_ptr<Service::SessionRequestManager> manager = {}); | 58 | std::weak_ptr<Service::SessionRequestManager> manager = {}); |
| 57 | 59 | ||
| 58 | Result SendReplyHLE() { | 60 | Result SendReplyHLE() { |
| 59 | return SendReply(true); | 61 | R_RETURN(this->SendReply(0, 0, 0, true)); |
| 62 | } | ||
| 63 | |||
| 64 | Result ReceiveRequestHLE(std::shared_ptr<Service::HLERequestContext>* out_context, | ||
| 65 | std::weak_ptr<Service::SessionRequestManager> manager) { | ||
| 66 | R_RETURN(this->ReceiveRequest(0, 0, 0, out_context, manager)); | ||
| 60 | } | 67 | } |
| 61 | 68 | ||
| 62 | private: | 69 | private: |
diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp index 44d7a8f02..4a1f6027e 100644 --- a/src/core/hle/kernel/k_session.cpp +++ b/src/core/hle/kernel/k_session.cpp | |||
| @@ -33,8 +33,7 @@ void KSession::Initialize(KClientPort* client_port, uintptr_t name) { | |||
| 33 | m_name = name; | 33 | m_name = name; |
| 34 | 34 | ||
| 35 | // Set our owner process. | 35 | // Set our owner process. |
| 36 | //! FIXME: this is the wrong process! | 36 | m_process = GetCurrentProcessPointer(m_kernel); |
| 37 | m_process = m_kernel.ApplicationProcess(); | ||
| 38 | m_process->Open(); | 37 | m_process->Open(); |
| 39 | 38 | ||
| 40 | // Set our port. | 39 | // Set our port. |
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 7d9a6e9cf..7d3421929 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp | |||
| @@ -1258,11 +1258,11 @@ ThreadState KThread::RequestTerminate() { | |||
| 1258 | // Change the thread's priority to be higher than any system thread's. | 1258 | // Change the thread's priority to be higher than any system thread's. |
| 1259 | this->IncreaseBasePriority(TerminatingThreadPriority); | 1259 | this->IncreaseBasePriority(TerminatingThreadPriority); |
| 1260 | 1260 | ||
| 1261 | // If the thread is runnable, send a termination interrupt to other cores. | 1261 | // If the thread is runnable, send a termination interrupt to cores it may be running on. |
| 1262 | if (this->GetState() == ThreadState::Runnable) { | 1262 | if (this->GetState() == ThreadState::Runnable) { |
| 1263 | if (const u64 core_mask = m_physical_affinity_mask.GetAffinityMask() & | 1263 | // NOTE: We do not mask the "current core", because this code may not actually be |
| 1264 | ~(1ULL << GetCurrentCoreId(m_kernel)); | 1264 | // executing from the thread representing the "current core". |
| 1265 | core_mask != 0) { | 1265 | if (const u64 core_mask = m_physical_affinity_mask.GetAffinityMask(); core_mask != 0) { |
| 1266 | Kernel::KInterruptManager::SendInterProcessorInterrupt(m_kernel, core_mask); | 1266 | Kernel::KInterruptManager::SendInterProcessorInterrupt(m_kernel, core_mask); |
| 1267 | } | 1267 | } |
| 1268 | } | 1268 | } |
| @@ -1422,8 +1422,7 @@ s32 GetCurrentCoreId(KernelCore& kernel) { | |||
| 1422 | } | 1422 | } |
| 1423 | 1423 | ||
| 1424 | Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel) { | 1424 | Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel) { |
| 1425 | // TODO: per-process memory | 1425 | return GetCurrentProcess(kernel).GetMemory(); |
| 1426 | return kernel.System().ApplicationMemory(); | ||
| 1427 | } | 1426 | } |
| 1428 | 1427 | ||
| 1429 | KScopedDisableDispatch::~KScopedDisableDispatch() { | 1428 | KScopedDisableDispatch::~KScopedDisableDispatch() { |
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index e9925d231..f13e232b2 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -314,11 +314,7 @@ public: | |||
| 314 | m_current_core_id = core; | 314 | m_current_core_id = core; |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | KProcess* GetOwnerProcess() { | 317 | KProcess* GetOwnerProcess() const { |
| 318 | return m_parent; | ||
| 319 | } | ||
| 320 | |||
| 321 | const KProcess* GetOwnerProcess() const { | ||
| 322 | return m_parent; | 318 | return m_parent; |
| 323 | } | 319 | } |
| 324 | 320 | ||
diff --git a/src/core/hle/kernel/k_transfer_memory.h b/src/core/hle/kernel/k_transfer_memory.h index 8a0b08761..530b45218 100644 --- a/src/core/hle/kernel/k_transfer_memory.h +++ b/src/core/hle/kernel/k_transfer_memory.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include <optional> | 6 | #include <optional> |
| 7 | 7 | ||
| 8 | #include "core/hle/kernel/k_light_lock.h" | ||
| 8 | #include "core/hle/kernel/k_page_group.h" | 9 | #include "core/hle/kernel/k_page_group.h" |
| 9 | #include "core/hle/kernel/slab_helpers.h" | 10 | #include "core/hle/kernel/slab_helpers.h" |
| 10 | #include "core/hle/kernel/svc_types.h" | 11 | #include "core/hle/kernel/svc_types.h" |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index e479dacde..1030f0c12 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -68,8 +68,6 @@ struct KernelCore::Impl { | |||
| 68 | 68 | ||
| 69 | global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel); | 69 | global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel); |
| 70 | global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); | 70 | global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); |
| 71 | global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel); | ||
| 72 | global_handle_table->Initialize(KHandleTable::MaxTableSize); | ||
| 73 | 71 | ||
| 74 | is_phantom_mode_for_singlecore = false; | 72 | is_phantom_mode_for_singlecore = false; |
| 75 | 73 | ||
| @@ -121,13 +119,8 @@ struct KernelCore::Impl { | |||
| 121 | next_user_process_id = KProcess::ProcessIdMin; | 119 | next_user_process_id = KProcess::ProcessIdMin; |
| 122 | next_thread_id = 1; | 120 | next_thread_id = 1; |
| 123 | 121 | ||
| 124 | global_handle_table->Finalize(); | ||
| 125 | global_handle_table.reset(); | ||
| 126 | |||
| 127 | preemption_event = nullptr; | 122 | preemption_event = nullptr; |
| 128 | 123 | ||
| 129 | exclusive_monitor.reset(); | ||
| 130 | |||
| 131 | // Cleanup persistent kernel objects | 124 | // Cleanup persistent kernel objects |
| 132 | auto CleanupObject = [](KAutoObject* obj) { | 125 | auto CleanupObject = [](KAutoObject* obj) { |
| 133 | if (obj) { | 126 | if (obj) { |
| @@ -191,8 +184,6 @@ struct KernelCore::Impl { | |||
| 191 | } | 184 | } |
| 192 | 185 | ||
| 193 | void InitializePhysicalCores() { | 186 | void InitializePhysicalCores() { |
| 194 | exclusive_monitor = | ||
| 195 | Core::MakeExclusiveMonitor(system.ApplicationMemory(), Core::Hardware::NUM_CPU_CORES); | ||
| 196 | for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { | 187 | for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { |
| 197 | const s32 core{static_cast<s32>(i)}; | 188 | const s32 core{static_cast<s32>(i)}; |
| 198 | 189 | ||
| @@ -247,7 +238,7 @@ struct KernelCore::Impl { | |||
| 247 | void InitializePreemption(KernelCore& kernel) { | 238 | void InitializePreemption(KernelCore& kernel) { |
| 248 | preemption_event = Core::Timing::CreateEvent( | 239 | preemption_event = Core::Timing::CreateEvent( |
| 249 | "PreemptionCallback", | 240 | "PreemptionCallback", |
| 250 | [this, &kernel](std::uintptr_t, s64 time, | 241 | [this, &kernel](s64 time, |
| 251 | std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> { | 242 | std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> { |
| 252 | { | 243 | { |
| 253 | KScopedSchedulerLock lock(kernel); | 244 | KScopedSchedulerLock lock(kernel); |
| @@ -791,10 +782,6 @@ struct KernelCore::Impl { | |||
| 791 | 782 | ||
| 792 | std::shared_ptr<Core::Timing::EventType> preemption_event; | 783 | std::shared_ptr<Core::Timing::EventType> preemption_event; |
| 793 | 784 | ||
| 794 | // This is the kernel's handle table or supervisor handle table which | ||
| 795 | // stores all the objects in place. | ||
| 796 | std::unique_ptr<KHandleTable> global_handle_table; | ||
| 797 | |||
| 798 | std::unique_ptr<KAutoObjectWithListContainer> global_object_list_container; | 785 | std::unique_ptr<KAutoObjectWithListContainer> global_object_list_container; |
| 799 | 786 | ||
| 800 | std::unique_ptr<KObjectNameGlobalData> object_name_global_data; | 787 | std::unique_ptr<KObjectNameGlobalData> object_name_global_data; |
| @@ -805,7 +792,6 @@ struct KernelCore::Impl { | |||
| 805 | std::mutex server_lock; | 792 | std::mutex server_lock; |
| 806 | std::vector<std::unique_ptr<Service::ServerManager>> server_managers; | 793 | std::vector<std::unique_ptr<Service::ServerManager>> server_managers; |
| 807 | 794 | ||
| 808 | std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; | ||
| 809 | std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores; | 795 | std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores; |
| 810 | 796 | ||
| 811 | // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others | 797 | // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others |
| @@ -882,10 +868,6 @@ KResourceLimit* KernelCore::GetSystemResourceLimit() { | |||
| 882 | return impl->system_resource_limit; | 868 | return impl->system_resource_limit; |
| 883 | } | 869 | } |
| 884 | 870 | ||
| 885 | KScopedAutoObject<KThread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const { | ||
| 886 | return impl->global_handle_table->GetObject<KThread>(handle); | ||
| 887 | } | ||
| 888 | |||
| 889 | void KernelCore::AppendNewProcess(KProcess* process) { | 871 | void KernelCore::AppendNewProcess(KProcess* process) { |
| 890 | impl->process_list.push_back(process); | 872 | impl->process_list.push_back(process); |
| 891 | } | 873 | } |
| @@ -959,14 +941,6 @@ Kernel::KHardwareTimer& KernelCore::HardwareTimer() { | |||
| 959 | return *impl->hardware_timer; | 941 | return *impl->hardware_timer; |
| 960 | } | 942 | } |
| 961 | 943 | ||
| 962 | Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { | ||
| 963 | return *impl->exclusive_monitor; | ||
| 964 | } | ||
| 965 | |||
| 966 | const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { | ||
| 967 | return *impl->exclusive_monitor; | ||
| 968 | } | ||
| 969 | |||
| 970 | KAutoObjectWithListContainer& KernelCore::ObjectListContainer() { | 944 | KAutoObjectWithListContainer& KernelCore::ObjectListContainer() { |
| 971 | return *impl->global_object_list_container; | 945 | return *impl->global_object_list_container; |
| 972 | } | 946 | } |
| @@ -1030,14 +1004,6 @@ u64 KernelCore::CreateNewUserProcessID() { | |||
| 1030 | return impl->next_user_process_id++; | 1004 | return impl->next_user_process_id++; |
| 1031 | } | 1005 | } |
| 1032 | 1006 | ||
| 1033 | KHandleTable& KernelCore::GlobalHandleTable() { | ||
| 1034 | return *impl->global_handle_table; | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | const KHandleTable& KernelCore::GlobalHandleTable() const { | ||
| 1038 | return *impl->global_handle_table; | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | void KernelCore::RegisterCoreThread(std::size_t core_id) { | 1007 | void KernelCore::RegisterCoreThread(std::size_t core_id) { |
| 1042 | impl->RegisterCoreThread(core_id); | 1008 | impl->RegisterCoreThread(core_id); |
| 1043 | } | 1009 | } |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 78c88902c..5d4102145 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -116,9 +116,6 @@ public: | |||
| 116 | /// Retrieves a shared pointer to the system resource limit instance. | 116 | /// Retrieves a shared pointer to the system resource limit instance. |
| 117 | KResourceLimit* GetSystemResourceLimit(); | 117 | KResourceLimit* GetSystemResourceLimit(); |
| 118 | 118 | ||
| 119 | /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. | ||
| 120 | KScopedAutoObject<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const; | ||
| 121 | |||
| 122 | /// Adds the given shared pointer to an internal list of active processes. | 119 | /// Adds the given shared pointer to an internal list of active processes. |
| 123 | void AppendNewProcess(KProcess* process); | 120 | void AppendNewProcess(KProcess* process); |
| 124 | 121 | ||
| @@ -170,10 +167,6 @@ public: | |||
| 170 | /// Stops execution of 'id' core, in order to reschedule a new thread. | 167 | /// Stops execution of 'id' core, in order to reschedule a new thread. |
| 171 | void PrepareReschedule(std::size_t id); | 168 | void PrepareReschedule(std::size_t id); |
| 172 | 169 | ||
| 173 | Core::ExclusiveMonitor& GetExclusiveMonitor(); | ||
| 174 | |||
| 175 | const Core::ExclusiveMonitor& GetExclusiveMonitor() const; | ||
| 176 | |||
| 177 | KAutoObjectWithListContainer& ObjectListContainer(); | 170 | KAutoObjectWithListContainer& ObjectListContainer(); |
| 178 | 171 | ||
| 179 | const KAutoObjectWithListContainer& ObjectListContainer() const; | 172 | const KAutoObjectWithListContainer& ObjectListContainer() const; |
diff --git a/src/core/hle/kernel/message_buffer.h b/src/core/hle/kernel/message_buffer.h index 75b275310..d528a9bb3 100644 --- a/src/core/hle/kernel/message_buffer.h +++ b/src/core/hle/kernel/message_buffer.h | |||
| @@ -18,13 +18,13 @@ public: | |||
| 18 | static constexpr inline u64 NullTag = 0; | 18 | static constexpr inline u64 NullTag = 0; |
| 19 | 19 | ||
| 20 | public: | 20 | public: |
| 21 | enum class ReceiveListCountType : u32 { | 21 | enum ReceiveListCountType : u32 { |
| 22 | None = 0, | 22 | ReceiveListCountType_None = 0, |
| 23 | ToMessageBuffer = 1, | 23 | ReceiveListCountType_ToMessageBuffer = 1, |
| 24 | ToSingleBuffer = 2, | 24 | ReceiveListCountType_ToSingleBuffer = 2, |
| 25 | 25 | ||
| 26 | CountOffset = 2, | 26 | ReceiveListCountType_CountOffset = 2, |
| 27 | CountMax = 13, | 27 | ReceiveListCountType_CountMax = 13, |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | private: | 30 | private: |
| @@ -591,16 +591,16 @@ public: | |||
| 591 | // Add the size of the receive list. | 591 | // Add the size of the receive list. |
| 592 | const auto count = hdr.GetReceiveListCount(); | 592 | const auto count = hdr.GetReceiveListCount(); |
| 593 | switch (count) { | 593 | switch (count) { |
| 594 | case MessageHeader::ReceiveListCountType::None: | 594 | case MessageHeader::ReceiveListCountType_None: |
| 595 | break; | 595 | break; |
| 596 | case MessageHeader::ReceiveListCountType::ToMessageBuffer: | 596 | case MessageHeader::ReceiveListCountType_ToMessageBuffer: |
| 597 | break; | 597 | break; |
| 598 | case MessageHeader::ReceiveListCountType::ToSingleBuffer: | 598 | case MessageHeader::ReceiveListCountType_ToSingleBuffer: |
| 599 | msg_size += ReceiveListEntry::GetDataSize(); | 599 | msg_size += ReceiveListEntry::GetDataSize(); |
| 600 | break; | 600 | break; |
| 601 | default: | 601 | default: |
| 602 | msg_size += (static_cast<s32>(count) - | 602 | msg_size += (static_cast<s32>(count) - |
| 603 | static_cast<s32>(MessageHeader::ReceiveListCountType::CountOffset)) * | 603 | static_cast<s32>(MessageHeader::ReceiveListCountType_CountOffset)) * |
| 604 | ReceiveListEntry::GetDataSize(); | 604 | ReceiveListEntry::GetDataSize(); |
| 605 | break; | 605 | break; |
| 606 | } | 606 | } |
diff --git a/src/core/hle/kernel/svc/svc_info.cpp b/src/core/hle/kernel/svc/svc_info.cpp index ada998772..231e4d0e1 100644 --- a/src/core/hle/kernel/svc/svc_info.cpp +++ b/src/core/hle/kernel/svc/svc_info.cpp | |||
| @@ -118,7 +118,6 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle | |||
| 118 | R_SUCCEED(); | 118 | R_SUCCEED(); |
| 119 | 119 | ||
| 120 | case InfoType::IsApplication: | 120 | case InfoType::IsApplication: |
| 121 | LOG_WARNING(Kernel_SVC, "(STUBBED) Assuming process is application"); | ||
| 122 | *result = process->IsApplication(); | 121 | *result = process->IsApplication(); |
| 123 | R_SUCCEED(); | 122 | R_SUCCEED(); |
| 124 | 123 | ||
diff --git a/src/core/hle/kernel/svc/svc_ipc.cpp b/src/core/hle/kernel/svc/svc_ipc.cpp index 47a3e7bb0..85cc4f561 100644 --- a/src/core/hle/kernel/svc/svc_ipc.cpp +++ b/src/core/hle/kernel/svc/svc_ipc.cpp | |||
| @@ -48,8 +48,7 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes | |||
| 48 | }; | 48 | }; |
| 49 | 49 | ||
| 50 | // Send the reply. | 50 | // Send the reply. |
| 51 | R_TRY(session->SendReply()); | 51 | R_TRY(session->SendReply(message, buffer_size, message_paddr)); |
| 52 | // R_TRY(session->SendReply(message, buffer_size, message_paddr)); | ||
| 53 | } | 52 | } |
| 54 | 53 | ||
| 55 | // Receive a message. | 54 | // Receive a message. |
| @@ -85,8 +84,7 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes | |||
| 85 | if (R_SUCCEEDED(result)) { | 84 | if (R_SUCCEEDED(result)) { |
| 86 | KServerSession* session = objs[index]->DynamicCast<KServerSession*>(); | 85 | KServerSession* session = objs[index]->DynamicCast<KServerSession*>(); |
| 87 | if (session != nullptr) { | 86 | if (session != nullptr) { |
| 88 | // result = session->ReceiveRequest(message, buffer_size, message_paddr); | 87 | result = session->ReceiveRequest(message, buffer_size, message_paddr); |
| 89 | result = session->ReceiveRequest(); | ||
| 90 | if (ResultNotFound == result) { | 88 | if (ResultNotFound == result) { |
| 91 | continue; | 89 | continue; |
| 92 | } | 90 | } |
diff --git a/src/core/hle/kernel/svc_results.h b/src/core/hle/kernel/svc_results.h index e1ad78607..38e71d516 100644 --- a/src/core/hle/kernel/svc_results.h +++ b/src/core/hle/kernel/svc_results.h | |||
| @@ -38,7 +38,9 @@ constexpr Result ResultInvalidState{ErrorModule::Kernel, 125}; | |||
| 38 | constexpr Result ResultReservedUsed{ErrorModule::Kernel, 126}; | 38 | constexpr Result ResultReservedUsed{ErrorModule::Kernel, 126}; |
| 39 | constexpr Result ResultPortClosed{ErrorModule::Kernel, 131}; | 39 | constexpr Result ResultPortClosed{ErrorModule::Kernel, 131}; |
| 40 | constexpr Result ResultLimitReached{ErrorModule::Kernel, 132}; | 40 | constexpr Result ResultLimitReached{ErrorModule::Kernel, 132}; |
| 41 | constexpr Result ResultReceiveListBroken{ErrorModule::Kernel, 258}; | ||
| 41 | constexpr Result ResultOutOfAddressSpace{ErrorModule::Kernel, 259}; | 42 | constexpr Result ResultOutOfAddressSpace{ErrorModule::Kernel, 259}; |
| 43 | constexpr Result ResultMessageTooLarge{ErrorModule::Kernel, 260}; | ||
| 42 | constexpr Result ResultInvalidId{ErrorModule::Kernel, 519}; | 44 | constexpr Result ResultInvalidId{ErrorModule::Kernel, 519}; |
| 43 | 45 | ||
| 44 | } // namespace Kernel | 46 | } // namespace Kernel |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index a266d7c21..97eb56ff0 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -1513,8 +1513,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) | |||
| 1513 | return; | 1513 | return; |
| 1514 | } | 1514 | } |
| 1515 | 1515 | ||
| 1516 | auto transfer_mem = | 1516 | auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle); |
| 1517 | system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle); | ||
| 1518 | 1517 | ||
| 1519 | if (transfer_mem.IsNull()) { | 1518 | if (transfer_mem.IsNull()) { |
| 1520 | LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); | 1519 | LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); |
| @@ -1524,8 +1523,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) | |||
| 1524 | } | 1523 | } |
| 1525 | 1524 | ||
| 1526 | std::vector<u8> memory(transfer_mem->GetSize()); | 1525 | std::vector<u8> memory(transfer_mem->GetSize()); |
| 1527 | system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), | 1526 | ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); |
| 1528 | memory.size()); | ||
| 1529 | 1527 | ||
| 1530 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1528 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1531 | rb.Push(ResultSuccess); | 1529 | rb.Push(ResultSuccess); |
| @@ -1547,8 +1545,7 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) { | |||
| 1547 | return; | 1545 | return; |
| 1548 | } | 1546 | } |
| 1549 | 1547 | ||
| 1550 | auto transfer_mem = | 1548 | auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle); |
| 1551 | system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle); | ||
| 1552 | 1549 | ||
| 1553 | if (transfer_mem.IsNull()) { | 1550 | if (transfer_mem.IsNull()) { |
| 1554 | LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); | 1551 | LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); |
| @@ -1558,8 +1555,7 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) { | |||
| 1558 | } | 1555 | } |
| 1559 | 1556 | ||
| 1560 | std::vector<u8> memory(transfer_mem->GetSize()); | 1557 | std::vector<u8> memory(transfer_mem->GetSize()); |
| 1561 | system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), | 1558 | ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); |
| 1562 | memory.size()); | ||
| 1563 | 1559 | ||
| 1564 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1560 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1565 | rb.Push(ResultSuccess); | 1561 | rb.Push(ResultSuccess); |
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 23e56c77a..bd4ca753b 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp | |||
| @@ -454,10 +454,8 @@ void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) { | |||
| 454 | return; | 454 | return; |
| 455 | } | 455 | } |
| 456 | 456 | ||
| 457 | const auto& handle_table{system.ApplicationProcess()->GetHandleTable()}; | 457 | auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)}; |
| 458 | auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)}; | 458 | auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; |
| 459 | auto transfer_memory{ | ||
| 460 | process->GetHandleTable().GetObject<Kernel::KTransferMemory>(transfer_memory_handle)}; | ||
| 461 | 459 | ||
| 462 | const auto session_id{impl->GetSessionId()}; | 460 | const auto session_id{impl->GetSessionId()}; |
| 463 | if (session_id == -1) { | 461 | if (session_id == -1) { |
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 6a7bf9416..91f33aabd 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp | |||
| @@ -278,9 +278,7 @@ void HwOpus::OpenHardwareOpusDecoder(HLERequestContext& ctx) { | |||
| 278 | auto params = rp.PopRaw<OpusParameters>(); | 278 | auto params = rp.PopRaw<OpusParameters>(); |
| 279 | auto transfer_memory_size{rp.Pop<u32>()}; | 279 | auto transfer_memory_size{rp.Pop<u32>()}; |
| 280 | auto transfer_memory_handle{ctx.GetCopyHandle(0)}; | 280 | auto transfer_memory_handle{ctx.GetCopyHandle(0)}; |
| 281 | auto transfer_memory{ | 281 | auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; |
| 282 | system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( | ||
| 283 | transfer_memory_handle)}; | ||
| 284 | 282 | ||
| 285 | LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}", | 283 | LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}", |
| 286 | params.sample_rate, params.channel_count, transfer_memory_size); | 284 | params.sample_rate, params.channel_count, transfer_memory_size); |
| @@ -323,9 +321,7 @@ void HwOpus::OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx) { | |||
| 323 | 321 | ||
| 324 | auto transfer_memory_size{rp.Pop<u32>()}; | 322 | auto transfer_memory_size{rp.Pop<u32>()}; |
| 325 | auto transfer_memory_handle{ctx.GetCopyHandle(0)}; | 323 | auto transfer_memory_handle{ctx.GetCopyHandle(0)}; |
| 326 | auto transfer_memory{ | 324 | auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; |
| 327 | system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( | ||
| 328 | transfer_memory_handle)}; | ||
| 329 | 325 | ||
| 330 | LOG_DEBUG(Service_Audio, | 326 | LOG_DEBUG(Service_Audio, |
| 331 | "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " | 327 | "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " |
| @@ -374,9 +370,7 @@ void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) { | |||
| 374 | auto params = rp.PopRaw<OpusParametersEx>(); | 370 | auto params = rp.PopRaw<OpusParametersEx>(); |
| 375 | auto transfer_memory_size{rp.Pop<u32>()}; | 371 | auto transfer_memory_size{rp.Pop<u32>()}; |
| 376 | auto transfer_memory_handle{ctx.GetCopyHandle(0)}; | 372 | auto transfer_memory_handle{ctx.GetCopyHandle(0)}; |
| 377 | auto transfer_memory{ | 373 | auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; |
| 378 | system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( | ||
| 379 | transfer_memory_handle)}; | ||
| 380 | 374 | ||
| 381 | LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}", | 375 | LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}", |
| 382 | params.sample_rate, params.channel_count, transfer_memory_size); | 376 | params.sample_rate, params.channel_count, transfer_memory_size); |
| @@ -414,9 +408,7 @@ void HwOpus::OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx) { | |||
| 414 | 408 | ||
| 415 | auto transfer_memory_size{rp.Pop<u32>()}; | 409 | auto transfer_memory_size{rp.Pop<u32>()}; |
| 416 | auto transfer_memory_handle{ctx.GetCopyHandle(0)}; | 410 | auto transfer_memory_handle{ctx.GetCopyHandle(0)}; |
| 417 | auto transfer_memory{ | 411 | auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; |
| 418 | system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( | ||
| 419 | transfer_memory_handle)}; | ||
| 420 | 412 | ||
| 421 | LOG_DEBUG(Service_Audio, | 413 | LOG_DEBUG(Service_Audio, |
| 422 | "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " | 414 | "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " |
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index fe2ed8df8..31da86074 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp | |||
| @@ -89,7 +89,7 @@ static void GenerateErrorReport(Core::System& system, Result error_code, const F | |||
| 89 | crash_report += fmt::format(" ESR: {:016x}\n", info.esr); | 89 | crash_report += fmt::format(" ESR: {:016x}\n", info.esr); |
| 90 | crash_report += fmt::format(" FAR: {:016x}\n", info.far); | 90 | crash_report += fmt::format(" FAR: {:016x}\n", info.far); |
| 91 | crash_report += "\nBacktrace:\n"; | 91 | crash_report += "\nBacktrace:\n"; |
| 92 | for (size_t i = 0; i < info.backtrace_size; i++) { | 92 | for (u32 i = 0; i < std::min<u32>(info.backtrace_size, 32); i++) { |
| 93 | crash_report += | 93 | crash_report += |
| 94 | fmt::format(" Backtrace[{:02d}]: {:016x}\n", i, info.backtrace[i]); | 94 | fmt::format(" Backtrace[{:02d}]: {:016x}\n", i, info.backtrace[i]); |
| 95 | } | 95 | } |
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..0862fdc2f 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,60 @@ 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 | static constexpr u64 SystemAruid = 0; | ||
| 29 | |||
| 30 | enum class RegistrationStatus : u32 { | ||
| 31 | None, | ||
| 32 | Initialized, | ||
| 33 | PendingDelete, | ||
| 34 | }; | ||
| 35 | |||
| 36 | struct DataStatusFlag { | ||
| 37 | union { | ||
| 38 | u32 raw{}; | ||
| 39 | |||
| 40 | BitField<0, 1, u32> is_initialized; | ||
| 41 | BitField<1, 1, u32> is_assigned; | ||
| 42 | BitField<16, 1, u32> enable_pad_input; | ||
| 43 | BitField<17, 1, u32> enable_six_axis_sensor; | ||
| 44 | BitField<18, 1, u32> bit_18; | ||
| 45 | BitField<19, 1, u32> is_palma_connectable; | ||
| 46 | BitField<20, 1, u32> enable_palma_boost_mode; | ||
| 47 | BitField<21, 1, u32> enable_touchscreen; | ||
| 48 | }; | ||
| 49 | }; | ||
| 50 | |||
| 51 | struct AruidRegisterList { | ||
| 52 | std::array<RegistrationStatus, AruidIndexMax> flag{}; | ||
| 53 | std::array<u64, AruidIndexMax> aruid{}; | ||
| 54 | }; | ||
| 55 | static_assert(sizeof(AruidRegisterList) == 0x180, "AruidRegisterList is an invalid size"); | ||
| 56 | |||
| 57 | struct AruidData { | ||
| 58 | DataStatusFlag flag{}; | ||
| 59 | u64 aruid{}; | ||
| 60 | SharedMemoryFormat* shared_memory_format{nullptr}; | ||
| 61 | }; | ||
| 62 | |||
| 63 | struct HandheldConfig { | ||
| 64 | bool is_handheld_hid_enabled; | ||
| 65 | bool is_force_handheld; | ||
| 66 | bool is_joycon_rail_enabled; | ||
| 67 | bool is_force_handheld_style_vibration; | ||
| 68 | }; | ||
| 69 | static_assert(sizeof(HandheldConfig) == 0x4, "HandheldConfig is an invalid size"); | ||
| 70 | |||
| 71 | struct AppletResourceHolder { | ||
| 72 | std::shared_ptr<AppletResource> applet_resource{nullptr}; | ||
| 73 | std::recursive_mutex* shared_mutex{nullptr}; | ||
| 74 | NPadResource* shared_npad_resource{nullptr}; | ||
| 75 | std::shared_ptr<HandheldConfig> handheld_config{nullptr}; | ||
| 76 | long* handle_1; | ||
| 77 | }; | ||
| 23 | 78 | ||
| 24 | class AppletResource { | 79 | class AppletResource { |
| 25 | public: | 80 | public: |
| @@ -36,6 +91,10 @@ public: | |||
| 36 | u64 GetActiveAruid(); | 91 | u64 GetActiveAruid(); |
| 37 | Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid); | 92 | Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid); |
| 38 | Result GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, u64 aruid); | 93 | Result GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, u64 aruid); |
| 94 | AruidData* GetAruidData(u64 aruid); | ||
| 95 | AruidData* GetAruidDataByIndex(std::size_t aruid_index); | ||
| 96 | |||
| 97 | bool IsVibrationAruidActive(u64 aruid) const; | ||
| 39 | 98 | ||
| 40 | u64 GetIndexFromAruid(u64 aruid); | 99 | u64 GetIndexFromAruid(u64 aruid); |
| 41 | 100 | ||
| @@ -52,46 +111,12 @@ public: | |||
| 52 | Result UnregisterCoreAppletResource(); | 111 | Result UnregisterCoreAppletResource(); |
| 53 | 112 | ||
| 54 | private: | 113 | 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{}; | 114 | u64 active_aruid{}; |
| 91 | AruidRegisterList registration_list{}; | 115 | AruidRegisterList registration_list{}; |
| 92 | std::array<AruidData, AruidIndexMax> data{}; | 116 | std::array<AruidData, AruidIndexMax> data{}; |
| 93 | std::array<SharedMemoryHolder, AruidIndexMax> shared_memory_holder{}; | 117 | std::array<SharedMemoryHolder, AruidIndexMax> shared_memory_holder{}; |
| 94 | s32 ref_counter{}; | 118 | s32 ref_counter{}; |
| 119 | u64 active_vibration_aruid; | ||
| 95 | 120 | ||
| 96 | Core::System& system; | 121 | Core::System& system; |
| 97 | }; | 122 | }; |
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..7847c080e --- /dev/null +++ b/src/core/hle/service/hid/controllers/capture_button.cpp | |||
| @@ -0,0 +1,39 @@ | |||
| 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 | std::scoped_lock shared_lock{*shared_mutex}; | ||
| 25 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 26 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 27 | |||
| 28 | if (data == nullptr || !data->flag.is_assigned) { | ||
| 29 | return; | ||
| 30 | } | ||
| 31 | |||
| 32 | auto& header = data->shared_memory_format->capture_button.header; | ||
| 33 | header.timestamp = core_timing.GetGlobalTimeNs().count(); | ||
| 34 | header.total_entry_count = 17; | ||
| 35 | header.entry_count = 0; | ||
| 36 | header.last_entry_index = 0; | ||
| 37 | } | ||
| 38 | |||
| 39 | } // 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..4b574c2e5 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,16 @@ 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 | std::scoped_lock shared_lock{*shared_mutex}; | ||
| 24 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 25 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 26 | |||
| 27 | if (data == nullptr || !data->flag.is_assigned) { | ||
| 28 | return; | ||
| 29 | } | ||
| 30 | |||
| 31 | ConsoleSixAxisSensorSharedMemoryFormat& shared_memory = data->shared_memory_format->console; | ||
| 32 | |||
| 25 | if (!IsControllerActivated()) { | 33 | if (!IsControllerActivated()) { |
| 26 | return; | 34 | return; |
| 27 | } | 35 | } |
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..afca7154c 100644 --- a/src/core/hle/service/hid/controllers/controller_base.cpp +++ b/src/core/hle/service/hid/controllers/controller_base.cpp | |||
| @@ -31,4 +31,11 @@ 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 | std::recursive_mutex* resource_mutex) { | ||
| 37 | applet_resource = resource; | ||
| 38 | shared_mutex = resource_mutex; | ||
| 39 | } | ||
| 40 | |||
| 34 | } // namespace Service::HID | 41 | } // 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..b34b85ece 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,13 @@ public: | |||
| 39 | 42 | ||
| 40 | bool IsControllerActivated() const; | 43 | bool IsControllerActivated() const; |
| 41 | 44 | ||
| 45 | void SetAppletResource(std::shared_ptr<AppletResource> resource, | ||
| 46 | std::recursive_mutex* resource_mutex); | ||
| 47 | |||
| 42 | protected: | 48 | protected: |
| 43 | bool is_activated{false}; | 49 | bool is_activated{false}; |
| 50 | std::shared_ptr<AppletResource> applet_resource{nullptr}; | ||
| 51 | std::recursive_mutex* shared_mutex{nullptr}; | ||
| 44 | 52 | ||
| 45 | Core::HID::HIDCore& hid_core; | 53 | Core::HID::HIDCore& hid_core; |
| 46 | }; | 54 | }; |
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..ceeb78d36 --- /dev/null +++ b/src/core/hle/service/hid/controllers/debug_mouse.cpp | |||
| @@ -0,0 +1,64 @@ | |||
| 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 | std::scoped_lock shared_lock{*shared_mutex}; | ||
| 25 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 26 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 27 | |||
| 28 | if (data == nullptr || !data->flag.is_assigned) { | ||
| 29 | return; | ||
| 30 | } | ||
| 31 | |||
| 32 | MouseSharedMemoryFormat& shared_memory = data->shared_memory_format->debug_mouse; | ||
| 33 | |||
| 34 | if (!IsControllerActivated()) { | ||
| 35 | shared_memory.mouse_lifo.buffer_count = 0; | ||
| 36 | shared_memory.mouse_lifo.buffer_tail = 0; | ||
| 37 | return; | ||
| 38 | } | ||
| 39 | |||
| 40 | next_state = {}; | ||
| 41 | |||
| 42 | const auto& last_entry = shared_memory.mouse_lifo.ReadCurrentEntry().state; | ||
| 43 | next_state.sampling_number = last_entry.sampling_number + 1; | ||
| 44 | |||
| 45 | if (Settings::values.mouse_enabled) { | ||
| 46 | const auto& mouse_button_state = emulated_devices->GetMouseButtons(); | ||
| 47 | const auto& mouse_position_state = emulated_devices->GetMousePosition(); | ||
| 48 | const auto& mouse_wheel_state = emulated_devices->GetMouseWheel(); | ||
| 49 | next_state.attribute.is_connected.Assign(1); | ||
| 50 | next_state.x = static_cast<s32>(mouse_position_state.x * Layout::ScreenUndocked::Width); | ||
| 51 | next_state.y = static_cast<s32>(mouse_position_state.y * Layout::ScreenUndocked::Height); | ||
| 52 | next_state.delta_x = next_state.x - last_entry.x; | ||
| 53 | next_state.delta_y = next_state.y - last_entry.y; | ||
| 54 | next_state.delta_wheel_x = mouse_wheel_state.x - last_mouse_wheel_state.x; | ||
| 55 | next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y; | ||
| 56 | |||
| 57 | last_mouse_wheel_state = mouse_wheel_state; | ||
| 58 | next_state.button = mouse_button_state; | ||
| 59 | } | ||
| 60 | |||
| 61 | shared_memory.mouse_lifo.WriteNextEntry(next_state); | ||
| 62 | } | ||
| 63 | |||
| 64 | } // 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..dc83f90f3 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,16 @@ 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 | std::scoped_lock shared_lock{*shared_mutex}; | ||
| 27 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 28 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 29 | |||
| 30 | if (data == nullptr || !data->flag.is_assigned) { | ||
| 31 | return; | ||
| 32 | } | ||
| 33 | |||
| 34 | DebugPadSharedMemoryFormat& shared_memory = data->shared_memory_format->debug_pad; | ||
| 35 | |||
| 27 | if (!IsControllerActivated()) { | 36 | if (!IsControllerActivated()) { |
| 28 | shared_memory.debug_pad_lifo.buffer_count = 0; | 37 | shared_memory.debug_pad_lifo.buffer_count = 0; |
| 29 | shared_memory.debug_pad_lifo.buffer_tail = 0; | 38 | 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..d5514c965 --- /dev/null +++ b/src/core/hle/service/hid/controllers/digitizer.cpp | |||
| @@ -0,0 +1,39 @@ | |||
| 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 | std::scoped_lock shared_lock{*shared_mutex}; | ||
| 25 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 26 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 27 | |||
| 28 | if (data == nullptr || !data->flag.is_assigned) { | ||
| 29 | return; | ||
| 30 | } | ||
| 31 | |||
| 32 | auto& header = data->shared_memory_format->digitizer.header; | ||
| 33 | header.timestamp = core_timing.GetGlobalTimeNs().count(); | ||
| 34 | header.total_entry_count = 17; | ||
| 35 | header.entry_count = 0; | ||
| 36 | header.last_entry_index = 0; | ||
| 37 | } | ||
| 38 | |||
| 39 | } // 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..c73da13ee 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,42 @@ 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 | std::scoped_lock shared_lock{*shared_mutex}; |
| 32 | shared_memory.gesture_lifo.buffer_tail = 0; | 32 | const u64 aruid = applet_resource->GetActiveAruid(); |
| 33 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 34 | |||
| 35 | if (data == nullptr || !data->flag.is_assigned) { | ||
| 36 | return; | ||
| 37 | } | ||
| 38 | |||
| 39 | shared_memory = &data->shared_memory_format->gesture; | ||
| 40 | shared_memory->gesture_lifo.buffer_count = 0; | ||
| 41 | shared_memory->gesture_lifo.buffer_tail = 0; | ||
| 33 | force_update = true; | 42 | force_update = true; |
| 34 | } | 43 | } |
| 35 | 44 | ||
| 36 | void Gesture::OnRelease() {} | 45 | void Gesture::OnRelease() {} |
| 37 | 46 | ||
| 38 | void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | 47 | void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { |
| 48 | std::scoped_lock shared_lock{*shared_mutex}; | ||
| 49 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 50 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 51 | |||
| 52 | if (data == nullptr || !data->flag.is_assigned) { | ||
| 53 | return; | ||
| 54 | } | ||
| 55 | |||
| 56 | shared_memory = &data->shared_memory_format->gesture; | ||
| 57 | |||
| 39 | if (!IsControllerActivated()) { | 58 | if (!IsControllerActivated()) { |
| 40 | shared_memory.gesture_lifo.buffer_count = 0; | 59 | shared_memory->gesture_lifo.buffer_count = 0; |
| 41 | shared_memory.gesture_lifo.buffer_tail = 0; | 60 | shared_memory->gesture_lifo.buffer_tail = 0; |
| 42 | return; | 61 | return; |
| 43 | } | 62 | } |
| 44 | 63 | ||
| @@ -46,7 +65,7 @@ void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | |||
| 46 | 65 | ||
| 47 | GestureProperties gesture = GetGestureProperties(); | 66 | GestureProperties gesture = GetGestureProperties(); |
| 48 | f32 time_difference = | 67 | f32 time_difference = |
| 49 | static_cast<f32>(shared_memory.gesture_lifo.timestamp - last_update_timestamp) / | 68 | static_cast<f32>(shared_memory->gesture_lifo.timestamp - last_update_timestamp) / |
| 50 | (1000 * 1000 * 1000); | 69 | (1000 * 1000 * 1000); |
| 51 | 70 | ||
| 52 | // Only update if necessary | 71 | // Only update if necessary |
| @@ -54,7 +73,7 @@ void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | |||
| 54 | return; | 73 | return; |
| 55 | } | 74 | } |
| 56 | 75 | ||
| 57 | last_update_timestamp = shared_memory.gesture_lifo.timestamp; | 76 | last_update_timestamp = shared_memory->gesture_lifo.timestamp; |
| 58 | UpdateGestureSharedMemory(gesture, time_difference); | 77 | UpdateGestureSharedMemory(gesture, time_difference); |
| 59 | } | 78 | } |
| 60 | 79 | ||
| @@ -97,7 +116,7 @@ void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_dif | |||
| 97 | GestureType type = GestureType::Idle; | 116 | GestureType type = GestureType::Idle; |
| 98 | GestureAttribute attributes{}; | 117 | GestureAttribute attributes{}; |
| 99 | 118 | ||
| 100 | const auto& last_entry = shared_memory.gesture_lifo.ReadCurrentEntry().state; | 119 | const auto& last_entry = shared_memory->gesture_lifo.ReadCurrentEntry().state; |
| 101 | 120 | ||
| 102 | // Reset next state to default | 121 | // Reset next state to default |
| 103 | next_state.sampling_number = last_entry.sampling_number + 1; | 122 | next_state.sampling_number = last_entry.sampling_number + 1; |
| @@ -127,7 +146,7 @@ void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_dif | |||
| 127 | next_state.points = gesture.points; | 146 | next_state.points = gesture.points; |
| 128 | last_gesture = gesture; | 147 | last_gesture = gesture; |
| 129 | 148 | ||
| 130 | shared_memory.gesture_lifo.WriteNextEntry(next_state); | 149 | shared_memory->gesture_lifo.WriteNextEntry(next_state); |
| 131 | } | 150 | } |
| 132 | 151 | ||
| 133 | void Gesture::NewGesture(GestureProperties& gesture, GestureType& type, | 152 | void Gesture::NewGesture(GestureProperties& gesture, GestureType& type, |
| @@ -300,7 +319,7 @@ void Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_ | |||
| 300 | } | 319 | } |
| 301 | 320 | ||
| 302 | const GestureState& Gesture::GetLastGestureEntry() const { | 321 | const GestureState& Gesture::GetLastGestureEntry() const { |
| 303 | return shared_memory.gesture_lifo.ReadCurrentEntry().state; | 322 | return shared_memory->gesture_lifo.ReadCurrentEntry().state; |
| 304 | } | 323 | } |
| 305 | 324 | ||
| 306 | GestureProperties Gesture::GetGestureProperties() { | 325 | 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..1397379f3 --- /dev/null +++ b/src/core/hle/service/hid/controllers/home_button.cpp | |||
| @@ -0,0 +1,39 @@ | |||
| 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 | std::scoped_lock shared_lock{*shared_mutex}; | ||
| 25 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 26 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 27 | |||
| 28 | if (data == nullptr || !data->flag.is_assigned) { | ||
| 29 | return; | ||
| 30 | } | ||
| 31 | |||
| 32 | auto& header = data->shared_memory_format->home_button.header; | ||
| 33 | header.timestamp = core_timing.GetGlobalTimeNs().count(); | ||
| 34 | header.total_entry_count = 17; | ||
| 35 | header.entry_count = 0; | ||
| 36 | header.last_entry_index = 0; | ||
| 37 | } | ||
| 38 | |||
| 39 | } // 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..c069bcbb2 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,16 @@ 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 | std::scoped_lock shared_lock{*shared_mutex}; | ||
| 26 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 27 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 28 | |||
| 29 | if (data == nullptr || !data->flag.is_assigned) { | ||
| 30 | return; | ||
| 31 | } | ||
| 32 | |||
| 33 | KeyboardSharedMemoryFormat& shared_memory = data->shared_memory_format->keyboard; | ||
| 34 | |||
| 26 | if (!IsControllerActivated()) { | 35 | if (!IsControllerActivated()) { |
| 27 | shared_memory.keyboard_lifo.buffer_count = 0; | 36 | shared_memory.keyboard_lifo.buffer_count = 0; |
| 28 | shared_memory.keyboard_lifo.buffer_tail = 0; | 37 | 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..3a8d1751b 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,16 @@ 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 | std::scoped_lock shared_lock{*shared_mutex}; | ||
| 25 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 26 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 27 | |||
| 28 | if (data == nullptr || !data->flag.is_assigned) { | ||
| 29 | return; | ||
| 30 | } | ||
| 31 | |||
| 32 | MouseSharedMemoryFormat& shared_memory = data->shared_memory_format->mouse; | ||
| 33 | |||
| 24 | if (!IsControllerActivated()) { | 34 | if (!IsControllerActivated()) { |
| 25 | shared_memory.mouse_lifo.buffer_count = 0; | 35 | shared_memory.mouse_lifo.buffer_count = 0; |
| 26 | shared_memory.mouse_lifo.buffer_tail = 0; | 36 | 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..17cd0d7a0 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -16,46 +16,102 @@ | |||
| 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" |
| 24 | 25 | ||
| 25 | namespace Service::HID { | 26 | namespace Service::HID { |
| 26 | constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{ | 27 | |
| 27 | Core::HID::NpadIdType::Player1, Core::HID::NpadIdType::Player2, Core::HID::NpadIdType::Player3, | 28 | NPad::NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_) |
| 28 | Core::HID::NpadIdType::Player4, Core::HID::NpadIdType::Player5, Core::HID::NpadIdType::Player6, | 29 | : hid_core{hid_core_}, service_context{service_context_}, npad_resource{service_context} { |
| 29 | Core::HID::NpadIdType::Player7, Core::HID::NpadIdType::Player8, Core::HID::NpadIdType::Other, | 30 | for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; ++aruid_index) { |
| 30 | Core::HID::NpadIdType::Handheld, | 31 | for (std::size_t i = 0; i < controller_data[aruid_index].size(); ++i) { |
| 31 | }; | 32 | auto& controller = controller_data[aruid_index][i]; |
| 32 | 33 | controller.device = hid_core.GetEmulatedControllerByIndex(i); | |
| 33 | NPad::NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format, | 34 | controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = |
| 34 | KernelHelpers::ServiceContext& service_context_) | 35 | Core::HID::DEFAULT_VIBRATION_VALUE; |
| 35 | : ControllerBase{hid_core_}, service_context{service_context_} { | 36 | controller.vibration[Core::HID::EmulatedDeviceIndex::RightIndex] |
| 36 | for (std::size_t i = 0; i < controller_data.size(); ++i) { | 37 | .latest_vibration_value = Core::HID::DEFAULT_VIBRATION_VALUE; |
| 37 | auto& controller = controller_data[i]; | 38 | Core::HID::ControllerUpdateCallback engine_callback{ |
| 38 | controller.shared_memory = &npad_shared_memory_format.npad_entry[i].internal_state; | 39 | .on_change = |
| 39 | controller.device = hid_core.GetEmulatedControllerByIndex(i); | 40 | [this, i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }, |
| 40 | controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = | 41 | .is_npad_service = true, |
| 41 | Core::HID::DEFAULT_VIBRATION_VALUE; | 42 | }; |
| 42 | controller.vibration[Core::HID::EmulatedDeviceIndex::RightIndex].latest_vibration_value = | 43 | controller.callback_key = controller.device->SetCallback(engine_callback); |
| 43 | Core::HID::DEFAULT_VIBRATION_VALUE; | 44 | } |
| 44 | Core::HID::ControllerUpdateCallback engine_callback{ | ||
| 45 | .on_change = [this, | ||
| 46 | i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }, | ||
| 47 | .is_npad_service = true, | ||
| 48 | }; | ||
| 49 | controller.callback_key = controller.device->SetCallback(engine_callback); | ||
| 50 | } | 45 | } |
| 51 | } | 46 | } |
| 52 | 47 | ||
| 53 | NPad::~NPad() { | 48 | NPad::~NPad() { |
| 54 | for (std::size_t i = 0; i < controller_data.size(); ++i) { | 49 | for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; ++aruid_index) { |
| 55 | auto& controller = controller_data[i]; | 50 | for (std::size_t i = 0; i < controller_data[aruid_index].size(); ++i) { |
| 56 | controller.device->DeleteCallback(controller.callback_key); | 51 | auto& controller = controller_data[aruid_index][i]; |
| 52 | controller.device->DeleteCallback(controller.callback_key); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | Result NPad::Activate() { | ||
| 58 | if (ref_counter == std::numeric_limits<s32>::max() - 1) { | ||
| 59 | return ResultNpadResourceOverflow; | ||
| 60 | } | ||
| 61 | |||
| 62 | if (ref_counter == 0) { | ||
| 63 | std::scoped_lock lock{mutex}; | ||
| 64 | |||
| 65 | // TODO: Activate handlers and AbstractedPad | ||
| 57 | } | 66 | } |
| 58 | OnRelease(); | 67 | |
| 68 | ref_counter++; | ||
| 69 | return ResultSuccess; | ||
| 70 | } | ||
| 71 | |||
| 72 | Result NPad::Activate(u64 aruid) { | ||
| 73 | std::scoped_lock lock{mutex}; | ||
| 74 | std::scoped_lock shared_lock{*applet_resource_holder.shared_mutex}; | ||
| 75 | |||
| 76 | auto* data = applet_resource_holder.applet_resource->GetAruidData(aruid); | ||
| 77 | const auto aruid_index = applet_resource_holder.applet_resource->GetIndexFromAruid(aruid); | ||
| 78 | |||
| 79 | if (data == nullptr || !data->flag.is_assigned) { | ||
| 80 | return ResultSuccess; | ||
| 81 | } | ||
| 82 | |||
| 83 | for (std::size_t i = 0; i < controller_data[aruid_index].size(); ++i) { | ||
| 84 | auto& controller = controller_data[aruid_index][i]; | ||
| 85 | controller.shared_memory = &data->shared_memory_format->npad.npad_entry[i].internal_state; | ||
| 86 | } | ||
| 87 | |||
| 88 | // Prefill controller buffers | ||
| 89 | for (auto& controller : controller_data[aruid_index]) { | ||
| 90 | auto* npad = controller.shared_memory; | ||
| 91 | npad->fullkey_color = { | ||
| 92 | .attribute = ColorAttribute::NoController, | ||
| 93 | .fullkey = {}, | ||
| 94 | }; | ||
| 95 | npad->joycon_color = { | ||
| 96 | .attribute = ColorAttribute::NoController, | ||
| 97 | .left = {}, | ||
| 98 | .right = {}, | ||
| 99 | }; | ||
| 100 | // HW seems to initialize the first 19 entries | ||
| 101 | for (std::size_t i = 0; i < 19; ++i) { | ||
| 102 | WriteEmptyEntry(npad); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | return ResultSuccess; | ||
| 107 | } | ||
| 108 | |||
| 109 | Result NPad::ActivateNpadResource() { | ||
| 110 | return npad_resource.Activate(); | ||
| 111 | } | ||
| 112 | |||
| 113 | Result NPad::ActivateNpadResource(u64 aruid) { | ||
| 114 | return npad_resource.Activate(aruid); | ||
| 59 | } | 115 | } |
| 60 | 116 | ||
| 61 | void NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx) { | 117 | void NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx) { |
| @@ -64,41 +120,50 @@ void NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t c | |||
| 64 | ControllerUpdate(Core::HID::ControllerTriggerType::Battery, controller_idx); | 120 | ControllerUpdate(Core::HID::ControllerTriggerType::Battery, controller_idx); |
| 65 | return; | 121 | return; |
| 66 | } | 122 | } |
| 67 | if (controller_idx >= controller_data.size()) { | ||
| 68 | return; | ||
| 69 | } | ||
| 70 | 123 | ||
| 71 | auto& controller = controller_data[controller_idx]; | 124 | for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { |
| 72 | const auto is_connected = controller.device->IsConnected(); | 125 | if (controller_idx >= controller_data[aruid_index].size()) { |
| 73 | const auto npad_type = controller.device->GetNpadStyleIndex(); | ||
| 74 | const auto npad_id = controller.device->GetNpadIdType(); | ||
| 75 | switch (type) { | ||
| 76 | case Core::HID::ControllerTriggerType::Connected: | ||
| 77 | case Core::HID::ControllerTriggerType::Disconnected: | ||
| 78 | if (is_connected == controller.is_connected) { | ||
| 79 | return; | 126 | return; |
| 80 | } | 127 | } |
| 81 | UpdateControllerAt(npad_type, npad_id, is_connected); | 128 | |
| 82 | break; | 129 | auto* data = applet_resource_holder.applet_resource->GetAruidDataByIndex(aruid_index); |
| 83 | case Core::HID::ControllerTriggerType::Battery: { | 130 | |
| 84 | if (!controller.device->IsConnected()) { | 131 | if (!data->flag.is_assigned) { |
| 85 | return; | 132 | continue; |
| 133 | } | ||
| 134 | |||
| 135 | auto& controller = controller_data[aruid_index][controller_idx]; | ||
| 136 | const auto is_connected = controller.device->IsConnected(); | ||
| 137 | const auto npad_type = controller.device->GetNpadStyleIndex(); | ||
| 138 | const auto npad_id = controller.device->GetNpadIdType(); | ||
| 139 | switch (type) { | ||
| 140 | case Core::HID::ControllerTriggerType::Connected: | ||
| 141 | case Core::HID::ControllerTriggerType::Disconnected: | ||
| 142 | if (is_connected == controller.is_connected) { | ||
| 143 | return; | ||
| 144 | } | ||
| 145 | UpdateControllerAt(data->aruid, npad_type, npad_id, is_connected); | ||
| 146 | break; | ||
| 147 | case Core::HID::ControllerTriggerType::Battery: { | ||
| 148 | if (!controller.device->IsConnected()) { | ||
| 149 | return; | ||
| 150 | } | ||
| 151 | auto* shared_memory = controller.shared_memory; | ||
| 152 | const auto& battery_level = controller.device->GetBattery(); | ||
| 153 | shared_memory->battery_level_dual = battery_level.dual.battery_level; | ||
| 154 | shared_memory->battery_level_left = battery_level.left.battery_level; | ||
| 155 | shared_memory->battery_level_right = battery_level.right.battery_level; | ||
| 156 | break; | ||
| 157 | } | ||
| 158 | default: | ||
| 159 | break; | ||
| 86 | } | 160 | } |
| 87 | auto* shared_memory = controller.shared_memory; | ||
| 88 | const auto& battery_level = controller.device->GetBattery(); | ||
| 89 | shared_memory->battery_level_dual = battery_level.dual.battery_level; | ||
| 90 | shared_memory->battery_level_left = battery_level.left.battery_level; | ||
| 91 | shared_memory->battery_level_right = battery_level.right.battery_level; | ||
| 92 | break; | ||
| 93 | } | ||
| 94 | default: | ||
| 95 | break; | ||
| 96 | } | 161 | } |
| 97 | } | 162 | } |
| 98 | 163 | ||
| 99 | void NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { | 164 | void NPad::InitNewlyAddedController(u64 aruid, Core::HID::NpadIdType npad_id) { |
| 100 | auto& controller = GetControllerFromNpadIdType(npad_id); | 165 | auto& controller = GetControllerFromNpadIdType(aruid, npad_id); |
| 101 | if (!IsControllerSupported(controller.device->GetNpadStyleIndex())) { | 166 | if (!npad_resource.IsControllerSupported(aruid, controller.device->GetNpadStyleIndex())) { |
| 102 | return; | 167 | return; |
| 103 | } | 168 | } |
| 104 | LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); | 169 | LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); |
| @@ -107,7 +172,7 @@ void NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { | |||
| 107 | const auto& battery_level = controller.device->GetBattery(); | 172 | const auto& battery_level = controller.device->GetBattery(); |
| 108 | auto* shared_memory = controller.shared_memory; | 173 | auto* shared_memory = controller.shared_memory; |
| 109 | if (controller_type == Core::HID::NpadStyleIndex::None) { | 174 | if (controller_type == Core::HID::NpadStyleIndex::None) { |
| 110 | controller.styleset_changed_event->Signal(); | 175 | npad_resource.SignalStyleSetUpdateEvent(aruid, npad_id); |
| 111 | return; | 176 | return; |
| 112 | } | 177 | } |
| 113 | 178 | ||
| @@ -291,45 +356,11 @@ void NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { | |||
| 291 | Common::Input::PollingMode::Active); | 356 | Common::Input::PollingMode::Active); |
| 292 | } | 357 | } |
| 293 | 358 | ||
| 294 | SignalStyleSetChangedEvent(npad_id); | 359 | npad_resource.SignalStyleSetUpdateEvent(aruid, npad_id); |
| 295 | WriteEmptyEntry(controller.shared_memory); | 360 | WriteEmptyEntry(controller.shared_memory); |
| 296 | hid_core.SetLastActiveController(npad_id); | 361 | hid_core.SetLastActiveController(npad_id); |
| 297 | } | 362 | } |
| 298 | 363 | ||
| 299 | void NPad::OnInit() { | ||
| 300 | if (!IsControllerActivated()) { | ||
| 301 | return; | ||
| 302 | } | ||
| 303 | |||
| 304 | for (std::size_t i = 0; i < controller_data.size(); ++i) { | ||
| 305 | auto& controller = controller_data[i]; | ||
| 306 | controller.styleset_changed_event = | ||
| 307 | service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i)); | ||
| 308 | } | ||
| 309 | |||
| 310 | supported_npad_id_types.resize(npad_id_list.size()); | ||
| 311 | std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), | ||
| 312 | npad_id_list.size() * sizeof(Core::HID::NpadIdType)); | ||
| 313 | |||
| 314 | // Prefill controller buffers | ||
| 315 | for (auto& controller : controller_data) { | ||
| 316 | auto* npad = controller.shared_memory; | ||
| 317 | npad->fullkey_color = { | ||
| 318 | .attribute = ColorAttribute::NoController, | ||
| 319 | .fullkey = {}, | ||
| 320 | }; | ||
| 321 | npad->joycon_color = { | ||
| 322 | .attribute = ColorAttribute::NoController, | ||
| 323 | .left = {}, | ||
| 324 | .right = {}, | ||
| 325 | }; | ||
| 326 | // HW seems to initialize the first 19 entries | ||
| 327 | for (std::size_t i = 0; i < 19; ++i) { | ||
| 328 | WriteEmptyEntry(npad); | ||
| 329 | } | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 333 | void NPad::WriteEmptyEntry(NpadInternalState* npad) { | 364 | void NPad::WriteEmptyEntry(NpadInternalState* npad) { |
| 334 | NPadGenericState dummy_pad_state{}; | 365 | NPadGenericState dummy_pad_state{}; |
| 335 | NpadGcTriggerState dummy_gc_state{}; | 366 | NpadGcTriggerState dummy_gc_state{}; |
| @@ -351,31 +382,20 @@ void NPad::WriteEmptyEntry(NpadInternalState* npad) { | |||
| 351 | npad->gc_trigger_lifo.WriteNextEntry(dummy_gc_state); | 382 | npad->gc_trigger_lifo.WriteNextEntry(dummy_gc_state); |
| 352 | } | 383 | } |
| 353 | 384 | ||
| 354 | void NPad::OnRelease() { | 385 | void NPad::RequestPadStateUpdate(u64 aruid, Core::HID::NpadIdType npad_id) { |
| 355 | is_controller_initialized = false; | 386 | std::scoped_lock lock{*applet_resource_holder.shared_mutex}; |
| 356 | for (std::size_t i = 0; i < controller_data.size(); ++i) { | 387 | auto& controller = GetControllerFromNpadIdType(aruid, npad_id); |
| 357 | auto& controller = controller_data[i]; | ||
| 358 | service_context.CloseEvent(controller.styleset_changed_event); | ||
| 359 | for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { | ||
| 360 | VibrateControllerAtIndex(controller.device->GetNpadIdType(), device_idx, {}); | ||
| 361 | } | ||
| 362 | } | ||
| 363 | } | ||
| 364 | |||
| 365 | void NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { | ||
| 366 | std::scoped_lock lock{mutex}; | ||
| 367 | auto& controller = GetControllerFromNpadIdType(npad_id); | ||
| 368 | const auto controller_type = controller.device->GetNpadStyleIndex(); | 388 | const auto controller_type = controller.device->GetNpadStyleIndex(); |
| 369 | 389 | ||
| 370 | if (!controller.device->IsConnected() && controller.is_connected) { | 390 | if (!controller.device->IsConnected() && controller.is_connected) { |
| 371 | DisconnectNpad(npad_id); | 391 | DisconnectNpad(aruid, npad_id); |
| 372 | return; | 392 | return; |
| 373 | } | 393 | } |
| 374 | if (!controller.device->IsConnected()) { | 394 | if (!controller.device->IsConnected()) { |
| 375 | return; | 395 | return; |
| 376 | } | 396 | } |
| 377 | if (controller.device->IsConnected() && !controller.is_connected) { | 397 | if (controller.device->IsConnected() && !controller.is_connected) { |
| 378 | InitNewlyAddedController(npad_id); | 398 | InitNewlyAddedController(aruid, npad_id); |
| 379 | } | 399 | } |
| 380 | 400 | ||
| 381 | // This function is unique to yuzu for the turbo buttons and motion to work properly | 401 | // This function is unique to yuzu for the turbo buttons and motion to work properly |
| @@ -432,222 +452,232 @@ void NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { | |||
| 432 | } | 452 | } |
| 433 | 453 | ||
| 434 | void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | 454 | void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { |
| 435 | if (!IsControllerActivated()) { | 455 | if (ref_counter == 0) { |
| 436 | return; | 456 | return; |
| 437 | } | 457 | } |
| 438 | 458 | ||
| 439 | for (std::size_t i = 0; i < controller_data.size(); ++i) { | 459 | std::scoped_lock lock{*applet_resource_holder.shared_mutex}; |
| 440 | auto& controller = controller_data[i]; | 460 | for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; ++aruid_index) { |
| 441 | auto* npad = controller.shared_memory; | 461 | const auto* data = applet_resource_holder.applet_resource->GetAruidDataByIndex(aruid_index); |
| 442 | 462 | const auto aruid = data->aruid; | |
| 443 | const auto& controller_type = controller.device->GetNpadStyleIndex(); | ||
| 444 | 463 | ||
| 445 | if (controller_type == Core::HID::NpadStyleIndex::None || | 464 | if (!data->flag.is_assigned) { |
| 446 | !controller.device->IsConnected()) { | ||
| 447 | continue; | 465 | continue; |
| 448 | } | 466 | } |
| 449 | 467 | ||
| 450 | RequestPadStateUpdate(controller.device->GetNpadIdType()); | 468 | for (std::size_t i = 0; i < controller_data[aruid_index].size(); ++i) { |
| 451 | auto& pad_state = controller.npad_pad_state; | 469 | auto& controller = controller_data[aruid_index][i]; |
| 452 | auto& libnx_state = controller.npad_libnx_state; | 470 | controller.shared_memory = |
| 453 | auto& trigger_state = controller.npad_trigger_state; | 471 | &data->shared_memory_format->npad.npad_entry[i].internal_state; |
| 454 | 472 | auto* npad = controller.shared_memory; | |
| 455 | // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate | 473 | |
| 456 | // any controllers. | 474 | const auto& controller_type = controller.device->GetNpadStyleIndex(); |
| 457 | libnx_state.connection_status.raw = 0; | 475 | |
| 458 | libnx_state.connection_status.is_connected.Assign(1); | 476 | if (controller_type == Core::HID::NpadStyleIndex::None || |
| 459 | switch (controller_type) { | 477 | !controller.device->IsConnected()) { |
| 460 | case Core::HID::NpadStyleIndex::None: | 478 | continue; |
| 461 | ASSERT(false); | 479 | } |
| 462 | break; | 480 | |
| 463 | case Core::HID::NpadStyleIndex::ProController: | 481 | RequestPadStateUpdate(aruid, controller.device->GetNpadIdType()); |
| 464 | case Core::HID::NpadStyleIndex::NES: | 482 | auto& pad_state = controller.npad_pad_state; |
| 465 | case Core::HID::NpadStyleIndex::SNES: | 483 | auto& libnx_state = controller.npad_libnx_state; |
| 466 | case Core::HID::NpadStyleIndex::N64: | 484 | auto& trigger_state = controller.npad_trigger_state; |
| 467 | case Core::HID::NpadStyleIndex::SegaGenesis: | 485 | |
| 468 | pad_state.connection_status.raw = 0; | 486 | // LibNX exclusively uses this section, so we always update it since LibNX doesn't |
| 469 | pad_state.connection_status.is_connected.Assign(1); | 487 | // activate any controllers. |
| 470 | pad_state.connection_status.is_wired.Assign(1); | 488 | libnx_state.connection_status.raw = 0; |
| 471 | 489 | libnx_state.connection_status.is_connected.Assign(1); | |
| 472 | libnx_state.connection_status.is_wired.Assign(1); | 490 | switch (controller_type) { |
| 473 | pad_state.sampling_number = | 491 | case Core::HID::NpadStyleIndex::None: |
| 474 | npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; | 492 | ASSERT(false); |
| 475 | npad->fullkey_lifo.WriteNextEntry(pad_state); | 493 | break; |
| 476 | break; | 494 | case Core::HID::NpadStyleIndex::ProController: |
| 477 | case Core::HID::NpadStyleIndex::Handheld: | 495 | case Core::HID::NpadStyleIndex::NES: |
| 478 | pad_state.connection_status.raw = 0; | 496 | case Core::HID::NpadStyleIndex::SNES: |
| 479 | pad_state.connection_status.is_connected.Assign(1); | 497 | case Core::HID::NpadStyleIndex::N64: |
| 480 | pad_state.connection_status.is_wired.Assign(1); | 498 | case Core::HID::NpadStyleIndex::SegaGenesis: |
| 481 | pad_state.connection_status.is_left_connected.Assign(1); | 499 | pad_state.connection_status.raw = 0; |
| 482 | pad_state.connection_status.is_right_connected.Assign(1); | 500 | pad_state.connection_status.is_connected.Assign(1); |
| 483 | pad_state.connection_status.is_left_wired.Assign(1); | 501 | pad_state.connection_status.is_wired.Assign(1); |
| 484 | pad_state.connection_status.is_right_wired.Assign(1); | 502 | |
| 485 | 503 | libnx_state.connection_status.is_wired.Assign(1); | |
| 486 | libnx_state.connection_status.is_wired.Assign(1); | 504 | pad_state.sampling_number = |
| 487 | libnx_state.connection_status.is_left_connected.Assign(1); | 505 | npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; |
| 488 | libnx_state.connection_status.is_right_connected.Assign(1); | 506 | npad->fullkey_lifo.WriteNextEntry(pad_state); |
| 489 | libnx_state.connection_status.is_left_wired.Assign(1); | 507 | break; |
| 490 | libnx_state.connection_status.is_right_wired.Assign(1); | 508 | case Core::HID::NpadStyleIndex::Handheld: |
| 491 | pad_state.sampling_number = | 509 | pad_state.connection_status.raw = 0; |
| 492 | npad->handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; | 510 | pad_state.connection_status.is_connected.Assign(1); |
| 493 | npad->handheld_lifo.WriteNextEntry(pad_state); | 511 | pad_state.connection_status.is_wired.Assign(1); |
| 494 | break; | ||
| 495 | case Core::HID::NpadStyleIndex::JoyconDual: | ||
| 496 | pad_state.connection_status.raw = 0; | ||
| 497 | pad_state.connection_status.is_connected.Assign(1); | ||
| 498 | if (controller.is_dual_left_connected) { | ||
| 499 | pad_state.connection_status.is_left_connected.Assign(1); | 512 | pad_state.connection_status.is_left_connected.Assign(1); |
| 513 | pad_state.connection_status.is_right_connected.Assign(1); | ||
| 514 | pad_state.connection_status.is_left_wired.Assign(1); | ||
| 515 | pad_state.connection_status.is_right_wired.Assign(1); | ||
| 516 | |||
| 517 | libnx_state.connection_status.is_wired.Assign(1); | ||
| 500 | libnx_state.connection_status.is_left_connected.Assign(1); | 518 | libnx_state.connection_status.is_left_connected.Assign(1); |
| 501 | } | 519 | libnx_state.connection_status.is_right_connected.Assign(1); |
| 502 | if (controller.is_dual_right_connected) { | 520 | libnx_state.connection_status.is_left_wired.Assign(1); |
| 521 | libnx_state.connection_status.is_right_wired.Assign(1); | ||
| 522 | pad_state.sampling_number = | ||
| 523 | npad->handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 524 | npad->handheld_lifo.WriteNextEntry(pad_state); | ||
| 525 | break; | ||
| 526 | case Core::HID::NpadStyleIndex::JoyconDual: | ||
| 527 | pad_state.connection_status.raw = 0; | ||
| 528 | pad_state.connection_status.is_connected.Assign(1); | ||
| 529 | if (controller.is_dual_left_connected) { | ||
| 530 | pad_state.connection_status.is_left_connected.Assign(1); | ||
| 531 | libnx_state.connection_status.is_left_connected.Assign(1); | ||
| 532 | } | ||
| 533 | if (controller.is_dual_right_connected) { | ||
| 534 | pad_state.connection_status.is_right_connected.Assign(1); | ||
| 535 | libnx_state.connection_status.is_right_connected.Assign(1); | ||
| 536 | } | ||
| 537 | |||
| 538 | pad_state.sampling_number = | ||
| 539 | npad->joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 540 | npad->joy_dual_lifo.WriteNextEntry(pad_state); | ||
| 541 | break; | ||
| 542 | case Core::HID::NpadStyleIndex::JoyconLeft: | ||
| 543 | pad_state.connection_status.raw = 0; | ||
| 544 | pad_state.connection_status.is_connected.Assign(1); | ||
| 545 | pad_state.connection_status.is_left_connected.Assign(1); | ||
| 546 | |||
| 547 | libnx_state.connection_status.is_left_connected.Assign(1); | ||
| 548 | pad_state.sampling_number = | ||
| 549 | npad->joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 550 | npad->joy_left_lifo.WriteNextEntry(pad_state); | ||
| 551 | break; | ||
| 552 | case Core::HID::NpadStyleIndex::JoyconRight: | ||
| 553 | pad_state.connection_status.raw = 0; | ||
| 554 | pad_state.connection_status.is_connected.Assign(1); | ||
| 503 | pad_state.connection_status.is_right_connected.Assign(1); | 555 | pad_state.connection_status.is_right_connected.Assign(1); |
| 556 | |||
| 504 | libnx_state.connection_status.is_right_connected.Assign(1); | 557 | libnx_state.connection_status.is_right_connected.Assign(1); |
| 558 | pad_state.sampling_number = | ||
| 559 | npad->joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 560 | npad->joy_right_lifo.WriteNextEntry(pad_state); | ||
| 561 | break; | ||
| 562 | case Core::HID::NpadStyleIndex::GameCube: | ||
| 563 | pad_state.connection_status.raw = 0; | ||
| 564 | pad_state.connection_status.is_connected.Assign(1); | ||
| 565 | pad_state.connection_status.is_wired.Assign(1); | ||
| 566 | |||
| 567 | libnx_state.connection_status.is_wired.Assign(1); | ||
| 568 | pad_state.sampling_number = | ||
| 569 | npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 570 | trigger_state.sampling_number = | ||
| 571 | npad->gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 572 | npad->fullkey_lifo.WriteNextEntry(pad_state); | ||
| 573 | npad->gc_trigger_lifo.WriteNextEntry(trigger_state); | ||
| 574 | break; | ||
| 575 | case Core::HID::NpadStyleIndex::Pokeball: | ||
| 576 | pad_state.connection_status.raw = 0; | ||
| 577 | pad_state.connection_status.is_connected.Assign(1); | ||
| 578 | pad_state.sampling_number = | ||
| 579 | npad->palma_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 580 | npad->palma_lifo.WriteNextEntry(pad_state); | ||
| 581 | break; | ||
| 582 | default: | ||
| 583 | break; | ||
| 505 | } | 584 | } |
| 506 | 585 | ||
| 507 | pad_state.sampling_number = | 586 | libnx_state.npad_buttons.raw = pad_state.npad_buttons.raw; |
| 508 | npad->joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1; | 587 | libnx_state.l_stick = pad_state.l_stick; |
| 509 | npad->joy_dual_lifo.WriteNextEntry(pad_state); | 588 | libnx_state.r_stick = pad_state.r_stick; |
| 510 | break; | 589 | npad->system_ext_lifo.WriteNextEntry(pad_state); |
| 511 | case Core::HID::NpadStyleIndex::JoyconLeft: | ||
| 512 | pad_state.connection_status.raw = 0; | ||
| 513 | pad_state.connection_status.is_connected.Assign(1); | ||
| 514 | pad_state.connection_status.is_left_connected.Assign(1); | ||
| 515 | |||
| 516 | libnx_state.connection_status.is_left_connected.Assign(1); | ||
| 517 | pad_state.sampling_number = | ||
| 518 | npad->joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 519 | npad->joy_left_lifo.WriteNextEntry(pad_state); | ||
| 520 | break; | ||
| 521 | case Core::HID::NpadStyleIndex::JoyconRight: | ||
| 522 | pad_state.connection_status.raw = 0; | ||
| 523 | pad_state.connection_status.is_connected.Assign(1); | ||
| 524 | pad_state.connection_status.is_right_connected.Assign(1); | ||
| 525 | |||
| 526 | libnx_state.connection_status.is_right_connected.Assign(1); | ||
| 527 | pad_state.sampling_number = | ||
| 528 | npad->joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 529 | npad->joy_right_lifo.WriteNextEntry(pad_state); | ||
| 530 | break; | ||
| 531 | case Core::HID::NpadStyleIndex::GameCube: | ||
| 532 | pad_state.connection_status.raw = 0; | ||
| 533 | pad_state.connection_status.is_connected.Assign(1); | ||
| 534 | pad_state.connection_status.is_wired.Assign(1); | ||
| 535 | |||
| 536 | libnx_state.connection_status.is_wired.Assign(1); | ||
| 537 | pad_state.sampling_number = | ||
| 538 | npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 539 | trigger_state.sampling_number = | ||
| 540 | npad->gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 541 | npad->fullkey_lifo.WriteNextEntry(pad_state); | ||
| 542 | npad->gc_trigger_lifo.WriteNextEntry(trigger_state); | ||
| 543 | break; | ||
| 544 | case Core::HID::NpadStyleIndex::Pokeball: | ||
| 545 | pad_state.connection_status.raw = 0; | ||
| 546 | pad_state.connection_status.is_connected.Assign(1); | ||
| 547 | pad_state.sampling_number = | ||
| 548 | npad->palma_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 549 | npad->palma_lifo.WriteNextEntry(pad_state); | ||
| 550 | break; | ||
| 551 | default: | ||
| 552 | break; | ||
| 553 | } | ||
| 554 | 590 | ||
| 555 | libnx_state.npad_buttons.raw = pad_state.npad_buttons.raw; | 591 | press_state |= static_cast<u64>(pad_state.npad_buttons.raw); |
| 556 | libnx_state.l_stick = pad_state.l_stick; | 592 | } |
| 557 | libnx_state.r_stick = pad_state.r_stick; | ||
| 558 | npad->system_ext_lifo.WriteNextEntry(pad_state); | ||
| 559 | |||
| 560 | press_state |= static_cast<u64>(pad_state.npad_buttons.raw); | ||
| 561 | } | 593 | } |
| 562 | } | 594 | } |
| 563 | 595 | ||
| 564 | void NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) { | 596 | Result NPad::SetSupportedNpadStyleSet(u64 aruid, Core::HID::NpadStyleSet supported_style_set) { |
| 565 | hid_core.SetSupportedStyleTag(style_set); | 597 | std::scoped_lock lock{mutex}; |
| 566 | 598 | hid_core.SetSupportedStyleTag({supported_style_set}); | |
| 567 | if (is_controller_initialized) { | 599 | const Result result = npad_resource.SetSupportedNpadStyleSet(aruid, supported_style_set); |
| 568 | return; | 600 | if (result.IsSuccess()) { |
| 601 | OnUpdate({}); | ||
| 569 | } | 602 | } |
| 570 | 603 | return result; | |
| 571 | // Once SetSupportedStyleSet is called controllers are fully initialized | ||
| 572 | is_controller_initialized = true; | ||
| 573 | } | 604 | } |
| 574 | 605 | ||
| 575 | Core::HID::NpadStyleTag NPad::GetSupportedStyleSet() const { | 606 | Result NPad::GetSupportedNpadStyleSet(u64 aruid, |
| 576 | if (!is_controller_initialized) { | 607 | Core::HID::NpadStyleSet& out_supported_style_set) const { |
| 577 | return {Core::HID::NpadStyleSet::None}; | 608 | std::scoped_lock lock{mutex}; |
| 609 | const Result result = npad_resource.GetSupportedNpadStyleSet(out_supported_style_set, aruid); | ||
| 610 | |||
| 611 | if (result == ResultUndefinedStyleset) { | ||
| 612 | out_supported_style_set = Core::HID::NpadStyleSet::None; | ||
| 613 | return ResultSuccess; | ||
| 578 | } | 614 | } |
| 579 | return hid_core.GetSupportedStyleTag(); | 615 | |
| 616 | return result; | ||
| 580 | } | 617 | } |
| 581 | 618 | ||
| 582 | Result NPad::SetSupportedNpadIdTypes(std::span<const u8> data) { | 619 | Result NPad::GetMaskedSupportedNpadStyleSet( |
| 583 | constexpr std::size_t max_number_npad_ids = 0xa; | 620 | u64 aruid, Core::HID::NpadStyleSet& out_supported_style_set) const { |
| 584 | const auto length = data.size(); | 621 | std::scoped_lock lock{mutex}; |
| 585 | ASSERT(length > 0 && (length % sizeof(u32)) == 0); | 622 | const Result result = |
| 586 | const std::size_t elements = length / sizeof(u32); | 623 | npad_resource.GetMaskedSupportedNpadStyleSet(out_supported_style_set, aruid); |
| 587 | 624 | ||
| 588 | if (elements > max_number_npad_ids) { | 625 | if (result == ResultUndefinedStyleset) { |
| 589 | return InvalidArraySize; | 626 | out_supported_style_set = Core::HID::NpadStyleSet::None; |
| 627 | return ResultSuccess; | ||
| 590 | } | 628 | } |
| 591 | 629 | ||
| 592 | supported_npad_id_types.clear(); | 630 | return result; |
| 593 | supported_npad_id_types.resize(elements); | ||
| 594 | std::memcpy(supported_npad_id_types.data(), data.data(), length); | ||
| 595 | return ResultSuccess; | ||
| 596 | } | 631 | } |
| 597 | 632 | ||
| 598 | void NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) { | 633 | Result NPad::SetSupportedNpadIdType(u64 aruid, |
| 599 | const auto copy_amount = supported_npad_id_types.size() * sizeof(u32); | 634 | std::span<const Core::HID::NpadIdType> supported_npad_list) { |
| 600 | ASSERT(max_length <= copy_amount); | 635 | std::scoped_lock lock{mutex}; |
| 601 | std::memcpy(data, supported_npad_id_types.data(), copy_amount); | 636 | if (supported_npad_list.size() > MaxSupportedNpadIdTypes) { |
| 602 | } | 637 | return ResultInvalidArraySize; |
| 638 | } | ||
| 603 | 639 | ||
| 604 | std::size_t NPad::GetSupportedNpadIdTypesSize() const { | 640 | Result result = npad_resource.SetSupportedNpadIdType(aruid, supported_npad_list); |
| 605 | return supported_npad_id_types.size(); | ||
| 606 | } | ||
| 607 | 641 | ||
| 608 | void NPad::SetHoldType(NpadJoyHoldType joy_hold_type) { | 642 | if (result.IsSuccess()) { |
| 609 | if (joy_hold_type != NpadJoyHoldType::Horizontal && | 643 | OnUpdate({}); |
| 610 | joy_hold_type != NpadJoyHoldType::Vertical) { | ||
| 611 | LOG_ERROR(Service_HID, "Npad joy hold type needs to be valid, joy_hold_type={}", | ||
| 612 | joy_hold_type); | ||
| 613 | return; | ||
| 614 | } | 644 | } |
| 615 | hold_type = joy_hold_type; | ||
| 616 | } | ||
| 617 | 645 | ||
| 618 | NpadJoyHoldType NPad::GetHoldType() const { | 646 | return result; |
| 619 | return hold_type; | ||
| 620 | } | 647 | } |
| 621 | 648 | ||
| 622 | void NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) { | 649 | Result NPad::SetNpadJoyHoldType(u64 aruid, NpadJoyHoldType hold_type) { |
| 623 | if (activation_mode >= NpadHandheldActivationMode::MaxActivationMode) { | 650 | std::scoped_lock lock{mutex}; |
| 624 | ASSERT_MSG(false, "Activation mode should be always None, Single or Dual"); | 651 | return npad_resource.SetNpadJoyHoldType(aruid, hold_type); |
| 625 | return; | ||
| 626 | } | ||
| 627 | |||
| 628 | handheld_activation_mode = activation_mode; | ||
| 629 | } | 652 | } |
| 630 | 653 | ||
| 631 | NpadHandheldActivationMode NPad::GetNpadHandheldActivationMode() const { | 654 | Result NPad::GetNpadJoyHoldType(u64 aruid, NpadJoyHoldType& out_hold_type) const { |
| 632 | return handheld_activation_mode; | 655 | std::scoped_lock lock{mutex}; |
| 656 | return npad_resource.GetNpadJoyHoldType(out_hold_type, aruid); | ||
| 633 | } | 657 | } |
| 634 | 658 | ||
| 635 | void NPad::SetNpadCommunicationMode(NpadCommunicationMode communication_mode_) { | 659 | Result NPad::SetNpadHandheldActivationMode(u64 aruid, NpadHandheldActivationMode mode) { |
| 636 | communication_mode = communication_mode_; | 660 | std::scoped_lock lock{mutex}; |
| 661 | Result result = npad_resource.SetNpadHandheldActivationMode(aruid, mode); | ||
| 662 | if (result.IsSuccess()) { | ||
| 663 | OnUpdate({}); | ||
| 664 | } | ||
| 665 | return result; | ||
| 637 | } | 666 | } |
| 638 | 667 | ||
| 639 | NpadCommunicationMode NPad::GetNpadCommunicationMode() const { | 668 | Result NPad::GetNpadHandheldActivationMode(u64 aruid, NpadHandheldActivationMode& out_mode) const { |
| 640 | return communication_mode; | 669 | std::scoped_lock lock{mutex}; |
| 670 | return npad_resource.GetNpadHandheldActivationMode(out_mode, aruid); | ||
| 641 | } | 671 | } |
| 642 | 672 | ||
| 643 | bool NPad::SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id, | 673 | bool NPad::SetNpadMode(u64 aruid, Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id, |
| 644 | NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode) { | 674 | NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode) { |
| 645 | if (!IsNpadIdValid(npad_id)) { | 675 | if (!IsNpadIdValid(npad_id)) { |
| 646 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | 676 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); |
| 647 | return false; | 677 | return false; |
| 648 | } | 678 | } |
| 649 | 679 | ||
| 650 | auto& controller = GetControllerFromNpadIdType(npad_id); | 680 | auto& controller = GetControllerFromNpadIdType(aruid, npad_id); |
| 651 | if (controller.shared_memory->assignment_mode != assignment_mode) { | 681 | if (controller.shared_memory->assignment_mode != assignment_mode) { |
| 652 | controller.shared_memory->assignment_mode = assignment_mode; | 682 | controller.shared_memory->assignment_mode = assignment_mode; |
| 653 | } | 683 | } |
| @@ -658,17 +688,17 @@ bool NPad::SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType | |||
| 658 | 688 | ||
| 659 | if (assignment_mode == NpadJoyAssignmentMode::Dual) { | 689 | if (assignment_mode == NpadJoyAssignmentMode::Dual) { |
| 660 | if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft) { | 690 | if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft) { |
| 661 | DisconnectNpad(npad_id); | 691 | DisconnectNpad(aruid, npad_id); |
| 662 | controller.is_dual_left_connected = true; | 692 | controller.is_dual_left_connected = true; |
| 663 | controller.is_dual_right_connected = false; | 693 | controller.is_dual_right_connected = false; |
| 664 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); | 694 | UpdateControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); |
| 665 | return false; | 695 | return false; |
| 666 | } | 696 | } |
| 667 | if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) { | 697 | if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) { |
| 668 | DisconnectNpad(npad_id); | 698 | DisconnectNpad(aruid, npad_id); |
| 669 | controller.is_dual_left_connected = false; | 699 | controller.is_dual_left_connected = false; |
| 670 | controller.is_dual_right_connected = true; | 700 | controller.is_dual_right_connected = true; |
| 671 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); | 701 | UpdateControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); |
| 672 | return false; | 702 | return false; |
| 673 | } | 703 | } |
| 674 | return false; | 704 | return false; |
| @@ -682,37 +712,38 @@ bool NPad::SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType | |||
| 682 | } | 712 | } |
| 683 | 713 | ||
| 684 | if (controller.is_dual_left_connected && !controller.is_dual_right_connected) { | 714 | if (controller.is_dual_left_connected && !controller.is_dual_right_connected) { |
| 685 | DisconnectNpad(npad_id); | 715 | DisconnectNpad(aruid, npad_id); |
| 686 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); | 716 | UpdateControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); |
| 687 | return false; | 717 | return false; |
| 688 | } | 718 | } |
| 689 | if (!controller.is_dual_left_connected && controller.is_dual_right_connected) { | 719 | if (!controller.is_dual_left_connected && controller.is_dual_right_connected) { |
| 690 | DisconnectNpad(npad_id); | 720 | DisconnectNpad(aruid, npad_id); |
| 691 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); | 721 | UpdateControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); |
| 692 | return false; | 722 | return false; |
| 693 | } | 723 | } |
| 694 | 724 | ||
| 695 | // We have two controllers connected to the same npad_id we need to split them | 725 | // We have two controllers connected to the same npad_id we need to split them |
| 696 | new_npad_id = hid_core.GetFirstDisconnectedNpadId(); | 726 | new_npad_id = hid_core.GetFirstDisconnectedNpadId(); |
| 697 | auto& controller_2 = GetControllerFromNpadIdType(new_npad_id); | 727 | auto& controller_2 = GetControllerFromNpadIdType(aruid, new_npad_id); |
| 698 | DisconnectNpad(npad_id); | 728 | DisconnectNpad(aruid, npad_id); |
| 699 | if (npad_device_type == NpadJoyDeviceType::Left) { | 729 | if (npad_device_type == NpadJoyDeviceType::Left) { |
| 700 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); | 730 | UpdateControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); |
| 701 | controller_2.is_dual_left_connected = false; | 731 | controller_2.is_dual_left_connected = false; |
| 702 | controller_2.is_dual_right_connected = true; | 732 | controller_2.is_dual_right_connected = true; |
| 703 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, new_npad_id, true); | 733 | UpdateControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconDual, new_npad_id, true); |
| 704 | } else { | 734 | } else { |
| 705 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); | 735 | UpdateControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); |
| 706 | controller_2.is_dual_left_connected = true; | 736 | controller_2.is_dual_left_connected = true; |
| 707 | controller_2.is_dual_right_connected = false; | 737 | controller_2.is_dual_right_connected = false; |
| 708 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, new_npad_id, true); | 738 | UpdateControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconDual, new_npad_id, true); |
| 709 | } | 739 | } |
| 710 | return true; | 740 | return true; |
| 711 | } | 741 | } |
| 712 | 742 | ||
| 713 | bool NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index, | 743 | bool NPad::VibrateControllerAtIndex(u64 aruid, Core::HID::NpadIdType npad_id, |
| 744 | std::size_t device_index, | ||
| 714 | const Core::HID::VibrationValue& vibration_value) { | 745 | const Core::HID::VibrationValue& vibration_value) { |
| 715 | auto& controller = GetControllerFromNpadIdType(npad_id); | 746 | auto& controller = GetControllerFromNpadIdType(aruid, npad_id); |
| 716 | if (!controller.device->IsConnected()) { | 747 | if (!controller.device->IsConnected()) { |
| 717 | return false; | 748 | return false; |
| 718 | } | 749 | } |
| @@ -755,7 +786,8 @@ bool NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t d | |||
| 755 | return controller.device->SetVibration(device_index, vibration); | 786 | return controller.device->SetVibration(device_index, vibration); |
| 756 | } | 787 | } |
| 757 | 788 | ||
| 758 | void NPad::VibrateController(const Core::HID::VibrationDeviceHandle& vibration_device_handle, | 789 | void NPad::VibrateController(u64 aruid, |
| 790 | const Core::HID::VibrationDeviceHandle& vibration_device_handle, | ||
| 759 | const Core::HID::VibrationValue& vibration_value) { | 791 | const Core::HID::VibrationValue& vibration_value) { |
| 760 | if (IsVibrationHandleValid(vibration_device_handle).IsError()) { | 792 | if (IsVibrationHandleValid(vibration_device_handle).IsError()) { |
| 761 | return; | 793 | return; |
| @@ -765,7 +797,7 @@ void NPad::VibrateController(const Core::HID::VibrationDeviceHandle& vibration_d | |||
| 765 | return; | 797 | return; |
| 766 | } | 798 | } |
| 767 | 799 | ||
| 768 | auto& controller = GetControllerFromHandle(vibration_device_handle); | 800 | auto& controller = GetControllerFromHandle(aruid, vibration_device_handle); |
| 769 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); | 801 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); |
| 770 | 802 | ||
| 771 | if (!controller.vibration[device_index].device_mounted || !controller.device->IsConnected()) { | 803 | if (!controller.vibration[device_index].device_mounted || !controller.device->IsConnected()) { |
| @@ -795,14 +827,14 @@ void NPad::VibrateController(const Core::HID::VibrationDeviceHandle& vibration_d | |||
| 795 | return; | 827 | return; |
| 796 | } | 828 | } |
| 797 | 829 | ||
| 798 | if (VibrateControllerAtIndex(controller.device->GetNpadIdType(), device_index, | 830 | if (VibrateControllerAtIndex(aruid, controller.device->GetNpadIdType(), device_index, |
| 799 | vibration_value)) { | 831 | vibration_value)) { |
| 800 | controller.vibration[device_index].latest_vibration_value = vibration_value; | 832 | controller.vibration[device_index].latest_vibration_value = vibration_value; |
| 801 | } | 833 | } |
| 802 | } | 834 | } |
| 803 | 835 | ||
| 804 | void NPad::VibrateControllers( | 836 | void NPad::VibrateControllers( |
| 805 | std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles, | 837 | u64 aruid, std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles, |
| 806 | std::span<const Core::HID::VibrationValue> vibration_values) { | 838 | std::span<const Core::HID::VibrationValue> vibration_values) { |
| 807 | if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { | 839 | if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { |
| 808 | return; | 840 | return; |
| @@ -814,17 +846,17 @@ void NPad::VibrateControllers( | |||
| 814 | "this is undefined behavior!"); | 846 | "this is undefined behavior!"); |
| 815 | 847 | ||
| 816 | for (std::size_t i = 0; i < vibration_device_handles.size(); ++i) { | 848 | for (std::size_t i = 0; i < vibration_device_handles.size(); ++i) { |
| 817 | VibrateController(vibration_device_handles[i], vibration_values[i]); | 849 | VibrateController(aruid, vibration_device_handles[i], vibration_values[i]); |
| 818 | } | 850 | } |
| 819 | } | 851 | } |
| 820 | 852 | ||
| 821 | Core::HID::VibrationValue NPad::GetLastVibration( | 853 | Core::HID::VibrationValue NPad::GetLastVibration( |
| 822 | const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { | 854 | u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { |
| 823 | if (IsVibrationHandleValid(vibration_device_handle).IsError()) { | 855 | if (IsVibrationHandleValid(vibration_device_handle).IsError()) { |
| 824 | return {}; | 856 | return {}; |
| 825 | } | 857 | } |
| 826 | 858 | ||
| 827 | const auto& controller = GetControllerFromHandle(vibration_device_handle); | 859 | const auto& controller = GetControllerFromHandle(aruid, vibration_device_handle); |
| 828 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); | 860 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); |
| 829 | return controller.vibration[device_index].latest_vibration_value; | 861 | return controller.vibration[device_index].latest_vibration_value; |
| 830 | } | 862 | } |
| @@ -835,14 +867,15 @@ void NPad::InitializeVibrationDevice( | |||
| 835 | return; | 867 | return; |
| 836 | } | 868 | } |
| 837 | 869 | ||
| 870 | const auto aruid = applet_resource_holder.applet_resource->GetActiveAruid(); | ||
| 838 | const auto npad_index = static_cast<Core::HID::NpadIdType>(vibration_device_handle.npad_id); | 871 | const auto npad_index = static_cast<Core::HID::NpadIdType>(vibration_device_handle.npad_id); |
| 839 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); | 872 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); |
| 840 | InitializeVibrationDeviceAtIndex(npad_index, device_index); | 873 | InitializeVibrationDeviceAtIndex(aruid, npad_index, device_index); |
| 841 | } | 874 | } |
| 842 | 875 | ||
| 843 | void NPad::InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, | 876 | void NPad::InitializeVibrationDeviceAtIndex(u64 aruid, Core::HID::NpadIdType npad_id, |
| 844 | std::size_t device_index) { | 877 | std::size_t device_index) { |
| 845 | auto& controller = GetControllerFromNpadIdType(npad_id); | 878 | auto& controller = GetControllerFromNpadIdType(aruid, npad_id); |
| 846 | if (!Settings::values.vibration_enabled.GetValue()) { | 879 | if (!Settings::values.vibration_enabled.GetValue()) { |
| 847 | controller.vibration[device_index].device_mounted = false; | 880 | controller.vibration[device_index].device_mounted = false; |
| 848 | return; | 881 | return; |
| @@ -857,60 +890,50 @@ void NPad::SetPermitVibrationSession(bool permit_vibration_session) { | |||
| 857 | } | 890 | } |
| 858 | 891 | ||
| 859 | bool NPad::IsVibrationDeviceMounted( | 892 | bool NPad::IsVibrationDeviceMounted( |
| 860 | const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { | 893 | u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { |
| 861 | if (IsVibrationHandleValid(vibration_device_handle).IsError()) { | 894 | if (IsVibrationHandleValid(vibration_device_handle).IsError()) { |
| 862 | return false; | 895 | return false; |
| 863 | } | 896 | } |
| 864 | 897 | ||
| 865 | const auto& controller = GetControllerFromHandle(vibration_device_handle); | 898 | const auto& controller = GetControllerFromHandle(aruid, vibration_device_handle); |
| 866 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); | 899 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); |
| 867 | return controller.vibration[device_index].device_mounted; | 900 | return controller.vibration[device_index].device_mounted; |
| 868 | } | 901 | } |
| 869 | 902 | ||
| 870 | Kernel::KReadableEvent& NPad::GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id) { | 903 | Result NPad::AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event, |
| 871 | if (!IsNpadIdValid(npad_id)) { | 904 | Core::HID::NpadIdType npad_id) { |
| 872 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | 905 | std::scoped_lock lock{mutex}; |
| 873 | // Fallback to player 1 | 906 | return npad_resource.AcquireNpadStyleSetUpdateEventHandle(aruid, out_event, npad_id); |
| 874 | const auto& controller = GetControllerFromNpadIdType(Core::HID::NpadIdType::Player1); | ||
| 875 | return controller.styleset_changed_event->GetReadableEvent(); | ||
| 876 | } | ||
| 877 | |||
| 878 | const auto& controller = GetControllerFromNpadIdType(npad_id); | ||
| 879 | return controller.styleset_changed_event->GetReadableEvent(); | ||
| 880 | } | ||
| 881 | |||
| 882 | void NPad::SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const { | ||
| 883 | const auto& controller = GetControllerFromNpadIdType(npad_id); | ||
| 884 | controller.styleset_changed_event->Signal(); | ||
| 885 | } | 907 | } |
| 886 | 908 | ||
| 887 | void NPad::AddNewControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id) { | 909 | void NPad::AddNewControllerAt(u64 aruid, Core::HID::NpadStyleIndex controller, |
| 888 | UpdateControllerAt(controller, npad_id, true); | 910 | Core::HID::NpadIdType npad_id) { |
| 911 | UpdateControllerAt(aruid, controller, npad_id, true); | ||
| 889 | } | 912 | } |
| 890 | 913 | ||
| 891 | void NPad::UpdateControllerAt(Core::HID::NpadStyleIndex type, Core::HID::NpadIdType npad_id, | 914 | void NPad::UpdateControllerAt(u64 aruid, Core::HID::NpadStyleIndex type, |
| 892 | bool connected) { | 915 | Core::HID::NpadIdType npad_id, bool connected) { |
| 893 | auto& controller = GetControllerFromNpadIdType(npad_id); | 916 | auto& controller = GetControllerFromNpadIdType(aruid, npad_id); |
| 894 | if (!connected) { | 917 | if (!connected) { |
| 895 | DisconnectNpad(npad_id); | 918 | DisconnectNpad(aruid, npad_id); |
| 896 | return; | 919 | return; |
| 897 | } | 920 | } |
| 898 | 921 | ||
| 899 | controller.device->SetNpadStyleIndex(type); | 922 | controller.device->SetNpadStyleIndex(type); |
| 900 | InitNewlyAddedController(npad_id); | 923 | InitNewlyAddedController(aruid, npad_id); |
| 901 | } | 924 | } |
| 902 | 925 | ||
| 903 | Result NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { | 926 | Result NPad::DisconnectNpad(u64 aruid, Core::HID::NpadIdType npad_id) { |
| 904 | if (!IsNpadIdValid(npad_id)) { | 927 | if (!IsNpadIdValid(npad_id)) { |
| 905 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | 928 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); |
| 906 | return InvalidNpadId; | 929 | return ResultInvalidNpadId; |
| 907 | } | 930 | } |
| 908 | 931 | ||
| 909 | LOG_DEBUG(Service_HID, "Npad disconnected {}", npad_id); | 932 | LOG_DEBUG(Service_HID, "Npad disconnected {}", npad_id); |
| 910 | auto& controller = GetControllerFromNpadIdType(npad_id); | 933 | auto& controller = GetControllerFromNpadIdType(aruid, npad_id); |
| 911 | for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { | 934 | for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { |
| 912 | // Send an empty vibration to stop any vibrations. | 935 | // Send an empty vibration to stop any vibrations. |
| 913 | VibrateControllerAtIndex(npad_id, device_idx, {}); | 936 | VibrateControllerAtIndex(aruid, npad_id, device_idx, {}); |
| 914 | controller.vibration[device_idx].device_mounted = false; | 937 | controller.vibration[device_idx].device_mounted = false; |
| 915 | } | 938 | } |
| 916 | 939 | ||
| @@ -944,71 +967,48 @@ Result NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { | |||
| 944 | controller.is_dual_right_connected = true; | 967 | controller.is_dual_right_connected = true; |
| 945 | controller.is_connected = false; | 968 | controller.is_connected = false; |
| 946 | controller.device->Disconnect(); | 969 | controller.device->Disconnect(); |
| 947 | SignalStyleSetChangedEvent(npad_id); | 970 | npad_resource.SignalStyleSetUpdateEvent(aruid, npad_id); |
| 948 | WriteEmptyEntry(shared_memory); | 971 | WriteEmptyEntry(shared_memory); |
| 949 | return ResultSuccess; | 972 | return ResultSuccess; |
| 950 | } | 973 | } |
| 951 | 974 | ||
| 952 | Result NPad::IsFirmwareUpdateAvailableForSixAxisSensor( | 975 | Result NPad::IsFirmwareUpdateAvailableForSixAxisSensor( |
| 953 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const { | 976 | u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 977 | bool& is_firmware_available) const { | ||
| 954 | const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); | 978 | const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); |
| 955 | if (is_valid.IsError()) { | 979 | if (is_valid.IsError()) { |
| 956 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); | 980 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); |
| 957 | return is_valid; | 981 | return is_valid; |
| 958 | } | 982 | } |
| 959 | 983 | ||
| 960 | const auto& sixaxis_properties = GetSixaxisProperties(sixaxis_handle); | 984 | const auto& sixaxis_properties = GetSixaxisProperties(aruid, sixaxis_handle); |
| 961 | is_firmware_available = sixaxis_properties.is_firmware_update_available != 0; | 985 | is_firmware_available = sixaxis_properties.is_firmware_update_available != 0; |
| 962 | return ResultSuccess; | 986 | return ResultSuccess; |
| 963 | } | 987 | } |
| 964 | 988 | ||
| 965 | Result NPad::ResetIsSixAxisSensorDeviceNewlyAssigned( | 989 | Result NPad::ResetIsSixAxisSensorDeviceNewlyAssigned( |
| 966 | const Core::HID::SixAxisSensorHandle& sixaxis_handle) { | 990 | u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) { |
| 967 | const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); | 991 | const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); |
| 968 | if (is_valid.IsError()) { | 992 | if (is_valid.IsError()) { |
| 969 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); | 993 | LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); |
| 970 | return is_valid; | 994 | return is_valid; |
| 971 | } | 995 | } |
| 972 | 996 | ||
| 973 | auto& sixaxis_properties = GetSixaxisProperties(sixaxis_handle); | 997 | auto& sixaxis_properties = GetSixaxisProperties(aruid, sixaxis_handle); |
| 974 | sixaxis_properties.is_newly_assigned.Assign(0); | 998 | sixaxis_properties.is_newly_assigned.Assign(0); |
| 975 | 999 | ||
| 976 | return ResultSuccess; | 1000 | return ResultSuccess; |
| 977 | } | 1001 | } |
| 978 | 1002 | ||
| 979 | NpadSixAxisSensorLifo& NPad::GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id) { | 1003 | Result NPad::MergeSingleJoyAsDualJoy(u64 aruid, Core::HID::NpadIdType npad_id_1, |
| 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, | ||
| 1004 | Core::HID::NpadIdType npad_id_2) { | 1004 | Core::HID::NpadIdType npad_id_2) { |
| 1005 | if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { | 1005 | if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { |
| 1006 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, | 1006 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, |
| 1007 | npad_id_2); | 1007 | npad_id_2); |
| 1008 | return InvalidNpadId; | 1008 | return ResultInvalidNpadId; |
| 1009 | } | 1009 | } |
| 1010 | auto& controller_1 = GetControllerFromNpadIdType(npad_id_1); | 1010 | auto& controller_1 = GetControllerFromNpadIdType(aruid, npad_id_1); |
| 1011 | auto& controller_2 = GetControllerFromNpadIdType(npad_id_2); | 1011 | auto& controller_2 = GetControllerFromNpadIdType(aruid, npad_id_2); |
| 1012 | auto controller_style_1 = controller_1.device->GetNpadStyleIndex(); | 1012 | auto controller_style_1 = controller_1.device->GetNpadStyleIndex(); |
| 1013 | auto controller_style_2 = controller_2.device->GetNpadStyleIndex(); | 1013 | auto controller_style_2 = controller_2.device->GetNpadStyleIndex(); |
| 1014 | 1014 | ||
| @@ -1055,51 +1055,62 @@ Result NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, | |||
| 1055 | } | 1055 | } |
| 1056 | 1056 | ||
| 1057 | // Disconnect the joycons and connect them as dual joycon at the first index. | 1057 | // Disconnect the joycons and connect them as dual joycon at the first index. |
| 1058 | DisconnectNpad(npad_id_1); | 1058 | DisconnectNpad(aruid, npad_id_1); |
| 1059 | DisconnectNpad(npad_id_2); | 1059 | DisconnectNpad(aruid, npad_id_2); |
| 1060 | controller_1.is_dual_left_connected = true; | 1060 | controller_1.is_dual_left_connected = true; |
| 1061 | controller_1.is_dual_right_connected = true; | 1061 | controller_1.is_dual_right_connected = true; |
| 1062 | AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_1); | 1062 | AddNewControllerAt(aruid, Core::HID::NpadStyleIndex::JoyconDual, npad_id_1); |
| 1063 | return ResultSuccess; | 1063 | return ResultSuccess; |
| 1064 | } | 1064 | } |
| 1065 | 1065 | ||
| 1066 | void NPad::StartLRAssignmentMode() { | 1066 | Result NPad::StartLrAssignmentMode(u64 aruid) { |
| 1067 | // Nothing internally is used for lr assignment mode. Since we have the ability to set the | 1067 | std::scoped_lock lock{mutex}; |
| 1068 | // controller types from boot, it doesn't really matter about showing a selection screen | 1068 | bool is_enabled{}; |
| 1069 | is_in_lr_assignment_mode = true; | 1069 | Result result = npad_resource.GetLrAssignmentMode(is_enabled, aruid); |
| 1070 | if (result.IsSuccess() && is_enabled == false) { | ||
| 1071 | result = npad_resource.SetLrAssignmentMode(aruid, true); | ||
| 1072 | } | ||
| 1073 | return result; | ||
| 1070 | } | 1074 | } |
| 1071 | 1075 | ||
| 1072 | void NPad::StopLRAssignmentMode() { | 1076 | Result NPad::StopLrAssignmentMode(u64 aruid) { |
| 1073 | is_in_lr_assignment_mode = false; | 1077 | std::scoped_lock lock{mutex}; |
| 1078 | bool is_enabled{}; | ||
| 1079 | Result result = npad_resource.GetLrAssignmentMode(is_enabled, aruid); | ||
| 1080 | if (result.IsSuccess() && is_enabled == true) { | ||
| 1081 | result = npad_resource.SetLrAssignmentMode(aruid, false); | ||
| 1082 | } | ||
| 1083 | return result; | ||
| 1074 | } | 1084 | } |
| 1075 | 1085 | ||
| 1076 | Result NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2) { | 1086 | Result NPad::SwapNpadAssignment(u64 aruid, Core::HID::NpadIdType npad_id_1, |
| 1087 | Core::HID::NpadIdType npad_id_2) { | ||
| 1077 | if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { | 1088 | if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { |
| 1078 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, | 1089 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, |
| 1079 | npad_id_2); | 1090 | npad_id_2); |
| 1080 | return InvalidNpadId; | 1091 | return ResultInvalidNpadId; |
| 1081 | } | 1092 | } |
| 1082 | if (npad_id_1 == Core::HID::NpadIdType::Handheld || | 1093 | if (npad_id_1 == Core::HID::NpadIdType::Handheld || |
| 1083 | npad_id_2 == Core::HID::NpadIdType::Handheld || npad_id_1 == Core::HID::NpadIdType::Other || | 1094 | npad_id_2 == Core::HID::NpadIdType::Handheld || npad_id_1 == Core::HID::NpadIdType::Other || |
| 1084 | npad_id_2 == Core::HID::NpadIdType::Other) { | 1095 | npad_id_2 == Core::HID::NpadIdType::Other) { |
| 1085 | return ResultSuccess; | 1096 | return ResultSuccess; |
| 1086 | } | 1097 | } |
| 1087 | const auto& controller_1 = GetControllerFromNpadIdType(npad_id_1).device; | 1098 | const auto& controller_1 = GetControllerFromNpadIdType(aruid, npad_id_1).device; |
| 1088 | const auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device; | 1099 | const auto& controller_2 = GetControllerFromNpadIdType(aruid, npad_id_2).device; |
| 1089 | const auto type_index_1 = controller_1->GetNpadStyleIndex(); | 1100 | const auto type_index_1 = controller_1->GetNpadStyleIndex(); |
| 1090 | const auto type_index_2 = controller_2->GetNpadStyleIndex(); | 1101 | const auto type_index_2 = controller_2->GetNpadStyleIndex(); |
| 1091 | const auto is_connected_1 = controller_1->IsConnected(); | 1102 | const auto is_connected_1 = controller_1->IsConnected(); |
| 1092 | const auto is_connected_2 = controller_2->IsConnected(); | 1103 | const auto is_connected_2 = controller_2->IsConnected(); |
| 1093 | 1104 | ||
| 1094 | if (!IsControllerSupported(type_index_1) && is_connected_1) { | 1105 | if (!npad_resource.IsControllerSupported(aruid, type_index_1) && is_connected_1) { |
| 1095 | return NpadNotConnected; | 1106 | return ResultNpadNotConnected; |
| 1096 | } | 1107 | } |
| 1097 | if (!IsControllerSupported(type_index_2) && is_connected_2) { | 1108 | if (!npad_resource.IsControllerSupported(aruid, type_index_2) && is_connected_2) { |
| 1098 | return NpadNotConnected; | 1109 | return ResultNpadNotConnected; |
| 1099 | } | 1110 | } |
| 1100 | 1111 | ||
| 1101 | UpdateControllerAt(type_index_2, npad_id_1, is_connected_2); | 1112 | UpdateControllerAt(aruid, type_index_2, npad_id_1, is_connected_2); |
| 1102 | UpdateControllerAt(type_index_1, npad_id_2, is_connected_1); | 1113 | UpdateControllerAt(aruid, type_index_1, npad_id_2, is_connected_1); |
| 1103 | 1114 | ||
| 1104 | return ResultSuccess; | 1115 | return ResultSuccess; |
| 1105 | } | 1116 | } |
| @@ -1107,68 +1118,68 @@ Result NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::Npad | |||
| 1107 | Result NPad::GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const { | 1118 | Result NPad::GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const { |
| 1108 | if (!IsNpadIdValid(npad_id)) { | 1119 | if (!IsNpadIdValid(npad_id)) { |
| 1109 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | 1120 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); |
| 1110 | return InvalidNpadId; | 1121 | return ResultInvalidNpadId; |
| 1111 | } | 1122 | } |
| 1112 | const auto& controller = GetControllerFromNpadIdType(npad_id).device; | 1123 | const auto aruid = applet_resource_holder.applet_resource->GetActiveAruid(); |
| 1124 | const auto& controller = GetControllerFromNpadIdType(aruid, npad_id).device; | ||
| 1113 | pattern = controller->GetLedPattern(); | 1125 | pattern = controller->GetLedPattern(); |
| 1114 | return ResultSuccess; | 1126 | return ResultSuccess; |
| 1115 | } | 1127 | } |
| 1116 | 1128 | ||
| 1117 | Result NPad::IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id, | 1129 | Result NPad::IsUnintendedHomeButtonInputProtectionEnabled(bool& out_is_enabled, u64 aruid, |
| 1118 | bool& is_valid) const { | 1130 | Core::HID::NpadIdType npad_id) const { |
| 1119 | if (!IsNpadIdValid(npad_id)) { | 1131 | std::scoped_lock lock{mutex}; |
| 1120 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | 1132 | return npad_resource.GetHomeProtectionEnabled(out_is_enabled, aruid, npad_id); |
| 1121 | return InvalidNpadId; | ||
| 1122 | } | ||
| 1123 | const auto& controller = GetControllerFromNpadIdType(npad_id); | ||
| 1124 | is_valid = controller.unintended_home_button_input_protection; | ||
| 1125 | return ResultSuccess; | ||
| 1126 | } | 1133 | } |
| 1127 | 1134 | ||
| 1128 | Result NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, | 1135 | Result NPad::EnableUnintendedHomeButtonInputProtection(u64 aruid, Core::HID::NpadIdType npad_id, |
| 1129 | Core::HID::NpadIdType npad_id) { | 1136 | bool is_enabled) { |
| 1130 | if (!IsNpadIdValid(npad_id)) { | 1137 | std::scoped_lock lock{mutex}; |
| 1131 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | 1138 | return npad_resource.SetHomeProtectionEnabled(aruid, npad_id, is_enabled); |
| 1132 | return InvalidNpadId; | ||
| 1133 | } | ||
| 1134 | auto& controller = GetControllerFromNpadIdType(npad_id); | ||
| 1135 | controller.unintended_home_button_input_protection = is_protection_enabled; | ||
| 1136 | return ResultSuccess; | ||
| 1137 | } | 1139 | } |
| 1138 | 1140 | ||
| 1139 | void NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) { | 1141 | void NPad::SetNpadAnalogStickUseCenterClamp(u64 aruid, bool is_enabled) { |
| 1140 | analog_stick_use_center_clamp = use_center_clamp; | 1142 | std::scoped_lock lock{mutex}; |
| 1143 | npad_resource.SetNpadAnalogStickUseCenterClamp(aruid, is_enabled); | ||
| 1141 | } | 1144 | } |
| 1142 | 1145 | ||
| 1143 | void NPad::ClearAllConnectedControllers() { | 1146 | void NPad::ClearAllConnectedControllers() { |
| 1144 | for (auto& controller : controller_data) { | 1147 | for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { |
| 1145 | if (controller.device->IsConnected() && | 1148 | for (auto& controller : controller_data[aruid_index]) { |
| 1146 | controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None) { | 1149 | if (controller.device->IsConnected() && |
| 1147 | controller.device->Disconnect(); | 1150 | controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None) { |
| 1148 | controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None); | 1151 | controller.device->Disconnect(); |
| 1152 | controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None); | ||
| 1153 | } | ||
| 1149 | } | 1154 | } |
| 1150 | } | 1155 | } |
| 1151 | } | 1156 | } |
| 1152 | 1157 | ||
| 1153 | void NPad::DisconnectAllConnectedControllers() { | 1158 | void NPad::DisconnectAllConnectedControllers() { |
| 1154 | for (auto& controller : controller_data) { | 1159 | for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { |
| 1155 | controller.device->Disconnect(); | 1160 | for (auto& controller : controller_data[aruid_index]) { |
| 1161 | controller.device->Disconnect(); | ||
| 1162 | } | ||
| 1156 | } | 1163 | } |
| 1157 | } | 1164 | } |
| 1158 | 1165 | ||
| 1159 | void NPad::ConnectAllDisconnectedControllers() { | 1166 | void NPad::ConnectAllDisconnectedControllers() { |
| 1160 | for (auto& controller : controller_data) { | 1167 | for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { |
| 1161 | if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None && | 1168 | for (auto& controller : controller_data[aruid_index]) { |
| 1162 | !controller.device->IsConnected()) { | 1169 | if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None && |
| 1163 | controller.device->Connect(); | 1170 | !controller.device->IsConnected()) { |
| 1171 | controller.device->Connect(); | ||
| 1172 | } | ||
| 1164 | } | 1173 | } |
| 1165 | } | 1174 | } |
| 1166 | } | 1175 | } |
| 1167 | 1176 | ||
| 1168 | void NPad::ClearAllControllers() { | 1177 | void NPad::ClearAllControllers() { |
| 1169 | for (auto& controller : controller_data) { | 1178 | for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { |
| 1170 | controller.device->Disconnect(); | 1179 | for (auto& controller : controller_data[aruid_index]) { |
| 1171 | controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None); | 1180 | controller.device->Disconnect(); |
| 1181 | controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None); | ||
| 1182 | } | ||
| 1172 | } | 1183 | } |
| 1173 | } | 1184 | } |
| 1174 | 1185 | ||
| @@ -1176,128 +1187,105 @@ Core::HID::NpadButton NPad::GetAndResetPressState() { | |||
| 1176 | return static_cast<Core::HID::NpadButton>(press_state.exchange(0)); | 1187 | return static_cast<Core::HID::NpadButton>(press_state.exchange(0)); |
| 1177 | } | 1188 | } |
| 1178 | 1189 | ||
| 1179 | void NPad::ApplyNpadSystemCommonPolicy() { | 1190 | Result NPad::ApplyNpadSystemCommonPolicy(u64 aruid) { |
| 1180 | Core::HID::NpadStyleTag styletag{}; | 1191 | std::scoped_lock lock{mutex}; |
| 1181 | styletag.fullkey.Assign(1); | 1192 | const Result result = npad_resource.ApplyNpadSystemCommonPolicy(aruid, false); |
| 1182 | styletag.handheld.Assign(1); | 1193 | if (result.IsSuccess()) { |
| 1183 | styletag.joycon_dual.Assign(1); | 1194 | OnUpdate({}); |
| 1184 | styletag.system_ext.Assign(1); | 1195 | } |
| 1185 | styletag.system.Assign(1); | 1196 | return result; |
| 1186 | SetSupportedStyleSet(styletag); | 1197 | } |
| 1187 | |||
| 1188 | SetNpadHandheldActivationMode(NpadHandheldActivationMode::Dual); | ||
| 1189 | |||
| 1190 | supported_npad_id_types.clear(); | ||
| 1191 | supported_npad_id_types.resize(10); | ||
| 1192 | supported_npad_id_types[0] = Core::HID::NpadIdType::Player1; | ||
| 1193 | supported_npad_id_types[1] = Core::HID::NpadIdType::Player2; | ||
| 1194 | supported_npad_id_types[2] = Core::HID::NpadIdType::Player3; | ||
| 1195 | supported_npad_id_types[3] = Core::HID::NpadIdType::Player4; | ||
| 1196 | supported_npad_id_types[4] = Core::HID::NpadIdType::Player5; | ||
| 1197 | supported_npad_id_types[5] = Core::HID::NpadIdType::Player6; | ||
| 1198 | supported_npad_id_types[6] = Core::HID::NpadIdType::Player7; | ||
| 1199 | supported_npad_id_types[7] = Core::HID::NpadIdType::Player8; | ||
| 1200 | supported_npad_id_types[8] = Core::HID::NpadIdType::Other; | ||
| 1201 | supported_npad_id_types[9] = Core::HID::NpadIdType::Handheld; | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | bool NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller) const { | ||
| 1205 | if (controller == Core::HID::NpadStyleIndex::Handheld) { | ||
| 1206 | const bool support_handheld = | ||
| 1207 | std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), | ||
| 1208 | Core::HID::NpadIdType::Handheld) != supported_npad_id_types.end(); | ||
| 1209 | // Handheld is not even a supported type, lets stop here | ||
| 1210 | if (!support_handheld) { | ||
| 1211 | return false; | ||
| 1212 | } | ||
| 1213 | // Handheld shouldn't be supported in docked mode | ||
| 1214 | if (Settings::IsDockedMode()) { | ||
| 1215 | return false; | ||
| 1216 | } | ||
| 1217 | 1198 | ||
| 1218 | return true; | 1199 | Result NPad::ApplyNpadSystemCommonPolicyFull(u64 aruid) { |
| 1219 | } | 1200 | std::scoped_lock lock{mutex}; |
| 1220 | 1201 | const Result result = npad_resource.ApplyNpadSystemCommonPolicy(aruid, true); | |
| 1221 | if (std::any_of(supported_npad_id_types.begin(), supported_npad_id_types.end(), | 1202 | if (result.IsSuccess()) { |
| 1222 | [](Core::HID::NpadIdType npad_id) { | 1203 | OnUpdate({}); |
| 1223 | return npad_id <= Core::HID::NpadIdType::Player8; | ||
| 1224 | })) { | ||
| 1225 | Core::HID::NpadStyleTag style = GetSupportedStyleSet(); | ||
| 1226 | switch (controller) { | ||
| 1227 | case Core::HID::NpadStyleIndex::ProController: | ||
| 1228 | return style.fullkey.As<bool>(); | ||
| 1229 | case Core::HID::NpadStyleIndex::JoyconDual: | ||
| 1230 | return style.joycon_dual.As<bool>(); | ||
| 1231 | case Core::HID::NpadStyleIndex::JoyconLeft: | ||
| 1232 | return style.joycon_left.As<bool>(); | ||
| 1233 | case Core::HID::NpadStyleIndex::JoyconRight: | ||
| 1234 | return style.joycon_right.As<bool>(); | ||
| 1235 | case Core::HID::NpadStyleIndex::GameCube: | ||
| 1236 | return style.gamecube.As<bool>(); | ||
| 1237 | case Core::HID::NpadStyleIndex::Pokeball: | ||
| 1238 | return style.palma.As<bool>(); | ||
| 1239 | case Core::HID::NpadStyleIndex::NES: | ||
| 1240 | return style.lark.As<bool>(); | ||
| 1241 | case Core::HID::NpadStyleIndex::SNES: | ||
| 1242 | return style.lucia.As<bool>(); | ||
| 1243 | case Core::HID::NpadStyleIndex::N64: | ||
| 1244 | return style.lagoon.As<bool>(); | ||
| 1245 | case Core::HID::NpadStyleIndex::SegaGenesis: | ||
| 1246 | return style.lager.As<bool>(); | ||
| 1247 | default: | ||
| 1248 | return false; | ||
| 1249 | } | ||
| 1250 | } | 1204 | } |
| 1205 | return result; | ||
| 1206 | } | ||
| 1207 | |||
| 1208 | Result NPad::ClearNpadSystemCommonPolicy(u64 aruid) { | ||
| 1209 | std::scoped_lock lock{mutex}; | ||
| 1210 | const Result result = npad_resource.ClearNpadSystemCommonPolicy(aruid); | ||
| 1211 | if (result.IsSuccess()) { | ||
| 1212 | OnUpdate({}); | ||
| 1213 | } | ||
| 1214 | return result; | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | void NPad::SetRevision(u64 aruid, NpadRevision revision) { | ||
| 1218 | npad_resource.SetNpadRevision(aruid, revision); | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | NpadRevision NPad::GetRevision(u64 aruid) { | ||
| 1222 | return npad_resource.GetNpadRevision(aruid); | ||
| 1223 | } | ||
| 1224 | |||
| 1225 | Result NPad::RegisterAppletResourceUserId(u64 aruid) { | ||
| 1226 | return npad_resource.RegisterAppletResourceUserId(aruid); | ||
| 1227 | } | ||
| 1228 | |||
| 1229 | void NPad::UnregisterAppletResourceUserId(u64 aruid) { | ||
| 1230 | npad_resource.UnregisterAppletResourceUserId(aruid); | ||
| 1231 | } | ||
| 1251 | 1232 | ||
| 1252 | return false; | 1233 | void NPad::SetNpadExternals(std::shared_ptr<AppletResource> resource, |
| 1234 | std::recursive_mutex* shared_mutex) { | ||
| 1235 | applet_resource_holder.applet_resource = resource; | ||
| 1236 | applet_resource_holder.shared_mutex = shared_mutex; | ||
| 1237 | applet_resource_holder.shared_npad_resource = &npad_resource; | ||
| 1253 | } | 1238 | } |
| 1254 | 1239 | ||
| 1255 | NPad::NpadControllerData& NPad::GetControllerFromHandle( | 1240 | NPad::NpadControllerData& NPad::GetControllerFromHandle( |
| 1256 | const Core::HID::VibrationDeviceHandle& device_handle) { | 1241 | u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle) { |
| 1257 | const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); | 1242 | const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); |
| 1258 | return GetControllerFromNpadIdType(npad_id); | 1243 | return GetControllerFromNpadIdType(aruid, npad_id); |
| 1259 | } | 1244 | } |
| 1260 | 1245 | ||
| 1261 | const NPad::NpadControllerData& NPad::GetControllerFromHandle( | 1246 | const NPad::NpadControllerData& NPad::GetControllerFromHandle( |
| 1262 | const Core::HID::VibrationDeviceHandle& device_handle) const { | 1247 | u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle) const { |
| 1263 | const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); | 1248 | const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); |
| 1264 | return GetControllerFromNpadIdType(npad_id); | 1249 | return GetControllerFromNpadIdType(aruid, npad_id); |
| 1265 | } | 1250 | } |
| 1266 | 1251 | ||
| 1267 | NPad::NpadControllerData& NPad::GetControllerFromHandle( | 1252 | NPad::NpadControllerData& NPad::GetControllerFromHandle( |
| 1268 | const Core::HID::SixAxisSensorHandle& device_handle) { | 1253 | u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle) { |
| 1269 | const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); | 1254 | const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); |
| 1270 | return GetControllerFromNpadIdType(npad_id); | 1255 | return GetControllerFromNpadIdType(aruid, npad_id); |
| 1271 | } | 1256 | } |
| 1272 | 1257 | ||
| 1273 | const NPad::NpadControllerData& NPad::GetControllerFromHandle( | 1258 | const NPad::NpadControllerData& NPad::GetControllerFromHandle( |
| 1274 | const Core::HID::SixAxisSensorHandle& device_handle) const { | 1259 | u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle) const { |
| 1275 | const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); | 1260 | const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); |
| 1276 | return GetControllerFromNpadIdType(npad_id); | 1261 | return GetControllerFromNpadIdType(aruid, npad_id); |
| 1277 | } | 1262 | } |
| 1278 | 1263 | ||
| 1279 | NPad::NpadControllerData& NPad::GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) { | 1264 | NPad::NpadControllerData& NPad::GetControllerFromNpadIdType(u64 aruid, |
| 1265 | Core::HID::NpadIdType npad_id) { | ||
| 1280 | if (!IsNpadIdValid(npad_id)) { | 1266 | if (!IsNpadIdValid(npad_id)) { |
| 1281 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | 1267 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); |
| 1282 | npad_id = Core::HID::NpadIdType::Player1; | 1268 | npad_id = Core::HID::NpadIdType::Player1; |
| 1283 | } | 1269 | } |
| 1284 | const auto npad_index = NpadIdTypeToIndex(npad_id); | 1270 | const auto npad_index = NpadIdTypeToIndex(npad_id); |
| 1285 | return controller_data[npad_index]; | 1271 | const auto aruid_index = applet_resource_holder.applet_resource->GetIndexFromAruid(aruid); |
| 1272 | return controller_data[aruid_index][npad_index]; | ||
| 1286 | } | 1273 | } |
| 1287 | 1274 | ||
| 1288 | const NPad::NpadControllerData& NPad::GetControllerFromNpadIdType( | 1275 | const NPad::NpadControllerData& NPad::GetControllerFromNpadIdType( |
| 1289 | Core::HID::NpadIdType npad_id) const { | 1276 | u64 aruid, Core::HID::NpadIdType npad_id) const { |
| 1290 | if (!IsNpadIdValid(npad_id)) { | 1277 | if (!IsNpadIdValid(npad_id)) { |
| 1291 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | 1278 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); |
| 1292 | npad_id = Core::HID::NpadIdType::Player1; | 1279 | npad_id = Core::HID::NpadIdType::Player1; |
| 1293 | } | 1280 | } |
| 1294 | const auto npad_index = NpadIdTypeToIndex(npad_id); | 1281 | const auto npad_index = NpadIdTypeToIndex(npad_id); |
| 1295 | return controller_data[npad_index]; | 1282 | const auto aruid_index = applet_resource_holder.applet_resource->GetIndexFromAruid(aruid); |
| 1283 | return controller_data[aruid_index][npad_index]; | ||
| 1296 | } | 1284 | } |
| 1297 | 1285 | ||
| 1298 | Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties( | 1286 | Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties( |
| 1299 | const Core::HID::SixAxisSensorHandle& sixaxis_handle) { | 1287 | u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) { |
| 1300 | auto& controller = GetControllerFromHandle(sixaxis_handle); | 1288 | auto& controller = GetControllerFromHandle(aruid, sixaxis_handle); |
| 1301 | switch (sixaxis_handle.npad_type) { | 1289 | switch (sixaxis_handle.npad_type) { |
| 1302 | case Core::HID::NpadStyleIndex::ProController: | 1290 | case Core::HID::NpadStyleIndex::ProController: |
| 1303 | case Core::HID::NpadStyleIndex::Pokeball: | 1291 | case Core::HID::NpadStyleIndex::Pokeball: |
| @@ -1319,8 +1307,8 @@ Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties( | |||
| 1319 | } | 1307 | } |
| 1320 | 1308 | ||
| 1321 | const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties( | 1309 | const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties( |
| 1322 | const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { | 1310 | u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { |
| 1323 | const auto& controller = GetControllerFromHandle(sixaxis_handle); | 1311 | const auto& controller = GetControllerFromHandle(aruid, sixaxis_handle); |
| 1324 | switch (sixaxis_handle.npad_type) { | 1312 | switch (sixaxis_handle.npad_type) { |
| 1325 | case Core::HID::NpadStyleIndex::ProController: | 1313 | case Core::HID::NpadStyleIndex::ProController: |
| 1326 | case Core::HID::NpadStyleIndex::Pokeball: | 1314 | case Core::HID::NpadStyleIndex::Pokeball: |
| @@ -1342,7 +1330,8 @@ const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties( | |||
| 1342 | } | 1330 | } |
| 1343 | 1331 | ||
| 1344 | AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) { | 1332 | AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) { |
| 1345 | const auto& shared_memory = GetControllerFromNpadIdType(npad_id).shared_memory; | 1333 | const auto aruid = applet_resource_holder.applet_resource->GetActiveAruid(); |
| 1334 | const auto& shared_memory = GetControllerFromNpadIdType(aruid, npad_id).shared_memory; | ||
| 1346 | 1335 | ||
| 1347 | return { | 1336 | return { |
| 1348 | .ui_variant = 0, | 1337 | .ui_variant = 0, |
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 4e2412356..8ab333064 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "core/hid/hid_types.h" | 12 | #include "core/hid/hid_types.h" |
| 13 | #include "core/hle/service/hid/controllers/controller_base.h" | 13 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 14 | #include "core/hle/service/hid/controllers/npad/npad_resource.h" | ||
| 14 | #include "core/hle/service/hid/controllers/types/npad_types.h" | 15 | #include "core/hle/service/hid/controllers/types/npad_types.h" |
| 15 | 16 | ||
| 16 | namespace Core::HID { | 17 | namespace Core::HID { |
| @@ -30,111 +31,121 @@ class ServiceContext; | |||
| 30 | union Result; | 31 | union Result; |
| 31 | 32 | ||
| 32 | namespace Service::HID { | 33 | namespace Service::HID { |
| 34 | class AppletResource; | ||
| 33 | struct NpadInternalState; | 35 | struct NpadInternalState; |
| 34 | struct NpadSixAxisSensorLifo; | 36 | struct NpadSixAxisSensorLifo; |
| 35 | struct NpadSharedMemoryFormat; | 37 | struct NpadSharedMemoryFormat; |
| 36 | 38 | ||
| 37 | class NPad final : public ControllerBase { | 39 | class NPad final { |
| 38 | public: | 40 | public: |
| 39 | explicit NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format, | 41 | explicit NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_); |
| 40 | KernelHelpers::ServiceContext& service_context_); | 42 | ~NPad(); |
| 41 | ~NPad() override; | ||
| 42 | 43 | ||
| 43 | // Called when the controller is initialized | 44 | Result Activate(); |
| 44 | void OnInit() override; | 45 | Result Activate(u64 aruid); |
| 45 | 46 | ||
| 46 | // When the controller is released | 47 | Result ActivateNpadResource(); |
| 47 | void OnRelease() override; | 48 | Result ActivateNpadResource(u64 aruid); |
| 48 | 49 | ||
| 49 | // When the controller is requesting an update for the shared memory | 50 | // When the controller is requesting an update for the shared memory |
| 50 | void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; | 51 | void OnUpdate(const Core::Timing::CoreTiming& core_timing); |
| 51 | 52 | ||
| 52 | void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); | 53 | Result SetSupportedNpadStyleSet(u64 aruid, Core::HID::NpadStyleSet supported_style_set); |
| 53 | Core::HID::NpadStyleTag GetSupportedStyleSet() const; | 54 | Result GetSupportedNpadStyleSet(u64 aruid, |
| 55 | Core::HID::NpadStyleSet& out_supported_style_set) const; | ||
| 56 | Result GetMaskedSupportedNpadStyleSet(u64 aruid, | ||
| 57 | Core::HID::NpadStyleSet& out_supported_style_set) const; | ||
| 54 | 58 | ||
| 55 | Result SetSupportedNpadIdTypes(std::span<const u8> data); | 59 | Result SetSupportedNpadIdType(u64 aruid, |
| 56 | void GetSupportedNpadIdTypes(u32* data, std::size_t max_length); | 60 | std::span<const Core::HID::NpadIdType> supported_npad_list); |
| 57 | std::size_t GetSupportedNpadIdTypesSize() const; | ||
| 58 | 61 | ||
| 59 | void SetHoldType(NpadJoyHoldType joy_hold_type); | 62 | Result SetNpadJoyHoldType(u64 aruid, NpadJoyHoldType hold_type); |
| 60 | NpadJoyHoldType GetHoldType() const; | 63 | Result GetNpadJoyHoldType(u64 aruid, NpadJoyHoldType& out_hold_type) const; |
| 61 | 64 | ||
| 62 | void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode); | 65 | Result SetNpadHandheldActivationMode(u64 aruid, NpadHandheldActivationMode mode); |
| 63 | NpadHandheldActivationMode GetNpadHandheldActivationMode() const; | 66 | Result GetNpadHandheldActivationMode(u64 aruid, NpadHandheldActivationMode& out_mode) const; |
| 64 | 67 | ||
| 65 | void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_); | 68 | bool SetNpadMode(u64 aruid, Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id, |
| 66 | NpadCommunicationMode GetNpadCommunicationMode() const; | ||
| 67 | |||
| 68 | bool SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id, | ||
| 69 | NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode); | 69 | NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode); |
| 70 | 70 | ||
| 71 | bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index, | 71 | bool VibrateControllerAtIndex(u64 aruid, Core::HID::NpadIdType npad_id, |
| 72 | std::size_t device_index, | ||
| 72 | const Core::HID::VibrationValue& vibration_value); | 73 | const Core::HID::VibrationValue& vibration_value); |
| 73 | 74 | ||
| 74 | void VibrateController(const Core::HID::VibrationDeviceHandle& vibration_device_handle, | 75 | void VibrateController(u64 aruid, |
| 76 | const Core::HID::VibrationDeviceHandle& vibration_device_handle, | ||
| 75 | const Core::HID::VibrationValue& vibration_value); | 77 | const Core::HID::VibrationValue& vibration_value); |
| 76 | 78 | ||
| 77 | void VibrateControllers( | 79 | void VibrateControllers( |
| 78 | std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles, | 80 | u64 aruid, std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles, |
| 79 | std::span<const Core::HID::VibrationValue> vibration_values); | 81 | std::span<const Core::HID::VibrationValue> vibration_values); |
| 80 | 82 | ||
| 81 | Core::HID::VibrationValue GetLastVibration( | 83 | Core::HID::VibrationValue GetLastVibration( |
| 82 | const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; | 84 | u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; |
| 83 | 85 | ||
| 84 | void InitializeVibrationDevice(const Core::HID::VibrationDeviceHandle& vibration_device_handle); | 86 | void InitializeVibrationDevice(const Core::HID::VibrationDeviceHandle& vibration_device_handle); |
| 85 | 87 | ||
| 86 | void InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index); | 88 | void InitializeVibrationDeviceAtIndex(u64 aruid, Core::HID::NpadIdType npad_id, |
| 89 | std::size_t device_index); | ||
| 87 | 90 | ||
| 88 | void SetPermitVibrationSession(bool permit_vibration_session); | 91 | void SetPermitVibrationSession(bool permit_vibration_session); |
| 89 | 92 | ||
| 90 | bool IsVibrationDeviceMounted( | 93 | bool IsVibrationDeviceMounted( |
| 91 | const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; | 94 | u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; |
| 92 | 95 | ||
| 93 | Kernel::KReadableEvent& GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id); | 96 | Result AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event, |
| 94 | void SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const; | 97 | Core::HID::NpadIdType npad_id); |
| 95 | 98 | ||
| 96 | // Adds a new controller at an index. | 99 | // Adds a new controller at an index. |
| 97 | void AddNewControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id); | 100 | void AddNewControllerAt(u64 aruid, Core::HID::NpadStyleIndex controller, |
| 101 | Core::HID::NpadIdType npad_id); | ||
| 98 | // Adds a new controller at an index with connection status. | 102 | // Adds a new controller at an index with connection status. |
| 99 | void UpdateControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id, | 103 | void UpdateControllerAt(u64 aruid, Core::HID::NpadStyleIndex controller, |
| 100 | bool connected); | 104 | Core::HID::NpadIdType npad_id, bool connected); |
| 101 | 105 | ||
| 102 | Result DisconnectNpad(Core::HID::NpadIdType npad_id); | 106 | Result DisconnectNpad(u64 aruid, Core::HID::NpadIdType npad_id); |
| 103 | 107 | ||
| 104 | Result IsFirmwareUpdateAvailableForSixAxisSensor( | 108 | Result IsFirmwareUpdateAvailableForSixAxisSensor( |
| 105 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const; | 109 | u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 110 | bool& is_firmware_available) const; | ||
| 106 | Result ResetIsSixAxisSensorDeviceNewlyAssigned( | 111 | Result ResetIsSixAxisSensorDeviceNewlyAssigned( |
| 107 | const Core::HID::SixAxisSensorHandle& sixaxis_handle); | 112 | u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle); |
| 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 | 113 | ||
| 116 | Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const; | 114 | Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const; |
| 117 | Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id, | 115 | |
| 118 | bool& is_enabled) const; | 116 | Result IsUnintendedHomeButtonInputProtectionEnabled(bool& out_is_enabled, u64 aruid, |
| 119 | Result SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, | 117 | Core::HID::NpadIdType npad_id) const; |
| 120 | Core::HID::NpadIdType npad_id); | 118 | Result EnableUnintendedHomeButtonInputProtection(u64 aruid, Core::HID::NpadIdType npad_id, |
| 121 | void SetAnalogStickUseCenterClamp(bool use_center_clamp); | 119 | bool is_enabled); |
| 120 | |||
| 121 | void SetNpadAnalogStickUseCenterClamp(u64 aruid, bool is_enabled); | ||
| 122 | void ClearAllConnectedControllers(); | 122 | void ClearAllConnectedControllers(); |
| 123 | void DisconnectAllConnectedControllers(); | 123 | void DisconnectAllConnectedControllers(); |
| 124 | void ConnectAllDisconnectedControllers(); | 124 | void ConnectAllDisconnectedControllers(); |
| 125 | void ClearAllControllers(); | 125 | void ClearAllControllers(); |
| 126 | 126 | ||
| 127 | Result MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, | 127 | Result MergeSingleJoyAsDualJoy(u64 aruid, Core::HID::NpadIdType npad_id_1, |
| 128 | Core::HID::NpadIdType npad_id_2); | 128 | Core::HID::NpadIdType npad_id_2); |
| 129 | void StartLRAssignmentMode(); | 129 | Result StartLrAssignmentMode(u64 aruid); |
| 130 | void StopLRAssignmentMode(); | 130 | Result StopLrAssignmentMode(u64 aruid); |
| 131 | Result SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2); | 131 | Result SwapNpadAssignment(u64 aruid, Core::HID::NpadIdType npad_id_1, |
| 132 | Core::HID::NpadIdType npad_id_2); | ||
| 132 | 133 | ||
| 133 | // Logical OR for all buttons presses on all controllers | 134 | // Logical OR for all buttons presses on all controllers |
| 134 | // Specifically for cheat engine and other features. | 135 | // Specifically for cheat engine and other features. |
| 135 | Core::HID::NpadButton GetAndResetPressState(); | 136 | Core::HID::NpadButton GetAndResetPressState(); |
| 136 | 137 | ||
| 137 | void ApplyNpadSystemCommonPolicy(); | 138 | Result ApplyNpadSystemCommonPolicy(u64 aruid); |
| 139 | Result ApplyNpadSystemCommonPolicyFull(u64 aruid); | ||
| 140 | Result ClearNpadSystemCommonPolicy(u64 aruid); | ||
| 141 | |||
| 142 | void SetRevision(u64 aruid, NpadRevision revision); | ||
| 143 | NpadRevision GetRevision(u64 aruid); | ||
| 144 | |||
| 145 | Result RegisterAppletResourceUserId(u64 aruid); | ||
| 146 | void UnregisterAppletResourceUserId(u64 aruid); | ||
| 147 | void SetNpadExternals(std::shared_ptr<AppletResource> resource, | ||
| 148 | std::recursive_mutex* shared_mutex); | ||
| 138 | 149 | ||
| 139 | AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id); | 150 | AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id); |
| 140 | 151 | ||
| @@ -146,12 +157,10 @@ private: | |||
| 146 | }; | 157 | }; |
| 147 | 158 | ||
| 148 | struct NpadControllerData { | 159 | struct NpadControllerData { |
| 149 | Kernel::KEvent* styleset_changed_event{}; | ||
| 150 | NpadInternalState* shared_memory = nullptr; | 160 | NpadInternalState* shared_memory = nullptr; |
| 151 | Core::HID::EmulatedController* device = nullptr; | 161 | Core::HID::EmulatedController* device = nullptr; |
| 152 | 162 | ||
| 153 | std::array<VibrationData, 2> vibration{}; | 163 | std::array<VibrationData, 2> vibration{}; |
| 154 | bool unintended_home_button_input_protection{}; | ||
| 155 | bool is_connected{}; | 164 | bool is_connected{}; |
| 156 | 165 | ||
| 157 | // Dual joycons can have only one side connected | 166 | // Dual joycons can have only one side connected |
| @@ -166,39 +175,40 @@ private: | |||
| 166 | }; | 175 | }; |
| 167 | 176 | ||
| 168 | void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx); | 177 | void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx); |
| 169 | void InitNewlyAddedController(Core::HID::NpadIdType npad_id); | 178 | void InitNewlyAddedController(u64 aruid, Core::HID::NpadIdType npad_id); |
| 170 | bool IsControllerSupported(Core::HID::NpadStyleIndex controller) const; | 179 | void RequestPadStateUpdate(u64 aruid, Core::HID::NpadIdType npad_id); |
| 171 | void RequestPadStateUpdate(Core::HID::NpadIdType npad_id); | ||
| 172 | void WriteEmptyEntry(NpadInternalState* npad); | 180 | void WriteEmptyEntry(NpadInternalState* npad); |
| 173 | 181 | ||
| 174 | NpadControllerData& GetControllerFromHandle( | 182 | NpadControllerData& GetControllerFromHandle( |
| 175 | const Core::HID::VibrationDeviceHandle& device_handle); | 183 | u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle); |
| 176 | const NpadControllerData& GetControllerFromHandle( | 184 | const NpadControllerData& GetControllerFromHandle( |
| 177 | const Core::HID::VibrationDeviceHandle& device_handle) const; | 185 | u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle) const; |
| 178 | NpadControllerData& GetControllerFromHandle( | 186 | NpadControllerData& GetControllerFromHandle( |
| 179 | const Core::HID::SixAxisSensorHandle& device_handle); | 187 | u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle); |
| 180 | const NpadControllerData& GetControllerFromHandle( | 188 | const NpadControllerData& GetControllerFromHandle( |
| 181 | const Core::HID::SixAxisSensorHandle& device_handle) const; | 189 | u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle) const; |
| 182 | NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id); | 190 | NpadControllerData& GetControllerFromNpadIdType(u64 aruid, Core::HID::NpadIdType npad_id); |
| 183 | const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const; | 191 | const NpadControllerData& GetControllerFromNpadIdType(u64 aruid, |
| 192 | Core::HID::NpadIdType npad_id) const; | ||
| 184 | 193 | ||
| 185 | Core::HID::SixAxisSensorProperties& GetSixaxisProperties( | 194 | Core::HID::SixAxisSensorProperties& GetSixaxisProperties( |
| 186 | const Core::HID::SixAxisSensorHandle& device_handle); | 195 | u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle); |
| 187 | const Core::HID::SixAxisSensorProperties& GetSixaxisProperties( | 196 | const Core::HID::SixAxisSensorProperties& GetSixaxisProperties( |
| 188 | const Core::HID::SixAxisSensorHandle& device_handle) const; | 197 | u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle) const; |
| 189 | 198 | ||
| 190 | std::atomic<u64> press_state{}; | 199 | Core::HID::HIDCore& hid_core; |
| 191 | |||
| 192 | std::array<NpadControllerData, NpadCount> controller_data{}; | ||
| 193 | KernelHelpers::ServiceContext& service_context; | 200 | KernelHelpers::ServiceContext& service_context; |
| 194 | std::mutex mutex; | 201 | |
| 195 | std::vector<Core::HID::NpadIdType> supported_npad_id_types{}; | 202 | s32 ref_counter{}; |
| 196 | NpadJoyHoldType hold_type{NpadJoyHoldType::Vertical}; | 203 | mutable std::mutex mutex; |
| 197 | NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; | 204 | NPadResource npad_resource; |
| 198 | NpadCommunicationMode communication_mode{NpadCommunicationMode::Default}; | 205 | AppletResourceHolder applet_resource_holder{}; |
| 199 | bool permit_vibration_session_enabled{false}; | 206 | Kernel::KEvent* input_event{nullptr}; |
| 200 | bool analog_stick_use_center_clamp{false}; | 207 | std::mutex* input_mutex{nullptr}; |
| 201 | bool is_in_lr_assignment_mode{false}; | 208 | |
| 202 | bool is_controller_initialized{false}; | 209 | std::atomic<u64> press_state{}; |
| 210 | bool permit_vibration_session_enabled; | ||
| 211 | std::array<std::array<NpadControllerData, MaxSupportedNpadIdTypes>, AruidIndexMax> | ||
| 212 | controller_data{}; | ||
| 203 | }; | 213 | }; |
| 204 | } // namespace Service::HID | 214 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/npad/npad_data.cpp b/src/core/hle/service/hid/controllers/npad/npad_data.cpp new file mode 100644 index 000000000..d2423b6d3 --- /dev/null +++ b/src/core/hle/service/hid/controllers/npad/npad_data.cpp | |||
| @@ -0,0 +1,228 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/hid/controllers/npad/npad_data.h" | ||
| 5 | #include "core/hle/service/hid/hid_util.h" | ||
| 6 | |||
| 7 | namespace Service::HID { | ||
| 8 | |||
| 9 | NPadData::NPadData() { | ||
| 10 | ClearNpadSystemCommonPolicy(); | ||
| 11 | } | ||
| 12 | |||
| 13 | NPadData::~NPadData() = default; | ||
| 14 | |||
| 15 | NpadStatus NPadData::GetNpadStatus() const { | ||
| 16 | return status; | ||
| 17 | } | ||
| 18 | |||
| 19 | void NPadData::SetNpadAnalogStickUseCenterClamp(bool is_enabled) { | ||
| 20 | status.use_center_clamp.Assign(is_enabled); | ||
| 21 | } | ||
| 22 | |||
| 23 | bool NPadData::GetNpadAnalogStickUseCenterClamp() const { | ||
| 24 | return status.use_center_clamp.As<bool>(); | ||
| 25 | } | ||
| 26 | |||
| 27 | void NPadData::SetNpadSystemExtStateEnabled(bool is_enabled) { | ||
| 28 | status.system_ext_state.Assign(is_enabled); | ||
| 29 | } | ||
| 30 | |||
| 31 | bool NPadData::GetNpadSystemExtState() const { | ||
| 32 | return status.system_ext_state.As<bool>(); | ||
| 33 | } | ||
| 34 | |||
| 35 | Result NPadData::SetSupportedNpadIdType(std::span<const Core::HID::NpadIdType> list) { | ||
| 36 | // Note: Real limit is 11. But array size is 10. N's bug? | ||
| 37 | if (list.size() > MaxSupportedNpadIdTypes) { | ||
| 38 | return ResultInvalidArraySize; | ||
| 39 | } | ||
| 40 | |||
| 41 | supported_npad_id_types_count = list.size(); | ||
| 42 | memcpy(supported_npad_id_types.data(), list.data(), | ||
| 43 | list.size() * sizeof(Core::HID::NpadIdType)); | ||
| 44 | |||
| 45 | return ResultSuccess; | ||
| 46 | } | ||
| 47 | |||
| 48 | std::size_t NPadData::GetSupportedNpadIdType(std::span<Core::HID::NpadIdType> out_list) const { | ||
| 49 | std::size_t out_size = std::min(supported_npad_id_types_count, out_list.size()); | ||
| 50 | |||
| 51 | memcpy(out_list.data(), supported_npad_id_types.data(), | ||
| 52 | out_size * sizeof(Core::HID::NpadIdType)); | ||
| 53 | |||
| 54 | return out_size; | ||
| 55 | } | ||
| 56 | |||
| 57 | bool NPadData::IsNpadIdTypeSupported(Core::HID::NpadIdType npad_id) const { | ||
| 58 | for (std::size_t i = 0; i < supported_npad_id_types_count; i++) { | ||
| 59 | if (supported_npad_id_types[i] == npad_id) { | ||
| 60 | return true; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | return false; | ||
| 65 | } | ||
| 66 | |||
| 67 | void NPadData::SetNpadSystemCommonPolicy(bool is_full_policy) { | ||
| 68 | supported_npad_style_set = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::JoyDual | | ||
| 69 | Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System; | ||
| 70 | handheld_activation_mode = NpadHandheldActivationMode::Dual; | ||
| 71 | |||
| 72 | status.is_supported_styleset_set.Assign(true); | ||
| 73 | status.is_hold_type_set.Assign(true); | ||
| 74 | status.lr_assignment_mode.Assign(false); | ||
| 75 | status.is_policy.Assign(true); | ||
| 76 | if (is_full_policy) { | ||
| 77 | status.is_full_policy.Assign(true); | ||
| 78 | } | ||
| 79 | |||
| 80 | supported_npad_id_types_count = 10; | ||
| 81 | supported_npad_id_types[0] = Core::HID::NpadIdType::Player1; | ||
| 82 | supported_npad_id_types[1] = Core::HID::NpadIdType::Player2; | ||
| 83 | supported_npad_id_types[2] = Core::HID::NpadIdType::Player3; | ||
| 84 | supported_npad_id_types[3] = Core::HID::NpadIdType::Player4; | ||
| 85 | supported_npad_id_types[4] = Core::HID::NpadIdType::Player5; | ||
| 86 | supported_npad_id_types[5] = Core::HID::NpadIdType::Player6; | ||
| 87 | supported_npad_id_types[6] = Core::HID::NpadIdType::Player7; | ||
| 88 | supported_npad_id_types[7] = Core::HID::NpadIdType::Player8; | ||
| 89 | supported_npad_id_types[8] = Core::HID::NpadIdType::Other; | ||
| 90 | supported_npad_id_types[9] = Core::HID::NpadIdType::Handheld; | ||
| 91 | |||
| 92 | for (auto& input_protection : is_unintended_home_button_input_protection) { | ||
| 93 | input_protection = true; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | void NPadData::ClearNpadSystemCommonPolicy() { | ||
| 98 | status.raw = 0; | ||
| 99 | supported_npad_style_set = Core::HID::NpadStyleSet::All; | ||
| 100 | npad_hold_type = NpadJoyHoldType::Vertical; | ||
| 101 | handheld_activation_mode = NpadHandheldActivationMode::Dual; | ||
| 102 | |||
| 103 | for (auto& button_assignment : npad_button_assignment) { | ||
| 104 | button_assignment = Core::HID::NpadButton::None; | ||
| 105 | } | ||
| 106 | |||
| 107 | supported_npad_id_types_count = 10; | ||
| 108 | supported_npad_id_types[0] = Core::HID::NpadIdType::Player1; | ||
| 109 | supported_npad_id_types[1] = Core::HID::NpadIdType::Player2; | ||
| 110 | supported_npad_id_types[2] = Core::HID::NpadIdType::Player3; | ||
| 111 | supported_npad_id_types[3] = Core::HID::NpadIdType::Player4; | ||
| 112 | supported_npad_id_types[4] = Core::HID::NpadIdType::Player5; | ||
| 113 | supported_npad_id_types[5] = Core::HID::NpadIdType::Player6; | ||
| 114 | supported_npad_id_types[6] = Core::HID::NpadIdType::Player7; | ||
| 115 | supported_npad_id_types[7] = Core::HID::NpadIdType::Player8; | ||
| 116 | supported_npad_id_types[8] = Core::HID::NpadIdType::Other; | ||
| 117 | supported_npad_id_types[9] = Core::HID::NpadIdType::Handheld; | ||
| 118 | |||
| 119 | for (auto& input_protection : is_unintended_home_button_input_protection) { | ||
| 120 | input_protection = true; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | void NPadData::SetNpadJoyHoldType(NpadJoyHoldType hold_type) { | ||
| 125 | npad_hold_type = hold_type; | ||
| 126 | status.is_hold_type_set.Assign(true); | ||
| 127 | } | ||
| 128 | |||
| 129 | NpadJoyHoldType NPadData::GetNpadJoyHoldType() const { | ||
| 130 | return npad_hold_type; | ||
| 131 | } | ||
| 132 | |||
| 133 | void NPadData::SetHandheldActivationMode(NpadHandheldActivationMode activation_mode) { | ||
| 134 | handheld_activation_mode = activation_mode; | ||
| 135 | } | ||
| 136 | |||
| 137 | NpadHandheldActivationMode NPadData::GetHandheldActivationMode() const { | ||
| 138 | return handheld_activation_mode; | ||
| 139 | } | ||
| 140 | |||
| 141 | void NPadData::SetSupportedNpadStyleSet(Core::HID::NpadStyleSet style_set) { | ||
| 142 | supported_npad_style_set = style_set; | ||
| 143 | status.is_supported_styleset_set.Assign(true); | ||
| 144 | status.is_hold_type_set.Assign(true); | ||
| 145 | } | ||
| 146 | |||
| 147 | Core::HID::NpadStyleSet NPadData::GetSupportedNpadStyleSet() const { | ||
| 148 | return supported_npad_style_set; | ||
| 149 | } | ||
| 150 | |||
| 151 | bool NPadData::IsNpadStyleIndexSupported(Core::HID::NpadStyleIndex style_index) const { | ||
| 152 | Core::HID::NpadStyleTag style = {supported_npad_style_set}; | ||
| 153 | switch (style_index) { | ||
| 154 | case Core::HID::NpadStyleIndex::ProController: | ||
| 155 | return style.fullkey.As<bool>(); | ||
| 156 | case Core::HID::NpadStyleIndex::Handheld: | ||
| 157 | return style.handheld.As<bool>(); | ||
| 158 | case Core::HID::NpadStyleIndex::JoyconDual: | ||
| 159 | return style.joycon_dual.As<bool>(); | ||
| 160 | case Core::HID::NpadStyleIndex::JoyconLeft: | ||
| 161 | return style.joycon_left.As<bool>(); | ||
| 162 | case Core::HID::NpadStyleIndex::JoyconRight: | ||
| 163 | return style.joycon_right.As<bool>(); | ||
| 164 | case Core::HID::NpadStyleIndex::GameCube: | ||
| 165 | return style.gamecube.As<bool>(); | ||
| 166 | case Core::HID::NpadStyleIndex::Pokeball: | ||
| 167 | return style.palma.As<bool>(); | ||
| 168 | case Core::HID::NpadStyleIndex::NES: | ||
| 169 | return style.lark.As<bool>(); | ||
| 170 | case Core::HID::NpadStyleIndex::SNES: | ||
| 171 | return style.lucia.As<bool>(); | ||
| 172 | case Core::HID::NpadStyleIndex::N64: | ||
| 173 | return style.lagoon.As<bool>(); | ||
| 174 | case Core::HID::NpadStyleIndex::SegaGenesis: | ||
| 175 | return style.lager.As<bool>(); | ||
| 176 | default: | ||
| 177 | return false; | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | void NPadData::SetLrAssignmentMode(bool is_enabled) { | ||
| 182 | status.lr_assignment_mode.Assign(is_enabled); | ||
| 183 | } | ||
| 184 | |||
| 185 | bool NPadData::GetLrAssignmentMode() const { | ||
| 186 | return status.lr_assignment_mode.As<bool>(); | ||
| 187 | } | ||
| 188 | |||
| 189 | void NPadData::SetAssigningSingleOnSlSrPress(bool is_enabled) { | ||
| 190 | status.assigning_single_on_sl_sr_press.Assign(is_enabled); | ||
| 191 | } | ||
| 192 | |||
| 193 | bool NPadData::GetAssigningSingleOnSlSrPress() const { | ||
| 194 | return status.assigning_single_on_sl_sr_press.As<bool>(); | ||
| 195 | } | ||
| 196 | |||
| 197 | void NPadData::SetHomeProtectionEnabled(bool is_enabled, Core::HID::NpadIdType npad_id) { | ||
| 198 | is_unintended_home_button_input_protection[NpadIdTypeToIndex(npad_id)] = is_enabled; | ||
| 199 | } | ||
| 200 | |||
| 201 | bool NPadData::GetHomeProtectionEnabled(Core::HID::NpadIdType npad_id) const { | ||
| 202 | return is_unintended_home_button_input_protection[NpadIdTypeToIndex(npad_id)]; | ||
| 203 | } | ||
| 204 | |||
| 205 | void NPadData::SetCaptureButtonAssignment(Core::HID::NpadButton button_assignment, | ||
| 206 | std::size_t style_index) { | ||
| 207 | npad_button_assignment[style_index] = button_assignment; | ||
| 208 | } | ||
| 209 | |||
| 210 | Core::HID::NpadButton NPadData::GetCaptureButtonAssignment(std::size_t style_index) const { | ||
| 211 | return npad_button_assignment[style_index]; | ||
| 212 | } | ||
| 213 | |||
| 214 | std::size_t NPadData::GetNpadCaptureButtonAssignmentList( | ||
| 215 | std::span<Core::HID::NpadButton> out_list) const { | ||
| 216 | for (std::size_t i = 0; i < out_list.size(); i++) { | ||
| 217 | Core::HID::NpadStyleSet style_set = GetStylesetByIndex(i); | ||
| 218 | if ((style_set & supported_npad_style_set) == Core::HID::NpadStyleSet::None || | ||
| 219 | npad_button_assignment[i] == Core::HID::NpadButton::None) { | ||
| 220 | return i; | ||
| 221 | } | ||
| 222 | out_list[i] = npad_button_assignment[i]; | ||
| 223 | } | ||
| 224 | |||
| 225 | return out_list.size(); | ||
| 226 | } | ||
| 227 | |||
| 228 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/hid/controllers/npad/npad_data.h b/src/core/hle/service/hid/controllers/npad/npad_data.h new file mode 100644 index 000000000..f799a9f9c --- /dev/null +++ b/src/core/hle/service/hid/controllers/npad/npad_data.h | |||
| @@ -0,0 +1,88 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | #include <span> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/hid/hid_types.h" | ||
| 11 | #include "core/hle/result.h" | ||
| 12 | #include "core/hle/service/hid/controllers/types/npad_types.h" | ||
| 13 | |||
| 14 | namespace Service::HID { | ||
| 15 | |||
| 16 | struct NpadStatus { | ||
| 17 | union { | ||
| 18 | u32 raw{}; | ||
| 19 | |||
| 20 | BitField<0, 1, u32> is_supported_styleset_set; | ||
| 21 | BitField<1, 1, u32> is_hold_type_set; | ||
| 22 | BitField<2, 1, u32> lr_assignment_mode; | ||
| 23 | BitField<3, 1, u32> assigning_single_on_sl_sr_press; | ||
| 24 | BitField<4, 1, u32> is_full_policy; | ||
| 25 | BitField<5, 1, u32> is_policy; | ||
| 26 | BitField<6, 1, u32> use_center_clamp; | ||
| 27 | BitField<7, 1, u32> system_ext_state; | ||
| 28 | }; | ||
| 29 | }; | ||
| 30 | static_assert(sizeof(NpadStatus) == 4, "NpadStatus is an invalid size"); | ||
| 31 | |||
| 32 | /// Handles Npad request from HID interfaces | ||
| 33 | class NPadData final { | ||
| 34 | public: | ||
| 35 | explicit NPadData(); | ||
| 36 | ~NPadData(); | ||
| 37 | |||
| 38 | NpadStatus GetNpadStatus() const; | ||
| 39 | |||
| 40 | void SetNpadAnalogStickUseCenterClamp(bool is_enabled); | ||
| 41 | bool GetNpadAnalogStickUseCenterClamp() const; | ||
| 42 | |||
| 43 | void SetNpadSystemExtStateEnabled(bool is_enabled); | ||
| 44 | bool GetNpadSystemExtState() const; | ||
| 45 | |||
| 46 | Result SetSupportedNpadIdType(std::span<const Core::HID::NpadIdType> list); | ||
| 47 | std::size_t GetSupportedNpadIdType(std::span<Core::HID::NpadIdType> out_list) const; | ||
| 48 | bool IsNpadIdTypeSupported(Core::HID::NpadIdType npad_id) const; | ||
| 49 | |||
| 50 | void SetNpadSystemCommonPolicy(bool is_full_policy); | ||
| 51 | void ClearNpadSystemCommonPolicy(); | ||
| 52 | |||
| 53 | void SetNpadJoyHoldType(NpadJoyHoldType hold_type); | ||
| 54 | NpadJoyHoldType GetNpadJoyHoldType() const; | ||
| 55 | |||
| 56 | void SetHandheldActivationMode(NpadHandheldActivationMode activation_mode); | ||
| 57 | NpadHandheldActivationMode GetHandheldActivationMode() const; | ||
| 58 | |||
| 59 | void SetSupportedNpadStyleSet(Core::HID::NpadStyleSet style_set); | ||
| 60 | Core::HID::NpadStyleSet GetSupportedNpadStyleSet() const; | ||
| 61 | bool IsNpadStyleIndexSupported(Core::HID::NpadStyleIndex style_index) const; | ||
| 62 | |||
| 63 | void SetLrAssignmentMode(bool is_enabled); | ||
| 64 | bool GetLrAssignmentMode() const; | ||
| 65 | |||
| 66 | void SetAssigningSingleOnSlSrPress(bool is_enabled); | ||
| 67 | bool GetAssigningSingleOnSlSrPress() const; | ||
| 68 | |||
| 69 | void SetHomeProtectionEnabled(bool is_enabled, Core::HID::NpadIdType npad_id); | ||
| 70 | bool GetHomeProtectionEnabled(Core::HID::NpadIdType npad_id) const; | ||
| 71 | |||
| 72 | void SetCaptureButtonAssignment(Core::HID::NpadButton button_assignment, | ||
| 73 | std::size_t style_index); | ||
| 74 | Core::HID::NpadButton GetCaptureButtonAssignment(std::size_t style_index) const; | ||
| 75 | std::size_t GetNpadCaptureButtonAssignmentList(std::span<Core::HID::NpadButton> out_list) const; | ||
| 76 | |||
| 77 | private: | ||
| 78 | NpadStatus status{}; | ||
| 79 | Core::HID::NpadStyleSet supported_npad_style_set{Core::HID::NpadStyleSet::All}; | ||
| 80 | NpadJoyHoldType npad_hold_type{NpadJoyHoldType::Vertical}; | ||
| 81 | NpadHandheldActivationMode handheld_activation_mode{}; | ||
| 82 | std::array<Core::HID::NpadIdType, MaxSupportedNpadIdTypes> supported_npad_id_types{}; | ||
| 83 | std::array<Core::HID::NpadButton, StyleIndexCount> npad_button_assignment{}; | ||
| 84 | std::size_t supported_npad_id_types_count{}; | ||
| 85 | std::array<bool, MaxSupportedNpadIdTypes> is_unintended_home_button_input_protection{}; | ||
| 86 | }; | ||
| 87 | |||
| 88 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/hid/controllers/npad/npad_resource.cpp b/src/core/hle/service/hid/controllers/npad/npad_resource.cpp new file mode 100644 index 000000000..0a9341a39 --- /dev/null +++ b/src/core/hle/service/hid/controllers/npad/npad_resource.cpp | |||
| @@ -0,0 +1,685 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/kernel/k_event.h" | ||
| 5 | #include "core/hle/kernel/k_readable_event.h" | ||
| 6 | #include "core/hle/service/hid/controllers/npad/npad_resource.h" | ||
| 7 | #include "core/hle/service/hid/controllers/types/npad_types.h" | ||
| 8 | #include "core/hle/service/hid/errors.h" | ||
| 9 | #include "core/hle/service/hid/hid_util.h" | ||
| 10 | |||
| 11 | namespace Service::HID { | ||
| 12 | |||
| 13 | NPadResource::NPadResource(KernelHelpers::ServiceContext& context) : service_context{context} {} | ||
| 14 | |||
| 15 | NPadResource::~NPadResource() = default; | ||
| 16 | |||
| 17 | Result NPadResource::RegisterAppletResourceUserId(u64 aruid) { | ||
| 18 | const auto aruid_index = GetIndexFromAruid(aruid); | ||
| 19 | if (aruid_index < AruidIndexMax) { | ||
| 20 | return ResultAruidAlreadyRegistered; | ||
| 21 | } | ||
| 22 | |||
| 23 | std::size_t data_index = AruidIndexMax; | ||
| 24 | for (std::size_t i = 0; i < AruidIndexMax; i++) { | ||
| 25 | if (!state[i].flag.is_initialized) { | ||
| 26 | data_index = i; | ||
| 27 | break; | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | if (data_index == AruidIndexMax) { | ||
| 32 | return ResultAruidNoAvailableEntries; | ||
| 33 | } | ||
| 34 | |||
| 35 | auto& aruid_data = state[data_index]; | ||
| 36 | |||
| 37 | aruid_data.aruid = aruid; | ||
| 38 | aruid_data.flag.is_initialized.Assign(true); | ||
| 39 | |||
| 40 | data_index = AruidIndexMax; | ||
| 41 | for (std::size_t i = 0; i < AruidIndexMax; i++) { | ||
| 42 | if (registration_list.flag[i] == RegistrationStatus::Initialized) { | ||
| 43 | if (registration_list.aruid[i] != aruid) { | ||
| 44 | continue; | ||
| 45 | } | ||
| 46 | data_index = i; | ||
| 47 | break; | ||
| 48 | } | ||
| 49 | if (registration_list.flag[i] == RegistrationStatus::None) { | ||
| 50 | data_index = i; | ||
| 51 | break; | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | if (data_index == AruidIndexMax) { | ||
| 56 | return ResultSuccess; | ||
| 57 | } | ||
| 58 | |||
| 59 | registration_list.flag[data_index] = RegistrationStatus::Initialized; | ||
| 60 | registration_list.aruid[data_index] = aruid; | ||
| 61 | |||
| 62 | return ResultSuccess; | ||
| 63 | } | ||
| 64 | |||
| 65 | void NPadResource::UnregisterAppletResourceUserId(u64 aruid) { | ||
| 66 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 67 | |||
| 68 | DestroyStyleSetUpdateEvents(aruid); | ||
| 69 | if (aruid_index < AruidIndexMax) { | ||
| 70 | state[aruid_index] = {}; | ||
| 71 | registration_list.flag[aruid_index] = RegistrationStatus::PendingDelete; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | void NPadResource::DestroyStyleSetUpdateEvents(u64 aruid) { | ||
| 76 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 77 | |||
| 78 | if (aruid_index >= AruidIndexMax) { | ||
| 79 | return; | ||
| 80 | } | ||
| 81 | |||
| 82 | for (auto& controller_state : state[aruid_index].controller_state) { | ||
| 83 | if (!controller_state.is_styleset_update_event_initialized) { | ||
| 84 | continue; | ||
| 85 | } | ||
| 86 | service_context.CloseEvent(controller_state.style_set_update_event); | ||
| 87 | controller_state.is_styleset_update_event_initialized = false; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | Result NPadResource::Activate(u64 aruid) { | ||
| 92 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 93 | |||
| 94 | if (aruid_index >= AruidIndexMax) { | ||
| 95 | return ResultSuccess; | ||
| 96 | } | ||
| 97 | |||
| 98 | auto& state_data = state[aruid_index]; | ||
| 99 | |||
| 100 | if (state_data.flag.is_assigned) { | ||
| 101 | return ResultAruidAlreadyRegistered; | ||
| 102 | } | ||
| 103 | |||
| 104 | state_data.flag.is_assigned.Assign(true); | ||
| 105 | state_data.data.ClearNpadSystemCommonPolicy(); | ||
| 106 | state_data.npad_revision = NpadRevision::Revision0; | ||
| 107 | state_data.button_config = {}; | ||
| 108 | |||
| 109 | if (active_data_aruid == aruid) { | ||
| 110 | default_hold_type = active_data.GetNpadJoyHoldType(); | ||
| 111 | active_data.SetNpadJoyHoldType(default_hold_type); | ||
| 112 | } | ||
| 113 | return ResultSuccess; | ||
| 114 | } | ||
| 115 | |||
| 116 | Result NPadResource::Activate() { | ||
| 117 | if (ref_counter == std::numeric_limits<s32>::max() - 1) { | ||
| 118 | return ResultAppletResourceOverflow; | ||
| 119 | } | ||
| 120 | if (ref_counter == 0) { | ||
| 121 | RegisterAppletResourceUserId(SystemAruid); | ||
| 122 | Activate(SystemAruid); | ||
| 123 | } | ||
| 124 | ref_counter++; | ||
| 125 | return ResultSuccess; | ||
| 126 | } | ||
| 127 | |||
| 128 | Result NPadResource::Deactivate() { | ||
| 129 | if (ref_counter == 0) { | ||
| 130 | return ResultAppletResourceNotInitialized; | ||
| 131 | } | ||
| 132 | |||
| 133 | UnregisterAppletResourceUserId(SystemAruid); | ||
| 134 | ref_counter--; | ||
| 135 | return ResultSuccess; | ||
| 136 | } | ||
| 137 | |||
| 138 | NPadData* NPadResource::GetActiveData() { | ||
| 139 | return &active_data; | ||
| 140 | } | ||
| 141 | |||
| 142 | u64 NPadResource::GetActiveDataAruid() { | ||
| 143 | return active_data_aruid; | ||
| 144 | } | ||
| 145 | |||
| 146 | void NPadResource::SetAppletResourceUserId(u64 aruid) { | ||
| 147 | if (active_data_aruid == aruid) { | ||
| 148 | return; | ||
| 149 | } | ||
| 150 | |||
| 151 | active_data_aruid = aruid; | ||
| 152 | default_hold_type = active_data.GetNpadJoyHoldType(); | ||
| 153 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 154 | |||
| 155 | if (aruid_index >= AruidIndexMax) { | ||
| 156 | return; | ||
| 157 | } | ||
| 158 | |||
| 159 | auto& data = state[aruid_index].data; | ||
| 160 | if (data.GetNpadStatus().is_policy || data.GetNpadStatus().is_full_policy) { | ||
| 161 | data.SetNpadJoyHoldType(default_hold_type); | ||
| 162 | } | ||
| 163 | |||
| 164 | active_data = data; | ||
| 165 | if (data.GetNpadStatus().is_hold_type_set) { | ||
| 166 | active_data.SetNpadJoyHoldType(default_hold_type); | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | std::size_t NPadResource::GetIndexFromAruid(u64 aruid) const { | ||
| 171 | for (std::size_t i = 0; i < AruidIndexMax; i++) { | ||
| 172 | if (registration_list.flag[i] == RegistrationStatus::Initialized && | ||
| 173 | registration_list.aruid[i] == aruid) { | ||
| 174 | return i; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | return AruidIndexMax; | ||
| 178 | } | ||
| 179 | |||
| 180 | Result NPadResource::ApplyNpadSystemCommonPolicy(u64 aruid, bool is_full_policy) { | ||
| 181 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 182 | if (aruid_index >= AruidIndexMax) { | ||
| 183 | return ResultNpadNotConnected; | ||
| 184 | } | ||
| 185 | |||
| 186 | auto& data = state[aruid_index].data; | ||
| 187 | data.SetNpadSystemCommonPolicy(is_full_policy); | ||
| 188 | data.SetNpadJoyHoldType(default_hold_type); | ||
| 189 | if (active_data_aruid == aruid) { | ||
| 190 | active_data.SetNpadSystemCommonPolicy(is_full_policy); | ||
| 191 | active_data.SetNpadJoyHoldType(default_hold_type); | ||
| 192 | } | ||
| 193 | return ResultSuccess; | ||
| 194 | } | ||
| 195 | |||
| 196 | Result NPadResource::ClearNpadSystemCommonPolicy(u64 aruid) { | ||
| 197 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 198 | if (aruid_index >= AruidIndexMax) { | ||
| 199 | return ResultNpadNotConnected; | ||
| 200 | } | ||
| 201 | |||
| 202 | state[aruid_index].data.ClearNpadSystemCommonPolicy(); | ||
| 203 | if (active_data_aruid == aruid) { | ||
| 204 | active_data.ClearNpadSystemCommonPolicy(); | ||
| 205 | } | ||
| 206 | return ResultSuccess; | ||
| 207 | } | ||
| 208 | |||
| 209 | Result NPadResource::SetSupportedNpadStyleSet(u64 aruid, Core::HID::NpadStyleSet style_set) { | ||
| 210 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 211 | if (aruid_index >= AruidIndexMax) { | ||
| 212 | return ResultNpadNotConnected; | ||
| 213 | } | ||
| 214 | |||
| 215 | auto& data = state[aruid_index].data; | ||
| 216 | data.SetSupportedNpadStyleSet(style_set); | ||
| 217 | if (active_data_aruid == aruid) { | ||
| 218 | active_data.SetSupportedNpadStyleSet(style_set); | ||
| 219 | active_data.SetNpadJoyHoldType(data.GetNpadJoyHoldType()); | ||
| 220 | } | ||
| 221 | return ResultSuccess; | ||
| 222 | } | ||
| 223 | |||
| 224 | Result NPadResource::GetSupportedNpadStyleSet(Core::HID::NpadStyleSet& out_style_Set, | ||
| 225 | u64 aruid) const { | ||
| 226 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 227 | if (aruid_index >= AruidIndexMax) { | ||
| 228 | return ResultNpadNotConnected; | ||
| 229 | } | ||
| 230 | |||
| 231 | auto& data = state[aruid_index].data; | ||
| 232 | if (!data.GetNpadStatus().is_supported_styleset_set) { | ||
| 233 | return ResultUndefinedStyleset; | ||
| 234 | } | ||
| 235 | |||
| 236 | out_style_Set = data.GetSupportedNpadStyleSet(); | ||
| 237 | return ResultSuccess; | ||
| 238 | } | ||
| 239 | |||
| 240 | Result NPadResource::GetMaskedSupportedNpadStyleSet(Core::HID::NpadStyleSet& out_style_set, | ||
| 241 | u64 aruid) const { | ||
| 242 | if (aruid == SystemAruid) { | ||
| 243 | out_style_set = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld | | ||
| 244 | Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft | | ||
| 245 | Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Palma | | ||
| 246 | Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System; | ||
| 247 | return ResultSuccess; | ||
| 248 | } | ||
| 249 | |||
| 250 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 251 | if (aruid_index >= AruidIndexMax) { | ||
| 252 | return ResultNpadNotConnected; | ||
| 253 | } | ||
| 254 | |||
| 255 | auto& data = state[aruid_index].data; | ||
| 256 | if (!data.GetNpadStatus().is_supported_styleset_set) { | ||
| 257 | return ResultUndefinedStyleset; | ||
| 258 | } | ||
| 259 | |||
| 260 | Core::HID::NpadStyleSet mask{Core::HID::NpadStyleSet::None}; | ||
| 261 | out_style_set = data.GetSupportedNpadStyleSet(); | ||
| 262 | |||
| 263 | switch (state[aruid_index].npad_revision) { | ||
| 264 | case NpadRevision::Revision1: | ||
| 265 | mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld | | ||
| 266 | Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft | | ||
| 267 | Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc | | ||
| 268 | Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::SystemExt | | ||
| 269 | Core::HID::NpadStyleSet::System; | ||
| 270 | break; | ||
| 271 | case NpadRevision::Revision2: | ||
| 272 | mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld | | ||
| 273 | Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft | | ||
| 274 | Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc | | ||
| 275 | Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::Lark | | ||
| 276 | Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System; | ||
| 277 | break; | ||
| 278 | case NpadRevision::Revision3: | ||
| 279 | mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld | | ||
| 280 | Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft | | ||
| 281 | Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc | | ||
| 282 | Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::Lark | | ||
| 283 | Core::HID::NpadStyleSet::HandheldLark | Core::HID::NpadStyleSet::Lucia | | ||
| 284 | Core::HID::NpadStyleSet::Lagoon | Core::HID::NpadStyleSet::Lager | | ||
| 285 | Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System; | ||
| 286 | break; | ||
| 287 | default: | ||
| 288 | mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld | | ||
| 289 | Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft | | ||
| 290 | Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::SystemExt | | ||
| 291 | Core::HID::NpadStyleSet::System; | ||
| 292 | break; | ||
| 293 | } | ||
| 294 | |||
| 295 | out_style_set = out_style_set & mask; | ||
| 296 | return ResultSuccess; | ||
| 297 | } | ||
| 298 | |||
| 299 | Result NPadResource::GetAvailableStyleset(Core::HID::NpadStyleSet& out_style_set, u64 aruid) const { | ||
| 300 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 301 | if (aruid_index >= AruidIndexMax) { | ||
| 302 | return ResultNpadNotConnected; | ||
| 303 | } | ||
| 304 | |||
| 305 | auto& data = state[aruid_index].data; | ||
| 306 | if (!data.GetNpadStatus().is_supported_styleset_set) { | ||
| 307 | return ResultUndefinedStyleset; | ||
| 308 | } | ||
| 309 | |||
| 310 | Core::HID::NpadStyleSet mask{Core::HID::NpadStyleSet::None}; | ||
| 311 | out_style_set = data.GetSupportedNpadStyleSet(); | ||
| 312 | |||
| 313 | switch (state[aruid_index].npad_revision) { | ||
| 314 | case NpadRevision::Revision1: | ||
| 315 | mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld | | ||
| 316 | Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft | | ||
| 317 | Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc | | ||
| 318 | Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::SystemExt | | ||
| 319 | Core::HID::NpadStyleSet::System; | ||
| 320 | break; | ||
| 321 | case NpadRevision::Revision2: | ||
| 322 | mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld | | ||
| 323 | Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft | | ||
| 324 | Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc | | ||
| 325 | Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::Lark | | ||
| 326 | Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System; | ||
| 327 | break; | ||
| 328 | case NpadRevision::Revision3: | ||
| 329 | mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld | | ||
| 330 | Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft | | ||
| 331 | Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::Gc | | ||
| 332 | Core::HID::NpadStyleSet::Palma | Core::HID::NpadStyleSet::Lark | | ||
| 333 | Core::HID::NpadStyleSet::HandheldLark | Core::HID::NpadStyleSet::Lucia | | ||
| 334 | Core::HID::NpadStyleSet::Lagoon | Core::HID::NpadStyleSet::Lager | | ||
| 335 | Core::HID::NpadStyleSet::SystemExt | Core::HID::NpadStyleSet::System; | ||
| 336 | break; | ||
| 337 | default: | ||
| 338 | mask = Core::HID::NpadStyleSet::Fullkey | Core::HID::NpadStyleSet::Handheld | | ||
| 339 | Core::HID::NpadStyleSet::JoyDual | Core::HID::NpadStyleSet::JoyLeft | | ||
| 340 | Core::HID::NpadStyleSet::JoyRight | Core::HID::NpadStyleSet::SystemExt | | ||
| 341 | Core::HID::NpadStyleSet::System; | ||
| 342 | break; | ||
| 343 | } | ||
| 344 | |||
| 345 | out_style_set = out_style_set & mask; | ||
| 346 | return ResultSuccess; | ||
| 347 | } | ||
| 348 | |||
| 349 | NpadRevision NPadResource::GetNpadRevision(u64 aruid) const { | ||
| 350 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 351 | if (aruid_index >= AruidIndexMax) { | ||
| 352 | return NpadRevision::Revision0; | ||
| 353 | } | ||
| 354 | |||
| 355 | return state[aruid_index].npad_revision; | ||
| 356 | } | ||
| 357 | |||
| 358 | Result NPadResource::IsSupportedNpadStyleSet(bool& is_set, u64 aruid) { | ||
| 359 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 360 | if (aruid_index >= AruidIndexMax) { | ||
| 361 | return ResultNpadNotConnected; | ||
| 362 | } | ||
| 363 | |||
| 364 | is_set = state[aruid_index].data.GetNpadStatus().is_supported_styleset_set.Value() != 0; | ||
| 365 | return ResultSuccess; | ||
| 366 | } | ||
| 367 | |||
| 368 | Result NPadResource::SetNpadJoyHoldType(u64 aruid, NpadJoyHoldType hold_type) { | ||
| 369 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 370 | if (aruid_index >= AruidIndexMax) { | ||
| 371 | return ResultNpadNotConnected; | ||
| 372 | } | ||
| 373 | |||
| 374 | state[aruid_index].data.SetNpadJoyHoldType(hold_type); | ||
| 375 | if (active_data_aruid == aruid) { | ||
| 376 | active_data.SetNpadJoyHoldType(hold_type); | ||
| 377 | } | ||
| 378 | return ResultSuccess; | ||
| 379 | } | ||
| 380 | |||
| 381 | Result NPadResource::GetNpadJoyHoldType(NpadJoyHoldType& hold_type, u64 aruid) const { | ||
| 382 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 383 | if (aruid_index >= AruidIndexMax) { | ||
| 384 | return ResultNpadNotConnected; | ||
| 385 | } | ||
| 386 | |||
| 387 | auto& data = state[aruid_index].data; | ||
| 388 | if (data.GetNpadStatus().is_policy || data.GetNpadStatus().is_full_policy) { | ||
| 389 | hold_type = active_data.GetNpadJoyHoldType(); | ||
| 390 | return ResultSuccess; | ||
| 391 | } | ||
| 392 | hold_type = data.GetNpadJoyHoldType(); | ||
| 393 | return ResultSuccess; | ||
| 394 | } | ||
| 395 | |||
| 396 | Result NPadResource::SetNpadHandheldActivationMode(u64 aruid, | ||
| 397 | NpadHandheldActivationMode activation_mode) { | ||
| 398 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 399 | if (aruid_index >= AruidIndexMax) { | ||
| 400 | return ResultNpadNotConnected; | ||
| 401 | } | ||
| 402 | |||
| 403 | state[aruid_index].data.SetHandheldActivationMode(activation_mode); | ||
| 404 | if (active_data_aruid == aruid) { | ||
| 405 | active_data.SetHandheldActivationMode(activation_mode); | ||
| 406 | } | ||
| 407 | return ResultSuccess; | ||
| 408 | } | ||
| 409 | |||
| 410 | Result NPadResource::GetNpadHandheldActivationMode(NpadHandheldActivationMode& activation_mode, | ||
| 411 | u64 aruid) const { | ||
| 412 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 413 | if (aruid_index >= AruidIndexMax) { | ||
| 414 | return ResultNpadNotConnected; | ||
| 415 | } | ||
| 416 | |||
| 417 | activation_mode = state[aruid_index].data.GetHandheldActivationMode(); | ||
| 418 | return ResultSuccess; | ||
| 419 | } | ||
| 420 | |||
| 421 | Result NPadResource::SetSupportedNpadIdType( | ||
| 422 | u64 aruid, std::span<const Core::HID::NpadIdType> supported_npad_list) { | ||
| 423 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 424 | if (aruid_index >= AruidIndexMax) { | ||
| 425 | return ResultNpadNotConnected; | ||
| 426 | } | ||
| 427 | if (supported_npad_list.size() > MaxSupportedNpadIdTypes) { | ||
| 428 | return ResultInvalidArraySize; | ||
| 429 | } | ||
| 430 | |||
| 431 | Result result = state[aruid_index].data.SetSupportedNpadIdType(supported_npad_list); | ||
| 432 | if (result.IsSuccess() && active_data_aruid == aruid) { | ||
| 433 | result = active_data.SetSupportedNpadIdType(supported_npad_list); | ||
| 434 | } | ||
| 435 | |||
| 436 | return result; | ||
| 437 | } | ||
| 438 | |||
| 439 | bool NPadResource::IsControllerSupported(u64 aruid, Core::HID::NpadStyleIndex style_index) const { | ||
| 440 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 441 | if (aruid_index >= AruidIndexMax) { | ||
| 442 | return false; | ||
| 443 | } | ||
| 444 | return state[aruid_index].data.IsNpadStyleIndexSupported(style_index); | ||
| 445 | } | ||
| 446 | |||
| 447 | Result NPadResource::SetLrAssignmentMode(u64 aruid, bool is_enabled) { | ||
| 448 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 449 | if (aruid_index >= AruidIndexMax) { | ||
| 450 | return ResultNpadNotConnected; | ||
| 451 | } | ||
| 452 | |||
| 453 | state[aruid_index].data.SetLrAssignmentMode(is_enabled); | ||
| 454 | if (active_data_aruid == aruid) { | ||
| 455 | active_data.SetLrAssignmentMode(is_enabled); | ||
| 456 | } | ||
| 457 | return ResultSuccess; | ||
| 458 | } | ||
| 459 | |||
| 460 | Result NPadResource::GetLrAssignmentMode(bool& is_enabled, u64 aruid) const { | ||
| 461 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 462 | if (aruid_index >= AruidIndexMax) { | ||
| 463 | return ResultNpadNotConnected; | ||
| 464 | } | ||
| 465 | |||
| 466 | is_enabled = state[aruid_index].data.GetLrAssignmentMode(); | ||
| 467 | return ResultSuccess; | ||
| 468 | } | ||
| 469 | |||
| 470 | Result NPadResource::SetAssigningSingleOnSlSrPress(u64 aruid, bool is_enabled) { | ||
| 471 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 472 | if (aruid_index >= AruidIndexMax) { | ||
| 473 | return ResultNpadNotConnected; | ||
| 474 | } | ||
| 475 | |||
| 476 | state[aruid_index].data.SetAssigningSingleOnSlSrPress(is_enabled); | ||
| 477 | if (active_data_aruid == aruid) { | ||
| 478 | active_data.SetAssigningSingleOnSlSrPress(is_enabled); | ||
| 479 | } | ||
| 480 | return ResultSuccess; | ||
| 481 | } | ||
| 482 | |||
| 483 | Result NPadResource::IsAssigningSingleOnSlSrPressEnabled(bool& is_enabled, u64 aruid) const { | ||
| 484 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 485 | if (aruid_index >= AruidIndexMax) { | ||
| 486 | return ResultNpadNotConnected; | ||
| 487 | } | ||
| 488 | |||
| 489 | is_enabled = state[aruid_index].data.GetAssigningSingleOnSlSrPress(); | ||
| 490 | return ResultSuccess; | ||
| 491 | } | ||
| 492 | |||
| 493 | Result NPadResource::AcquireNpadStyleSetUpdateEventHandle(u64 aruid, | ||
| 494 | Kernel::KReadableEvent** out_event, | ||
| 495 | Core::HID::NpadIdType npad_id) { | ||
| 496 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 497 | if (aruid_index >= AruidIndexMax) { | ||
| 498 | return ResultNpadNotConnected; | ||
| 499 | } | ||
| 500 | |||
| 501 | auto& controller_state = state[aruid_index].controller_state[NpadIdTypeToIndex(npad_id)]; | ||
| 502 | if (!controller_state.is_styleset_update_event_initialized) { | ||
| 503 | // Auto clear = true | ||
| 504 | controller_state.style_set_update_event = | ||
| 505 | service_context.CreateEvent("NpadResource:StylesetUpdateEvent"); | ||
| 506 | |||
| 507 | // Assume creating the event succeeds otherwise crash the system here | ||
| 508 | controller_state.is_styleset_update_event_initialized = true; | ||
| 509 | } | ||
| 510 | |||
| 511 | *out_event = &controller_state.style_set_update_event->GetReadableEvent(); | ||
| 512 | |||
| 513 | if (controller_state.is_styleset_update_event_initialized) { | ||
| 514 | controller_state.style_set_update_event->Signal(); | ||
| 515 | } | ||
| 516 | |||
| 517 | return ResultSuccess; | ||
| 518 | } | ||
| 519 | |||
| 520 | Result NPadResource::SignalStyleSetUpdateEvent(u64 aruid, Core::HID::NpadIdType npad_id) { | ||
| 521 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 522 | if (aruid_index >= AruidIndexMax) { | ||
| 523 | return ResultNpadNotConnected; | ||
| 524 | } | ||
| 525 | auto controller = state[aruid_index].controller_state[NpadIdTypeToIndex(npad_id)]; | ||
| 526 | if (controller.is_styleset_update_event_initialized) { | ||
| 527 | controller.style_set_update_event->Signal(); | ||
| 528 | } | ||
| 529 | return ResultSuccess; | ||
| 530 | } | ||
| 531 | |||
| 532 | Result NPadResource::GetHomeProtectionEnabled(bool& is_enabled, u64 aruid, | ||
| 533 | Core::HID::NpadIdType npad_id) const { | ||
| 534 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 535 | if (aruid_index >= AruidIndexMax) { | ||
| 536 | return ResultNpadNotConnected; | ||
| 537 | } | ||
| 538 | |||
| 539 | is_enabled = state[aruid_index].data.GetHomeProtectionEnabled(npad_id); | ||
| 540 | return ResultSuccess; | ||
| 541 | } | ||
| 542 | |||
| 543 | Result NPadResource::SetHomeProtectionEnabled(u64 aruid, Core::HID::NpadIdType npad_id, | ||
| 544 | bool is_enabled) { | ||
| 545 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 546 | if (aruid_index >= AruidIndexMax) { | ||
| 547 | return ResultNpadNotConnected; | ||
| 548 | } | ||
| 549 | |||
| 550 | state[aruid_index].data.SetHomeProtectionEnabled(is_enabled, npad_id); | ||
| 551 | if (active_data_aruid == aruid) { | ||
| 552 | active_data.SetHomeProtectionEnabled(is_enabled, npad_id); | ||
| 553 | } | ||
| 554 | return ResultSuccess; | ||
| 555 | } | ||
| 556 | |||
| 557 | Result NPadResource::SetNpadAnalogStickUseCenterClamp(u64 aruid, bool is_enabled) { | ||
| 558 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 559 | if (aruid_index >= AruidIndexMax) { | ||
| 560 | return ResultNpadNotConnected; | ||
| 561 | } | ||
| 562 | |||
| 563 | state[aruid_index].data.SetNpadAnalogStickUseCenterClamp(is_enabled); | ||
| 564 | if (active_data_aruid == aruid) { | ||
| 565 | active_data.SetNpadAnalogStickUseCenterClamp(is_enabled); | ||
| 566 | } | ||
| 567 | return ResultSuccess; | ||
| 568 | } | ||
| 569 | |||
| 570 | Result NPadResource::SetButtonConfig(u64 aruid, Core::HID::NpadIdType npad_id, std::size_t index, | ||
| 571 | Core::HID::NpadButton button_config) { | ||
| 572 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 573 | if (aruid_index >= AruidIndexMax) { | ||
| 574 | return ResultNpadNotConnected; | ||
| 575 | } | ||
| 576 | |||
| 577 | state[aruid_index].button_config[NpadIdTypeToIndex(npad_id)][index] = button_config; | ||
| 578 | return ResultSuccess; | ||
| 579 | } | ||
| 580 | |||
| 581 | Core::HID::NpadButton NPadResource::GetButtonConfig(u64 aruid, Core::HID::NpadIdType npad_id, | ||
| 582 | std::size_t index, Core::HID::NpadButton mask, | ||
| 583 | bool is_enabled) { | ||
| 584 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 585 | if (aruid_index >= AruidIndexMax) { | ||
| 586 | return Core::HID::NpadButton::None; | ||
| 587 | } | ||
| 588 | |||
| 589 | auto& button_config = state[aruid_index].button_config[NpadIdTypeToIndex(npad_id)][index]; | ||
| 590 | if (is_enabled) { | ||
| 591 | button_config = button_config | mask; | ||
| 592 | return button_config; | ||
| 593 | } | ||
| 594 | |||
| 595 | button_config = Core::HID::NpadButton::None; | ||
| 596 | return Core::HID::NpadButton::None; | ||
| 597 | } | ||
| 598 | |||
| 599 | void NPadResource::ResetButtonConfig() { | ||
| 600 | for (auto& selected_state : state) { | ||
| 601 | selected_state.button_config = {}; | ||
| 602 | } | ||
| 603 | } | ||
| 604 | |||
| 605 | Result NPadResource::SetNpadCaptureButtonAssignment(u64 aruid, | ||
| 606 | Core::HID::NpadStyleSet npad_style_set, | ||
| 607 | Core::HID::NpadButton button_assignment) { | ||
| 608 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 609 | if (aruid_index >= AruidIndexMax) { | ||
| 610 | return ResultNpadNotConnected; | ||
| 611 | } | ||
| 612 | |||
| 613 | // Must be a power of two | ||
| 614 | const auto raw_styleset = static_cast<u32>(npad_style_set); | ||
| 615 | if (raw_styleset == 0 && (raw_styleset & (raw_styleset - 1)) != 0) { | ||
| 616 | return ResultMultipleStyleSetSelected; | ||
| 617 | } | ||
| 618 | |||
| 619 | std::size_t style_index{}; | ||
| 620 | Core::HID::NpadStyleSet style_selected{}; | ||
| 621 | for (style_index = 0; style_index < StyleIndexCount; ++style_index) { | ||
| 622 | style_selected = GetStylesetByIndex(style_index); | ||
| 623 | if (npad_style_set == style_selected) { | ||
| 624 | break; | ||
| 625 | } | ||
| 626 | } | ||
| 627 | |||
| 628 | if (style_selected == Core::HID::NpadStyleSet::None) { | ||
| 629 | return ResultMultipleStyleSetSelected; | ||
| 630 | } | ||
| 631 | |||
| 632 | state[aruid_index].data.SetCaptureButtonAssignment(button_assignment, style_index); | ||
| 633 | if (active_data_aruid == aruid) { | ||
| 634 | active_data.SetCaptureButtonAssignment(button_assignment, style_index); | ||
| 635 | } | ||
| 636 | return ResultSuccess; | ||
| 637 | } | ||
| 638 | |||
| 639 | Result NPadResource::ClearNpadCaptureButtonAssignment(u64 aruid) { | ||
| 640 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 641 | if (aruid_index >= AruidIndexMax) { | ||
| 642 | return ResultNpadNotConnected; | ||
| 643 | } | ||
| 644 | |||
| 645 | for (std::size_t i = 0; i < StyleIndexCount; i++) { | ||
| 646 | state[aruid_index].data.SetCaptureButtonAssignment(Core::HID::NpadButton::None, i); | ||
| 647 | if (active_data_aruid == aruid) { | ||
| 648 | active_data.SetCaptureButtonAssignment(Core::HID::NpadButton::None, i); | ||
| 649 | } | ||
| 650 | } | ||
| 651 | return ResultSuccess; | ||
| 652 | } | ||
| 653 | |||
| 654 | std::size_t NPadResource::GetNpadCaptureButtonAssignment(std::span<Core::HID::NpadButton> out_list, | ||
| 655 | u64 aruid) const { | ||
| 656 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 657 | if (aruid_index >= AruidIndexMax) { | ||
| 658 | return 0; | ||
| 659 | } | ||
| 660 | return state[aruid_index].data.GetNpadCaptureButtonAssignmentList(out_list); | ||
| 661 | } | ||
| 662 | |||
| 663 | void NPadResource::SetNpadRevision(u64 aruid, NpadRevision revision) { | ||
| 664 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 665 | if (aruid_index >= AruidIndexMax) { | ||
| 666 | return; | ||
| 667 | } | ||
| 668 | |||
| 669 | state[aruid_index].npad_revision = revision; | ||
| 670 | } | ||
| 671 | |||
| 672 | Result NPadResource::SetNpadSystemExtStateEnabled(u64 aruid, bool is_enabled) { | ||
| 673 | const u64 aruid_index = GetIndexFromAruid(aruid); | ||
| 674 | if (aruid_index >= AruidIndexMax) { | ||
| 675 | return ResultNpadNotConnected; | ||
| 676 | } | ||
| 677 | |||
| 678 | state[aruid_index].data.SetNpadAnalogStickUseCenterClamp(is_enabled); | ||
| 679 | if (active_data_aruid == aruid) { | ||
| 680 | active_data.SetNpadAnalogStickUseCenterClamp(is_enabled); | ||
| 681 | } | ||
| 682 | return ResultSuccess; | ||
| 683 | } | ||
| 684 | |||
| 685 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/hid/controllers/npad/npad_resource.h b/src/core/hle/service/hid/controllers/npad/npad_resource.h new file mode 100644 index 000000000..4c7e6ab0e --- /dev/null +++ b/src/core/hle/service/hid/controllers/npad/npad_resource.h | |||
| @@ -0,0 +1,132 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | #include <mutex> | ||
| 8 | #include <span> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "core/hid/hid_types.h" | ||
| 12 | #include "core/hle/result.h" | ||
| 13 | #include "core/hle/service/hid/controllers/applet_resource.h" | ||
| 14 | #include "core/hle/service/hid/controllers/npad/npad_data.h" | ||
| 15 | #include "core/hle/service/hid/controllers/types/npad_types.h" | ||
| 16 | #include "core/hle/service/kernel_helpers.h" | ||
| 17 | |||
| 18 | namespace Core { | ||
| 19 | class System; | ||
| 20 | } | ||
| 21 | |||
| 22 | namespace Kernel { | ||
| 23 | class KReadableEvent; | ||
| 24 | } | ||
| 25 | |||
| 26 | namespace Service::HID { | ||
| 27 | struct DataStatusFlag; | ||
| 28 | |||
| 29 | struct NpadControllerState { | ||
| 30 | bool is_styleset_update_event_initialized{}; | ||
| 31 | INSERT_PADDING_BYTES(0x7); | ||
| 32 | Kernel::KEvent* style_set_update_event{nullptr}; | ||
| 33 | INSERT_PADDING_BYTES(0x27); | ||
| 34 | }; | ||
| 35 | |||
| 36 | struct NpadState { | ||
| 37 | DataStatusFlag flag{}; | ||
| 38 | u64 aruid{}; | ||
| 39 | NPadData data{}; | ||
| 40 | std::array<std::array<Core::HID::NpadButton, StyleIndexCount>, MaxSupportedNpadIdTypes> | ||
| 41 | button_config; | ||
| 42 | std::array<NpadControllerState, MaxSupportedNpadIdTypes> controller_state; | ||
| 43 | NpadRevision npad_revision; | ||
| 44 | }; | ||
| 45 | |||
| 46 | /// Handles Npad request from HID interfaces | ||
| 47 | class NPadResource final { | ||
| 48 | public: | ||
| 49 | explicit NPadResource(KernelHelpers::ServiceContext& context); | ||
| 50 | ~NPadResource(); | ||
| 51 | |||
| 52 | NPadData* GetActiveData(); | ||
| 53 | u64 GetActiveDataAruid(); | ||
| 54 | |||
| 55 | Result RegisterAppletResourceUserId(u64 aruid); | ||
| 56 | void UnregisterAppletResourceUserId(u64 aruid); | ||
| 57 | |||
| 58 | void DestroyStyleSetUpdateEvents(u64 aruid); | ||
| 59 | |||
| 60 | Result Activate(u64 aruid); | ||
| 61 | Result Activate(); | ||
| 62 | Result Deactivate(); | ||
| 63 | |||
| 64 | void SetAppletResourceUserId(u64 aruid); | ||
| 65 | std::size_t GetIndexFromAruid(u64 aruid) const; | ||
| 66 | |||
| 67 | Result ApplyNpadSystemCommonPolicy(u64 aruid, bool is_full_policy); | ||
| 68 | Result ClearNpadSystemCommonPolicy(u64 aruid); | ||
| 69 | |||
| 70 | Result SetSupportedNpadStyleSet(u64 aruid, Core::HID::NpadStyleSet style_set); | ||
| 71 | Result GetSupportedNpadStyleSet(Core::HID::NpadStyleSet& out_style_Set, u64 aruid) const; | ||
| 72 | Result GetMaskedSupportedNpadStyleSet(Core::HID::NpadStyleSet& out_style_set, u64 aruid) const; | ||
| 73 | Result GetAvailableStyleset(Core::HID::NpadStyleSet& out_style_set, u64 aruid) const; | ||
| 74 | |||
| 75 | NpadRevision GetNpadRevision(u64 aruid) const; | ||
| 76 | void SetNpadRevision(u64 aruid, NpadRevision revision); | ||
| 77 | |||
| 78 | Result IsSupportedNpadStyleSet(bool& is_set, u64 aruid); | ||
| 79 | |||
| 80 | Result SetNpadJoyHoldType(u64 aruid, NpadJoyHoldType hold_type); | ||
| 81 | Result GetNpadJoyHoldType(NpadJoyHoldType& hold_type, u64 aruid) const; | ||
| 82 | |||
| 83 | Result SetNpadHandheldActivationMode(u64 aruid, NpadHandheldActivationMode activation_mode); | ||
| 84 | Result GetNpadHandheldActivationMode(NpadHandheldActivationMode& activation_mode, | ||
| 85 | u64 aruid) const; | ||
| 86 | |||
| 87 | Result SetSupportedNpadIdType(u64 aruid, | ||
| 88 | std::span<const Core::HID::NpadIdType> supported_npad_list); | ||
| 89 | bool IsControllerSupported(u64 aruid, Core::HID::NpadStyleIndex style_index) const; | ||
| 90 | |||
| 91 | Result SetLrAssignmentMode(u64 aruid, bool is_enabled); | ||
| 92 | Result GetLrAssignmentMode(bool& is_enabled, u64 aruid) const; | ||
| 93 | |||
| 94 | Result SetAssigningSingleOnSlSrPress(u64 aruid, bool is_enabled); | ||
| 95 | Result IsAssigningSingleOnSlSrPressEnabled(bool& is_enabled, u64 aruid) const; | ||
| 96 | |||
| 97 | Result AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event, | ||
| 98 | Core::HID::NpadIdType npad_id); | ||
| 99 | Result SignalStyleSetUpdateEvent(u64 aruid, Core::HID::NpadIdType npad_id); | ||
| 100 | |||
| 101 | Result GetHomeProtectionEnabled(bool& is_enabled, u64 aruid, | ||
| 102 | Core::HID::NpadIdType npad_id) const; | ||
| 103 | Result SetHomeProtectionEnabled(u64 aruid, Core::HID::NpadIdType npad_id, bool is_enabled); | ||
| 104 | |||
| 105 | Result SetNpadAnalogStickUseCenterClamp(u64 aruid, bool is_enabled); | ||
| 106 | |||
| 107 | Result SetButtonConfig(u64 aruid, Core::HID::NpadIdType npad_id, std::size_t index, | ||
| 108 | Core::HID::NpadButton button_config); | ||
| 109 | Core::HID::NpadButton GetButtonConfig(u64 aruid, Core::HID::NpadIdType npad_id, | ||
| 110 | std::size_t index, Core::HID::NpadButton mask, | ||
| 111 | bool is_enabled); | ||
| 112 | void ResetButtonConfig(); | ||
| 113 | |||
| 114 | Result SetNpadCaptureButtonAssignment(u64 aruid, Core::HID::NpadStyleSet npad_style_set, | ||
| 115 | Core::HID::NpadButton button_assignment); | ||
| 116 | Result ClearNpadCaptureButtonAssignment(u64 aruid); | ||
| 117 | std::size_t GetNpadCaptureButtonAssignment(std::span<Core::HID::NpadButton> out_list, | ||
| 118 | u64 aruid) const; | ||
| 119 | |||
| 120 | Result SetNpadSystemExtStateEnabled(u64 aruid, bool is_enabled); | ||
| 121 | |||
| 122 | private: | ||
| 123 | NPadData active_data{}; | ||
| 124 | AruidRegisterList registration_list{}; | ||
| 125 | std::array<NpadState, AruidIndexMax> state{}; | ||
| 126 | u64 active_data_aruid{}; | ||
| 127 | NpadJoyHoldType default_hold_type{}; | ||
| 128 | s32 ref_counter{}; | ||
| 129 | |||
| 130 | KernelHelpers::ServiceContext& service_context; | ||
| 131 | }; | ||
| 132 | } // namespace Service::HID | ||
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..adab60911 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,21 @@ 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 | std::scoped_lock shared_lock{*shared_mutex}; | ||
| 31 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 32 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 33 | |||
| 34 | if (data == nullptr || !data->flag.is_assigned) { | ||
| 35 | return; | ||
| 36 | } | ||
| 37 | |||
| 30 | if (!IsControllerActivated()) { | 38 | if (!IsControllerActivated()) { |
| 31 | return; | 39 | return; |
| 32 | } | 40 | } |
| 33 | 41 | ||
| 34 | for (std::size_t i = 0; i < controller_data.size(); ++i) { | 42 | for (std::size_t i = 0; i < controller_data.size(); ++i) { |
| 43 | NpadSharedMemoryEntry& shared_memory = data->shared_memory_format->npad.npad_entry[i]; | ||
| 35 | auto& controller = controller_data[i]; | 44 | auto& controller = controller_data[i]; |
| 36 | |||
| 37 | const auto npad_id = IndexToNpadIdType(i); | ||
| 38 | const auto& controller_type = controller.device->GetNpadStyleIndex(); | 45 | const auto& controller_type = controller.device->GetNpadStyleIndex(); |
| 39 | 46 | ||
| 40 | if (controller_type == Core::HID::NpadStyleIndex::None || | 47 | if (controller_type == Core::HID::NpadStyleIndex::None || |
| @@ -50,12 +57,12 @@ void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | |||
| 50 | auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state; | 57 | auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state; |
| 51 | auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state; | 58 | auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state; |
| 52 | 59 | ||
| 53 | auto& sixaxis_fullkey_lifo = npad->GetSixAxisFullkeyLifo(npad_id); | 60 | auto& sixaxis_fullkey_lifo = shared_memory.internal_state.sixaxis_fullkey_lifo; |
| 54 | auto& sixaxis_handheld_lifo = npad->GetSixAxisHandheldLifo(npad_id); | 61 | auto& sixaxis_handheld_lifo = shared_memory.internal_state.sixaxis_handheld_lifo; |
| 55 | auto& sixaxis_dual_left_lifo = npad->GetSixAxisDualLeftLifo(npad_id); | 62 | auto& sixaxis_dual_left_lifo = shared_memory.internal_state.sixaxis_dual_left_lifo; |
| 56 | auto& sixaxis_dual_right_lifo = npad->GetSixAxisDualRightLifo(npad_id); | 63 | auto& sixaxis_dual_right_lifo = shared_memory.internal_state.sixaxis_dual_right_lifo; |
| 57 | auto& sixaxis_left_lifo = npad->GetSixAxisLeftLifo(npad_id); | 64 | auto& sixaxis_left_lifo = shared_memory.internal_state.sixaxis_left_lifo; |
| 58 | auto& sixaxis_right_lifo = npad->GetSixAxisRightLifo(npad_id); | 65 | auto& sixaxis_right_lifo = shared_memory.internal_state.sixaxis_right_lifo; |
| 59 | 66 | ||
| 60 | // Clear previous state | 67 | // Clear previous state |
| 61 | sixaxis_fullkey_state = {}; | 68 | 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..d44b1f4cc --- /dev/null +++ b/src/core/hle/service/hid/controllers/sleep_button.cpp | |||
| @@ -0,0 +1,39 @@ | |||
| 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 | std::scoped_lock shared_lock{*shared_mutex}; | ||
| 25 | const u64 aruid = applet_resource->GetActiveAruid(); | ||
| 26 | auto* data = applet_resource->GetAruidData(aruid); | ||
| 27 | |||
| 28 | if (data == nullptr || !data->flag.is_assigned) { | ||
| 29 | return; | ||
| 30 | } | ||
| 31 | |||
| 32 | auto& header = data->shared_memory_format->capture_button.header; | ||
| 33 | header.timestamp = core_timing.GetGlobalTimeNs().count(); | ||
| 34 | header.total_entry_count = 17; | ||
| 35 | header.entry_count = 0; | ||
| 36 | header.last_entry_index = 0; | ||
| 37 | } | ||
| 38 | |||
| 39 | } // 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..b585a5829 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 || !data->flag.is_assigned) { | ||
| 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/types/npad_types.h b/src/core/hle/service/hid/controllers/types/npad_types.h index a5ce2562b..419c33a8c 100644 --- a/src/core/hle/service/hid/controllers/types/npad_types.h +++ b/src/core/hle/service/hid/controllers/types/npad_types.h | |||
| @@ -9,7 +9,8 @@ | |||
| 9 | #include "core/hid/hid_types.h" | 9 | #include "core/hid/hid_types.h" |
| 10 | 10 | ||
| 11 | namespace Service::HID { | 11 | namespace Service::HID { |
| 12 | static constexpr std::size_t NpadCount = 10; | 12 | static constexpr std::size_t MaxSupportedNpadIdTypes = 10; |
| 13 | static constexpr std::size_t StyleIndexCount = 7; | ||
| 13 | 14 | ||
| 14 | // This is nn::hid::NpadJoyHoldType | 15 | // This is nn::hid::NpadJoyHoldType |
| 15 | enum class NpadJoyHoldType : u64 { | 16 | enum class NpadJoyHoldType : u64 { |
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..976043b9c 100644 --- a/src/core/hle/service/hid/controllers/shared_memory_format.h +++ b/src/core/hle/service/hid/controllers/types/shared_memory_format.h | |||
| @@ -171,7 +171,7 @@ static_assert(sizeof(NpadSharedMemoryEntry) == 0x5000, "NpadSharedMemoryEntry is | |||
| 171 | 171 | ||
| 172 | // This is nn::hid::detail::NpadSharedMemoryFormat | 172 | // This is nn::hid::detail::NpadSharedMemoryFormat |
| 173 | struct NpadSharedMemoryFormat { | 173 | struct NpadSharedMemoryFormat { |
| 174 | std::array<NpadSharedMemoryEntry, NpadCount> npad_entry; | 174 | std::array<NpadSharedMemoryEntry, MaxSupportedNpadIdTypes> npad_entry; |
| 175 | }; | 175 | }; |
| 176 | static_assert(sizeof(NpadSharedMemoryFormat) == 0x32000, | 176 | static_assert(sizeof(NpadSharedMemoryFormat) == 0x32000, |
| 177 | "NpadSharedMemoryFormat is an invalid size"); | 177 | "NpadSharedMemoryFormat is an invalid size"); |
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..6c543031d --- /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 || !data->flag.is_assigned) { | ||
| 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/errors.h b/src/core/hle/service/hid/errors.h index 6dc976fe1..bb14aa61e 100644 --- a/src/core/hle/service/hid/errors.h +++ b/src/core/hle/service/hid/errors.h | |||
| @@ -10,15 +10,32 @@ namespace Service::HID { | |||
| 10 | constexpr Result PalmaResultSuccess{ErrorModule::HID, 0}; | 10 | constexpr Result PalmaResultSuccess{ErrorModule::HID, 0}; |
| 11 | constexpr Result NpadInvalidHandle{ErrorModule::HID, 100}; | 11 | constexpr Result NpadInvalidHandle{ErrorModule::HID, 100}; |
| 12 | constexpr Result NpadDeviceIndexOutOfRange{ErrorModule::HID, 107}; | 12 | constexpr Result NpadDeviceIndexOutOfRange{ErrorModule::HID, 107}; |
| 13 | constexpr Result VibrationInvalidStyleIndex{ErrorModule::HID, 122}; | 13 | |
| 14 | constexpr Result VibrationInvalidNpadId{ErrorModule::HID, 123}; | 14 | constexpr Result ResultVibrationNotInitialized{ErrorModule::HID, 121}; |
| 15 | constexpr Result VibrationDeviceIndexOutOfRange{ErrorModule::HID, 124}; | 15 | constexpr Result ResultVibrationInvalidStyleIndex{ErrorModule::HID, 122}; |
| 16 | constexpr Result ResultVibrationInvalidNpadId{ErrorModule::HID, 123}; | ||
| 17 | constexpr Result ResultVibrationDeviceIndexOutOfRange{ErrorModule::HID, 124}; | ||
| 18 | constexpr Result ResultVibrationStrenghtOutOfRange{ErrorModule::HID, 126}; | ||
| 19 | constexpr Result ResultVibrationArraySizeMismatch{ErrorModule::HID, 131}; | ||
| 20 | |||
| 16 | constexpr Result InvalidSixAxisFusionRange{ErrorModule::HID, 423}; | 21 | constexpr Result InvalidSixAxisFusionRange{ErrorModule::HID, 423}; |
| 22 | |||
| 23 | constexpr Result ResultNfcIsNotReady{ErrorModule::HID, 461}; | ||
| 24 | constexpr Result ResultNfcXcdHandleIsNotInitialized{ErrorModule::HID, 464}; | ||
| 25 | constexpr Result ResultIrSensorIsNotReady{ErrorModule::HID, 501}; | ||
| 26 | constexpr Result ResultMcuIsNotReady{ErrorModule::HID, 541}; | ||
| 27 | |||
| 17 | constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601}; | 28 | constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601}; |
| 18 | constexpr Result NpadIsSameType{ErrorModule::HID, 602}; | 29 | constexpr Result NpadIsSameType{ErrorModule::HID, 602}; |
| 19 | constexpr Result InvalidNpadId{ErrorModule::HID, 709}; | 30 | constexpr Result ResultNpadIsNotProController{ErrorModule::HID, 604}; |
| 20 | constexpr Result NpadNotConnected{ErrorModule::HID, 710}; | 31 | |
| 21 | constexpr Result InvalidArraySize{ErrorModule::HID, 715}; | 32 | constexpr Result ResultInvalidNpadId{ErrorModule::HID, 709}; |
| 33 | constexpr Result ResultNpadNotConnected{ErrorModule::HID, 710}; | ||
| 34 | constexpr Result ResultNpadHandlerOverflow{ErrorModule::HID, 711}; | ||
| 35 | constexpr Result ResultNpadHandlerNotInitialized{ErrorModule::HID, 712}; | ||
| 36 | constexpr Result ResultInvalidArraySize{ErrorModule::HID, 715}; | ||
| 37 | constexpr Result ResultUndefinedStyleset{ErrorModule::HID, 716}; | ||
| 38 | constexpr Result ResultMultipleStyleSetSelected{ErrorModule::HID, 717}; | ||
| 22 | 39 | ||
| 23 | constexpr Result ResultAppletResourceOverflow{ErrorModule::HID, 1041}; | 40 | constexpr Result ResultAppletResourceOverflow{ErrorModule::HID, 1041}; |
| 24 | constexpr Result ResultAppletResourceNotInitialized{ErrorModule::HID, 1042}; | 41 | constexpr Result ResultAppletResourceNotInitialized{ErrorModule::HID, 1042}; |
| @@ -27,6 +44,9 @@ constexpr Result ResultAruidNoAvailableEntries{ErrorModule::HID, 1044}; | |||
| 27 | constexpr Result ResultAruidAlreadyRegistered{ErrorModule::HID, 1046}; | 44 | constexpr Result ResultAruidAlreadyRegistered{ErrorModule::HID, 1046}; |
| 28 | constexpr Result ResultAruidNotRegistered{ErrorModule::HID, 1047}; | 45 | constexpr Result ResultAruidNotRegistered{ErrorModule::HID, 1047}; |
| 29 | 46 | ||
| 47 | constexpr Result ResultNpadResourceOverflow{ErrorModule::HID, 2001}; | ||
| 48 | constexpr Result ResultNpadResourceNotInitialized{ErrorModule::HID, 2002}; | ||
| 49 | |||
| 30 | constexpr Result InvalidPalmaHandle{ErrorModule::HID, 3302}; | 50 | constexpr Result InvalidPalmaHandle{ErrorModule::HID, 3302}; |
| 31 | 51 | ||
| 32 | } // namespace Service::HID | 52 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index afbcb019f..bd2873181 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -25,6 +25,7 @@ void LoopProcess(Core::System& system) { | |||
| 25 | // TODO: Remove this hack until this service is emulated properly. | 25 | // TODO: Remove this hack until this service is emulated properly. |
| 26 | const auto process_list = system.Kernel().GetProcessList(); | 26 | const auto process_list = system.Kernel().GetProcessList(); |
| 27 | if (!process_list.empty()) { | 27 | if (!process_list.empty()) { |
| 28 | resouce_manager->Initialize(); | ||
| 28 | resouce_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true); | 29 | resouce_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true); |
| 29 | } | 30 | } |
| 30 | 31 | ||
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp index de24b0401..a953c92b3 100644 --- a/src/core/hle/service/hid/hid_server.cpp +++ b/src/core/hle/service/hid/hid_server.cpp | |||
| @@ -51,7 +51,7 @@ private: | |||
| 51 | IPC::RequestParser rp{ctx}; | 51 | IPC::RequestParser rp{ctx}; |
| 52 | const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; | 52 | const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; |
| 53 | 53 | ||
| 54 | if (resource_manager != nullptr) { | 54 | if (resource_manager != nullptr && resource_manager->GetNpad()) { |
| 55 | resource_manager->GetNpad()->InitializeVibrationDevice(vibration_device_handle); | 55 | resource_manager->GetNpad()->InitializeVibrationDevice(vibration_device_handle); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| @@ -785,8 +785,8 @@ void IHidServer::IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ct | |||
| 785 | 785 | ||
| 786 | bool is_firmware_available{}; | 786 | bool is_firmware_available{}; |
| 787 | auto controller = GetResourceManager()->GetNpad(); | 787 | auto controller = GetResourceManager()->GetNpad(); |
| 788 | controller->IsFirmwareUpdateAvailableForSixAxisSensor(parameters.sixaxis_handle, | 788 | controller->IsFirmwareUpdateAvailableForSixAxisSensor( |
| 789 | is_firmware_available); | 789 | parameters.applet_resource_user_id, parameters.sixaxis_handle, is_firmware_available); |
| 790 | 790 | ||
| 791 | LOG_WARNING( | 791 | LOG_WARNING( |
| 792 | Service_HID, | 792 | Service_HID, |
| @@ -924,8 +924,8 @@ void IHidServer::ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx) | |||
| 924 | const auto parameters{rp.PopRaw<Parameters>()}; | 924 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 925 | 925 | ||
| 926 | auto controller = GetResourceManager()->GetNpad(); | 926 | auto controller = GetResourceManager()->GetNpad(); |
| 927 | const auto result = | 927 | const auto result = controller->ResetIsSixAxisSensorDeviceNewlyAssigned( |
| 928 | controller->ResetIsSixAxisSensorDeviceNewlyAssigned(parameters.sixaxis_handle); | 928 | parameters.applet_resource_user_id, parameters.sixaxis_handle); |
| 929 | 929 | ||
| 930 | LOG_WARNING( | 930 | LOG_WARNING( |
| 931 | Service_HID, | 931 | Service_HID, |
| @@ -970,7 +970,7 @@ void IHidServer::ActivateGesture(HLERequestContext& ctx) { | |||
| 970 | void IHidServer::SetSupportedNpadStyleSet(HLERequestContext& ctx) { | 970 | void IHidServer::SetSupportedNpadStyleSet(HLERequestContext& ctx) { |
| 971 | IPC::RequestParser rp{ctx}; | 971 | IPC::RequestParser rp{ctx}; |
| 972 | struct Parameters { | 972 | struct Parameters { |
| 973 | Core::HID::NpadStyleSet supported_styleset; | 973 | Core::HID::NpadStyleSet supported_style_set; |
| 974 | INSERT_PADDING_WORDS_NOINIT(1); | 974 | INSERT_PADDING_WORDS_NOINIT(1); |
| 975 | u64 applet_resource_user_id; | 975 | u64 applet_resource_user_id; |
| 976 | }; | 976 | }; |
| @@ -978,13 +978,25 @@ void IHidServer::SetSupportedNpadStyleSet(HLERequestContext& ctx) { | |||
| 978 | 978 | ||
| 979 | const auto parameters{rp.PopRaw<Parameters>()}; | 979 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 980 | 980 | ||
| 981 | GetResourceManager()->GetNpad()->SetSupportedStyleSet({parameters.supported_styleset}); | 981 | LOG_DEBUG(Service_HID, "called, supported_style_set={}, applet_resource_user_id={}", |
| 982 | parameters.supported_style_set, parameters.applet_resource_user_id); | ||
| 983 | |||
| 984 | const auto npad = GetResourceManager()->GetNpad(); | ||
| 985 | const Result result = npad->SetSupportedNpadStyleSet(parameters.applet_resource_user_id, | ||
| 986 | parameters.supported_style_set); | ||
| 982 | 987 | ||
| 983 | LOG_DEBUG(Service_HID, "called, supported_styleset={}, applet_resource_user_id={}", | 988 | if (result.IsSuccess()) { |
| 984 | parameters.supported_styleset, parameters.applet_resource_user_id); | 989 | Core::HID::NpadStyleTag style_tag{parameters.supported_style_set}; |
| 990 | const auto revision = npad->GetRevision(parameters.applet_resource_user_id); | ||
| 991 | |||
| 992 | if (style_tag.palma != 0 && revision < NpadRevision::Revision3) { | ||
| 993 | // GetResourceManager()->GetPalma()->EnableBoostMode(parameters.applet_resource_user_id, | ||
| 994 | // true); | ||
| 995 | } | ||
| 996 | } | ||
| 985 | 997 | ||
| 986 | IPC::ResponseBuilder rb{ctx, 2}; | 998 | IPC::ResponseBuilder rb{ctx, 2}; |
| 987 | rb.Push(ResultSuccess); | 999 | rb.Push(result); |
| 988 | } | 1000 | } |
| 989 | 1001 | ||
| 990 | void IHidServer::GetSupportedNpadStyleSet(HLERequestContext& ctx) { | 1002 | void IHidServer::GetSupportedNpadStyleSet(HLERequestContext& ctx) { |
| @@ -993,19 +1005,31 @@ void IHidServer::GetSupportedNpadStyleSet(HLERequestContext& ctx) { | |||
| 993 | 1005 | ||
| 994 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 1006 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 995 | 1007 | ||
| 1008 | Core::HID::NpadStyleSet supported_style_set{}; | ||
| 1009 | const auto npad = GetResourceManager()->GetNpad(); | ||
| 1010 | const auto result = | ||
| 1011 | npad->GetSupportedNpadStyleSet(applet_resource_user_id, supported_style_set); | ||
| 1012 | |||
| 996 | IPC::ResponseBuilder rb{ctx, 3}; | 1013 | IPC::ResponseBuilder rb{ctx, 3}; |
| 997 | rb.Push(ResultSuccess); | 1014 | rb.Push(result); |
| 998 | rb.PushEnum(GetResourceManager()->GetNpad()->GetSupportedStyleSet().raw); | 1015 | rb.PushEnum(supported_style_set); |
| 999 | } | 1016 | } |
| 1000 | 1017 | ||
| 1001 | void IHidServer::SetSupportedNpadIdType(HLERequestContext& ctx) { | 1018 | void IHidServer::SetSupportedNpadIdType(HLERequestContext& ctx) { |
| 1002 | IPC::RequestParser rp{ctx}; | 1019 | IPC::RequestParser rp{ctx}; |
| 1003 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 1020 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 1004 | 1021 | const auto buffer = ctx.ReadBuffer(); | |
| 1005 | const auto result = GetResourceManager()->GetNpad()->SetSupportedNpadIdTypes(ctx.ReadBuffer()); | 1022 | const std::size_t elements = ctx.GetReadBufferNumElements<Core::HID::NpadIdType>(); |
| 1006 | 1023 | ||
| 1007 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 1024 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 1008 | 1025 | ||
| 1026 | std::vector<Core::HID::NpadIdType> supported_npad_list(elements); | ||
| 1027 | memcpy(supported_npad_list.data(), buffer.data(), buffer.size()); | ||
| 1028 | |||
| 1029 | const auto npad = GetResourceManager()->GetNpad(); | ||
| 1030 | const Result result = | ||
| 1031 | npad->SetSupportedNpadIdType(applet_resource_user_id, supported_npad_list); | ||
| 1032 | |||
| 1009 | IPC::ResponseBuilder rb{ctx, 2}; | 1033 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1010 | rb.Push(result); | 1034 | rb.Push(result); |
| 1011 | } | 1035 | } |
| @@ -1018,7 +1042,7 @@ void IHidServer::ActivateNpad(HLERequestContext& ctx) { | |||
| 1018 | 1042 | ||
| 1019 | auto npad = GetResourceManager()->GetNpad(); | 1043 | auto npad = GetResourceManager()->GetNpad(); |
| 1020 | 1044 | ||
| 1021 | // TODO: npad->SetRevision(applet_resource_user_id, NpadRevision::Revision0); | 1045 | npad->SetRevision(applet_resource_user_id, NpadRevision::Revision0); |
| 1022 | const Result result = npad->Activate(applet_resource_user_id); | 1046 | const Result result = npad->Activate(applet_resource_user_id); |
| 1023 | 1047 | ||
| 1024 | IPC::ResponseBuilder rb{ctx, 2}; | 1048 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -1052,13 +1076,13 @@ void IHidServer::AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx) { | |||
| 1052 | LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", | 1076 | LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", |
| 1053 | parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown); | 1077 | parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown); |
| 1054 | 1078 | ||
| 1055 | // Games expect this event to be signaled after calling this function | 1079 | Kernel::KReadableEvent* style_set_update_event; |
| 1056 | GetResourceManager()->GetNpad()->SignalStyleSetChangedEvent(parameters.npad_id); | 1080 | const auto result = GetResourceManager()->GetNpad()->AcquireNpadStyleSetUpdateEventHandle( |
| 1081 | parameters.applet_resource_user_id, &style_set_update_event, parameters.npad_id); | ||
| 1057 | 1082 | ||
| 1058 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 1083 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 1059 | rb.Push(ResultSuccess); | 1084 | rb.Push(result); |
| 1060 | rb.PushCopyObjects( | 1085 | rb.PushCopyObjects(style_set_update_event); |
| 1061 | GetResourceManager()->GetNpad()->GetStyleSetChangedEvent(parameters.npad_id)); | ||
| 1062 | } | 1086 | } |
| 1063 | 1087 | ||
| 1064 | void IHidServer::DisconnectNpad(HLERequestContext& ctx) { | 1088 | void IHidServer::DisconnectNpad(HLERequestContext& ctx) { |
| @@ -1073,7 +1097,7 @@ void IHidServer::DisconnectNpad(HLERequestContext& ctx) { | |||
| 1073 | const auto parameters{rp.PopRaw<Parameters>()}; | 1097 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1074 | 1098 | ||
| 1075 | auto controller = GetResourceManager()->GetNpad(); | 1099 | auto controller = GetResourceManager()->GetNpad(); |
| 1076 | controller->DisconnectNpad(parameters.npad_id); | 1100 | controller->DisconnectNpad(parameters.applet_resource_user_id, parameters.npad_id); |
| 1077 | 1101 | ||
| 1078 | LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, | 1102 | LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, |
| 1079 | parameters.applet_resource_user_id); | 1103 | parameters.applet_resource_user_id); |
| @@ -1113,7 +1137,7 @@ void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) { | |||
| 1113 | 1137 | ||
| 1114 | auto npad = GetResourceManager()->GetNpad(); | 1138 | auto npad = GetResourceManager()->GetNpad(); |
| 1115 | 1139 | ||
| 1116 | // TODO: npad->SetRevision(applet_resource_user_id, revision); | 1140 | npad->SetRevision(parameters.applet_resource_user_id, parameters.revision); |
| 1117 | const auto result = npad->Activate(parameters.applet_resource_user_id); | 1141 | const auto result = npad->Activate(parameters.applet_resource_user_id); |
| 1118 | 1142 | ||
| 1119 | IPC::ResponseBuilder rb{ctx, 2}; | 1143 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -1125,13 +1149,19 @@ void IHidServer::SetNpadJoyHoldType(HLERequestContext& ctx) { | |||
| 1125 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 1149 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 1126 | const auto hold_type{rp.PopEnum<NpadJoyHoldType>()}; | 1150 | const auto hold_type{rp.PopEnum<NpadJoyHoldType>()}; |
| 1127 | 1151 | ||
| 1128 | GetResourceManager()->GetNpad()->SetHoldType(hold_type); | ||
| 1129 | |||
| 1130 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}", | 1152 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}", |
| 1131 | applet_resource_user_id, hold_type); | 1153 | applet_resource_user_id, hold_type); |
| 1132 | 1154 | ||
| 1155 | if (hold_type != NpadJoyHoldType::Horizontal && hold_type != NpadJoyHoldType::Vertical) { | ||
| 1156 | // This should crash console | ||
| 1157 | ASSERT_MSG(false, "Invalid npad joy hold type"); | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | const auto npad = GetResourceManager()->GetNpad(); | ||
| 1161 | const auto result = npad->SetNpadJoyHoldType(applet_resource_user_id, hold_type); | ||
| 1162 | |||
| 1133 | IPC::ResponseBuilder rb{ctx, 2}; | 1163 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1134 | rb.Push(ResultSuccess); | 1164 | rb.Push(result); |
| 1135 | } | 1165 | } |
| 1136 | 1166 | ||
| 1137 | void IHidServer::GetNpadJoyHoldType(HLERequestContext& ctx) { | 1167 | void IHidServer::GetNpadJoyHoldType(HLERequestContext& ctx) { |
| @@ -1140,9 +1170,13 @@ void IHidServer::GetNpadJoyHoldType(HLERequestContext& ctx) { | |||
| 1140 | 1170 | ||
| 1141 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 1171 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 1142 | 1172 | ||
| 1173 | NpadJoyHoldType hold_type{}; | ||
| 1174 | const auto npad = GetResourceManager()->GetNpad(); | ||
| 1175 | const auto result = npad->GetNpadJoyHoldType(applet_resource_user_id, hold_type); | ||
| 1176 | |||
| 1143 | IPC::ResponseBuilder rb{ctx, 4}; | 1177 | IPC::ResponseBuilder rb{ctx, 4}; |
| 1144 | rb.Push(ResultSuccess); | 1178 | rb.Push(result); |
| 1145 | rb.PushEnum(GetResourceManager()->GetNpad()->GetHoldType()); | 1179 | rb.PushEnum(hold_type); |
| 1146 | } | 1180 | } |
| 1147 | 1181 | ||
| 1148 | void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx) { | 1182 | void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx) { |
| @@ -1158,8 +1192,8 @@ void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx) | |||
| 1158 | 1192 | ||
| 1159 | Core::HID::NpadIdType new_npad_id{}; | 1193 | Core::HID::NpadIdType new_npad_id{}; |
| 1160 | auto controller = GetResourceManager()->GetNpad(); | 1194 | auto controller = GetResourceManager()->GetNpad(); |
| 1161 | controller->SetNpadMode(new_npad_id, parameters.npad_id, NpadJoyDeviceType::Left, | 1195 | controller->SetNpadMode(parameters.applet_resource_user_id, new_npad_id, parameters.npad_id, |
| 1162 | NpadJoyAssignmentMode::Single); | 1196 | NpadJoyDeviceType::Left, NpadJoyAssignmentMode::Single); |
| 1163 | 1197 | ||
| 1164 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, | 1198 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, |
| 1165 | parameters.applet_resource_user_id); | 1199 | parameters.applet_resource_user_id); |
| @@ -1182,8 +1216,8 @@ void IHidServer::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) { | |||
| 1182 | 1216 | ||
| 1183 | Core::HID::NpadIdType new_npad_id{}; | 1217 | Core::HID::NpadIdType new_npad_id{}; |
| 1184 | auto controller = GetResourceManager()->GetNpad(); | 1218 | auto controller = GetResourceManager()->GetNpad(); |
| 1185 | controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, | 1219 | controller->SetNpadMode(parameters.applet_resource_user_id, new_npad_id, parameters.npad_id, |
| 1186 | NpadJoyAssignmentMode::Single); | 1220 | parameters.npad_joy_device_type, NpadJoyAssignmentMode::Single); |
| 1187 | 1221 | ||
| 1188 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", | 1222 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", |
| 1189 | parameters.npad_id, parameters.applet_resource_user_id, | 1223 | parameters.npad_id, parameters.applet_resource_user_id, |
| @@ -1206,7 +1240,8 @@ void IHidServer::SetNpadJoyAssignmentModeDual(HLERequestContext& ctx) { | |||
| 1206 | 1240 | ||
| 1207 | Core::HID::NpadIdType new_npad_id{}; | 1241 | Core::HID::NpadIdType new_npad_id{}; |
| 1208 | auto controller = GetResourceManager()->GetNpad(); | 1242 | auto controller = GetResourceManager()->GetNpad(); |
| 1209 | controller->SetNpadMode(new_npad_id, parameters.npad_id, {}, NpadJoyAssignmentMode::Dual); | 1243 | controller->SetNpadMode(parameters.applet_resource_user_id, new_npad_id, parameters.npad_id, {}, |
| 1244 | NpadJoyAssignmentMode::Dual); | ||
| 1210 | 1245 | ||
| 1211 | LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, | 1246 | LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, |
| 1212 | parameters.applet_resource_user_id); // Spams a lot when controller applet is open | 1247 | parameters.applet_resource_user_id); // Spams a lot when controller applet is open |
| @@ -1222,7 +1257,8 @@ void IHidServer::MergeSingleJoyAsDualJoy(HLERequestContext& ctx) { | |||
| 1222 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 1257 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 1223 | 1258 | ||
| 1224 | auto controller = GetResourceManager()->GetNpad(); | 1259 | auto controller = GetResourceManager()->GetNpad(); |
| 1225 | const auto result = controller->MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2); | 1260 | const auto result = |
| 1261 | controller->MergeSingleJoyAsDualJoy(applet_resource_user_id, npad_id_1, npad_id_2); | ||
| 1226 | 1262 | ||
| 1227 | LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", | 1263 | LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", |
| 1228 | npad_id_1, npad_id_2, applet_resource_user_id); | 1264 | npad_id_1, npad_id_2, applet_resource_user_id); |
| @@ -1235,10 +1271,10 @@ void IHidServer::StartLrAssignmentMode(HLERequestContext& ctx) { | |||
| 1235 | IPC::RequestParser rp{ctx}; | 1271 | IPC::RequestParser rp{ctx}; |
| 1236 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 1272 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 1237 | 1273 | ||
| 1238 | GetResourceManager()->GetNpad()->StartLRAssignmentMode(); | ||
| 1239 | |||
| 1240 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 1274 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 1241 | 1275 | ||
| 1276 | GetResourceManager()->GetNpad()->StartLrAssignmentMode(applet_resource_user_id); | ||
| 1277 | |||
| 1242 | IPC::ResponseBuilder rb{ctx, 2}; | 1278 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1243 | rb.Push(ResultSuccess); | 1279 | rb.Push(ResultSuccess); |
| 1244 | } | 1280 | } |
| @@ -1247,10 +1283,10 @@ void IHidServer::StopLrAssignmentMode(HLERequestContext& ctx) { | |||
| 1247 | IPC::RequestParser rp{ctx}; | 1283 | IPC::RequestParser rp{ctx}; |
| 1248 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 1284 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 1249 | 1285 | ||
| 1250 | GetResourceManager()->GetNpad()->StopLRAssignmentMode(); | ||
| 1251 | |||
| 1252 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 1286 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 1253 | 1287 | ||
| 1288 | GetResourceManager()->GetNpad()->StopLrAssignmentMode(applet_resource_user_id); | ||
| 1289 | |||
| 1254 | IPC::ResponseBuilder rb{ctx, 2}; | 1290 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1255 | rb.Push(ResultSuccess); | 1291 | rb.Push(ResultSuccess); |
| 1256 | } | 1292 | } |
| @@ -1260,13 +1296,23 @@ void IHidServer::SetNpadHandheldActivationMode(HLERequestContext& ctx) { | |||
| 1260 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 1296 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 1261 | const auto activation_mode{rp.PopEnum<NpadHandheldActivationMode>()}; | 1297 | const auto activation_mode{rp.PopEnum<NpadHandheldActivationMode>()}; |
| 1262 | 1298 | ||
| 1263 | GetResourceManager()->GetNpad()->SetNpadHandheldActivationMode(activation_mode); | ||
| 1264 | |||
| 1265 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, activation_mode={}", | 1299 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, activation_mode={}", |
| 1266 | applet_resource_user_id, activation_mode); | 1300 | applet_resource_user_id, activation_mode); |
| 1267 | 1301 | ||
| 1302 | if (activation_mode >= NpadHandheldActivationMode::MaxActivationMode) { | ||
| 1303 | // Console should crash here | ||
| 1304 | ASSERT_MSG(false, "Activation mode should be always None, Single or Dual"); | ||
| 1305 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1306 | rb.Push(ResultSuccess); | ||
| 1307 | return; | ||
| 1308 | } | ||
| 1309 | |||
| 1310 | const auto npad = GetResourceManager()->GetNpad(); | ||
| 1311 | const auto result = | ||
| 1312 | npad->SetNpadHandheldActivationMode(applet_resource_user_id, activation_mode); | ||
| 1313 | |||
| 1268 | IPC::ResponseBuilder rb{ctx, 2}; | 1314 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1269 | rb.Push(ResultSuccess); | 1315 | rb.Push(result); |
| 1270 | } | 1316 | } |
| 1271 | 1317 | ||
| 1272 | void IHidServer::GetNpadHandheldActivationMode(HLERequestContext& ctx) { | 1318 | void IHidServer::GetNpadHandheldActivationMode(HLERequestContext& ctx) { |
| @@ -1275,9 +1321,14 @@ void IHidServer::GetNpadHandheldActivationMode(HLERequestContext& ctx) { | |||
| 1275 | 1321 | ||
| 1276 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 1322 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 1277 | 1323 | ||
| 1324 | NpadHandheldActivationMode activation_mode{}; | ||
| 1325 | const auto npad = GetResourceManager()->GetNpad(); | ||
| 1326 | const auto result = | ||
| 1327 | npad->GetNpadHandheldActivationMode(applet_resource_user_id, activation_mode); | ||
| 1328 | |||
| 1278 | IPC::ResponseBuilder rb{ctx, 4}; | 1329 | IPC::ResponseBuilder rb{ctx, 4}; |
| 1279 | rb.Push(ResultSuccess); | 1330 | rb.Push(result); |
| 1280 | rb.PushEnum(GetResourceManager()->GetNpad()->GetNpadHandheldActivationMode()); | 1331 | rb.PushEnum(activation_mode); |
| 1281 | } | 1332 | } |
| 1282 | 1333 | ||
| 1283 | void IHidServer::SwapNpadAssignment(HLERequestContext& ctx) { | 1334 | void IHidServer::SwapNpadAssignment(HLERequestContext& ctx) { |
| @@ -1286,12 +1337,12 @@ void IHidServer::SwapNpadAssignment(HLERequestContext& ctx) { | |||
| 1286 | const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()}; | 1337 | const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()}; |
| 1287 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 1338 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 1288 | 1339 | ||
| 1289 | auto controller = GetResourceManager()->GetNpad(); | ||
| 1290 | const auto result = controller->SwapNpadAssignment(npad_id_1, npad_id_2); | ||
| 1291 | |||
| 1292 | LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", | 1340 | LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", |
| 1293 | npad_id_1, npad_id_2, applet_resource_user_id); | 1341 | npad_id_1, npad_id_2, applet_resource_user_id); |
| 1294 | 1342 | ||
| 1343 | const auto npad = GetResourceManager()->GetNpad(); | ||
| 1344 | const auto result = npad->SwapNpadAssignment(applet_resource_user_id, npad_id_1, npad_id_2); | ||
| 1345 | |||
| 1295 | IPC::ResponseBuilder rb{ctx, 2}; | 1346 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1296 | rb.Push(result); | 1347 | rb.Push(result); |
| 1297 | } | 1348 | } |
| @@ -1307,13 +1358,19 @@ void IHidServer::IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& | |||
| 1307 | 1358 | ||
| 1308 | const auto parameters{rp.PopRaw<Parameters>()}; | 1359 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1309 | 1360 | ||
| 1310 | bool is_enabled = false; | 1361 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, |
| 1311 | auto controller = GetResourceManager()->GetNpad(); | 1362 | parameters.applet_resource_user_id); |
| 1312 | const auto result = | ||
| 1313 | controller->IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id, is_enabled); | ||
| 1314 | 1363 | ||
| 1315 | LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", | 1364 | if (!IsNpadIdValid(parameters.npad_id)) { |
| 1316 | parameters.npad_id, parameters.applet_resource_user_id); | 1365 | IPC::ResponseBuilder rb{ctx, 3}; |
| 1366 | rb.Push(ResultInvalidNpadId); | ||
| 1367 | return; | ||
| 1368 | } | ||
| 1369 | |||
| 1370 | bool is_enabled{}; | ||
| 1371 | const auto npad = GetResourceManager()->GetNpad(); | ||
| 1372 | const auto result = npad->IsUnintendedHomeButtonInputProtectionEnabled( | ||
| 1373 | is_enabled, parameters.applet_resource_user_id, parameters.npad_id); | ||
| 1317 | 1374 | ||
| 1318 | IPC::ResponseBuilder rb{ctx, 3}; | 1375 | IPC::ResponseBuilder rb{ctx, 3}; |
| 1319 | rb.Push(result); | 1376 | rb.Push(result); |
| @@ -1332,13 +1389,18 @@ void IHidServer::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ct | |||
| 1332 | 1389 | ||
| 1333 | const auto parameters{rp.PopRaw<Parameters>()}; | 1390 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1334 | 1391 | ||
| 1335 | auto controller = GetResourceManager()->GetNpad(); | 1392 | LOG_INFO(Service_HID, "called, is_enabled={}, npad_id={}, applet_resource_user_id={}", |
| 1336 | const auto result = controller->SetUnintendedHomeButtonInputProtectionEnabled( | 1393 | parameters.is_enabled, parameters.npad_id, parameters.applet_resource_user_id); |
| 1337 | parameters.is_enabled, parameters.npad_id); | ||
| 1338 | 1394 | ||
| 1339 | LOG_DEBUG(Service_HID, | 1395 | if (!IsNpadIdValid(parameters.npad_id)) { |
| 1340 | "(STUBBED) called, is_enabled={}, npad_id={}, applet_resource_user_id={}", | 1396 | IPC::ResponseBuilder rb{ctx, 3}; |
| 1341 | parameters.is_enabled, parameters.npad_id, parameters.applet_resource_user_id); | 1397 | rb.Push(ResultInvalidNpadId); |
| 1398 | return; | ||
| 1399 | } | ||
| 1400 | |||
| 1401 | const auto npad = GetResourceManager()->GetNpad(); | ||
| 1402 | const auto result = npad->EnableUnintendedHomeButtonInputProtection( | ||
| 1403 | parameters.applet_resource_user_id, parameters.npad_id, parameters.is_enabled); | ||
| 1342 | 1404 | ||
| 1343 | IPC::ResponseBuilder rb{ctx, 2}; | 1405 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1344 | rb.Push(result); | 1406 | rb.Push(result); |
| @@ -1359,8 +1421,8 @@ void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext | |||
| 1359 | Core::HID::NpadIdType new_npad_id{}; | 1421 | Core::HID::NpadIdType new_npad_id{}; |
| 1360 | auto controller = GetResourceManager()->GetNpad(); | 1422 | auto controller = GetResourceManager()->GetNpad(); |
| 1361 | const auto is_reassigned = | 1423 | const auto is_reassigned = |
| 1362 | controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, | 1424 | controller->SetNpadMode(parameters.applet_resource_user_id, new_npad_id, parameters.npad_id, |
| 1363 | NpadJoyAssignmentMode::Single); | 1425 | parameters.npad_joy_device_type, NpadJoyAssignmentMode::Single); |
| 1364 | 1426 | ||
| 1365 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", | 1427 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", |
| 1366 | parameters.npad_id, parameters.applet_resource_user_id, | 1428 | parameters.npad_id, parameters.applet_resource_user_id, |
| @@ -1375,7 +1437,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext | |||
| 1375 | void IHidServer::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) { | 1437 | void IHidServer::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) { |
| 1376 | IPC::RequestParser rp{ctx}; | 1438 | IPC::RequestParser rp{ctx}; |
| 1377 | struct Parameters { | 1439 | struct Parameters { |
| 1378 | bool analog_stick_use_center_clamp; | 1440 | bool use_center_clamp; |
| 1379 | INSERT_PADDING_BYTES_NOINIT(7); | 1441 | INSERT_PADDING_BYTES_NOINIT(7); |
| 1380 | u64 applet_resource_user_id; | 1442 | u64 applet_resource_user_id; |
| 1381 | }; | 1443 | }; |
| @@ -1383,12 +1445,11 @@ void IHidServer::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) { | |||
| 1383 | 1445 | ||
| 1384 | const auto parameters{rp.PopRaw<Parameters>()}; | 1446 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1385 | 1447 | ||
| 1386 | GetResourceManager()->GetNpad()->SetAnalogStickUseCenterClamp( | 1448 | LOG_WARNING(Service_HID, "(STUBBED) called, use_center_clamp={}, applet_resource_user_id={}", |
| 1387 | parameters.analog_stick_use_center_clamp); | 1449 | parameters.use_center_clamp, parameters.applet_resource_user_id); |
| 1388 | 1450 | ||
| 1389 | LOG_WARNING(Service_HID, | 1451 | GetResourceManager()->GetNpad()->SetNpadAnalogStickUseCenterClamp( |
| 1390 | "(STUBBED) called, analog_stick_use_center_clamp={}, applet_resource_user_id={}", | 1452 | parameters.applet_resource_user_id, parameters.use_center_clamp); |
| 1391 | parameters.analog_stick_use_center_clamp, parameters.applet_resource_user_id); | ||
| 1392 | 1453 | ||
| 1393 | IPC::ResponseBuilder rb{ctx, 2}; | 1454 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1394 | rb.Push(ResultSuccess); | 1455 | rb.Push(ResultSuccess); |
| @@ -1496,7 +1557,8 @@ void IHidServer::SendVibrationValue(HLERequestContext& ctx) { | |||
| 1496 | 1557 | ||
| 1497 | const auto parameters{rp.PopRaw<Parameters>()}; | 1558 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1498 | 1559 | ||
| 1499 | GetResourceManager()->GetNpad()->VibrateController(parameters.vibration_device_handle, | 1560 | GetResourceManager()->GetNpad()->VibrateController(parameters.applet_resource_user_id, |
| 1561 | parameters.vibration_device_handle, | ||
| 1500 | parameters.vibration_value); | 1562 | parameters.vibration_value); |
| 1501 | 1563 | ||
| 1502 | LOG_DEBUG(Service_HID, | 1564 | LOG_DEBUG(Service_HID, |
| @@ -1528,8 +1590,8 @@ void IHidServer::GetActualVibrationValue(HLERequestContext& ctx) { | |||
| 1528 | 1590 | ||
| 1529 | IPC::ResponseBuilder rb{ctx, 6}; | 1591 | IPC::ResponseBuilder rb{ctx, 6}; |
| 1530 | rb.Push(ResultSuccess); | 1592 | rb.Push(ResultSuccess); |
| 1531 | rb.PushRaw( | 1593 | rb.PushRaw(GetResourceManager()->GetNpad()->GetLastVibration( |
| 1532 | GetResourceManager()->GetNpad()->GetLastVibration(parameters.vibration_device_handle)); | 1594 | parameters.applet_resource_user_id, parameters.vibration_device_handle)); |
| 1533 | } | 1595 | } |
| 1534 | 1596 | ||
| 1535 | void IHidServer::CreateActiveVibrationDeviceList(HLERequestContext& ctx) { | 1597 | void IHidServer::CreateActiveVibrationDeviceList(HLERequestContext& ctx) { |
| @@ -1580,7 +1642,8 @@ void IHidServer::SendVibrationValues(HLERequestContext& ctx) { | |||
| 1580 | auto vibration_values = std::span( | 1642 | auto vibration_values = std::span( |
| 1581 | reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count); | 1643 | reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count); |
| 1582 | 1644 | ||
| 1583 | GetResourceManager()->GetNpad()->VibrateControllers(vibration_device_handles, vibration_values); | 1645 | GetResourceManager()->GetNpad()->VibrateControllers(applet_resource_user_id, |
| 1646 | vibration_device_handles, vibration_values); | ||
| 1584 | 1647 | ||
| 1585 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 1648 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 1586 | 1649 | ||
| @@ -1634,8 +1697,8 @@ void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) { | |||
| 1634 | } | 1697 | } |
| 1635 | }(); | 1698 | }(); |
| 1636 | 1699 | ||
| 1637 | GetResourceManager()->GetNpad()->VibrateController(parameters.vibration_device_handle, | 1700 | GetResourceManager()->GetNpad()->VibrateController( |
| 1638 | vibration_value); | 1701 | parameters.applet_resource_user_id, parameters.vibration_device_handle, vibration_value); |
| 1639 | 1702 | ||
| 1640 | LOG_DEBUG(Service_HID, | 1703 | LOG_DEBUG(Service_HID, |
| 1641 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, " | 1704 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, " |
| @@ -1659,8 +1722,8 @@ void IHidServer::GetActualVibrationGcErmCommand(HLERequestContext& ctx) { | |||
| 1659 | 1722 | ||
| 1660 | const auto parameters{rp.PopRaw<Parameters>()}; | 1723 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1661 | 1724 | ||
| 1662 | const auto last_vibration = | 1725 | const auto last_vibration = GetResourceManager()->GetNpad()->GetLastVibration( |
| 1663 | GetResourceManager()->GetNpad()->GetLastVibration(parameters.vibration_device_handle); | 1726 | parameters.applet_resource_user_id, parameters.vibration_device_handle); |
| 1664 | 1727 | ||
| 1665 | const auto gc_erm_command = [last_vibration] { | 1728 | const auto gc_erm_command = [last_vibration] { |
| 1666 | if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) { | 1729 | if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) { |
| @@ -1732,7 +1795,7 @@ void IHidServer::IsVibrationDeviceMounted(HLERequestContext& ctx) { | |||
| 1732 | IPC::ResponseBuilder rb{ctx, 3}; | 1795 | IPC::ResponseBuilder rb{ctx, 3}; |
| 1733 | rb.Push(ResultSuccess); | 1796 | rb.Push(ResultSuccess); |
| 1734 | rb.Push(GetResourceManager()->GetNpad()->IsVibrationDeviceMounted( | 1797 | rb.Push(GetResourceManager()->GetNpad()->IsVibrationDeviceMounted( |
| 1735 | parameters.vibration_device_handle)); | 1798 | parameters.applet_resource_user_id, parameters.vibration_device_handle)); |
| 1736 | } | 1799 | } |
| 1737 | 1800 | ||
| 1738 | void IHidServer::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) { | 1801 | void IHidServer::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) { |
| @@ -1850,8 +1913,7 @@ void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) { | |||
| 1850 | ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes"); | 1913 | ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes"); |
| 1851 | ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes"); | 1914 | ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes"); |
| 1852 | 1915 | ||
| 1853 | auto t_mem_1 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( | 1916 | auto t_mem_1 = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_1_handle); |
| 1854 | t_mem_1_handle); | ||
| 1855 | 1917 | ||
| 1856 | if (t_mem_1.IsNull()) { | 1918 | if (t_mem_1.IsNull()) { |
| 1857 | LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle); | 1919 | LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle); |
| @@ -1860,8 +1922,7 @@ void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) { | |||
| 1860 | return; | 1922 | return; |
| 1861 | } | 1923 | } |
| 1862 | 1924 | ||
| 1863 | auto t_mem_2 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( | 1925 | auto t_mem_2 = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_2_handle); |
| 1864 | t_mem_2_handle); | ||
| 1865 | 1926 | ||
| 1866 | if (t_mem_2.IsNull()) { | 1927 | if (t_mem_2.IsNull()) { |
| 1867 | LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle); | 1928 | LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle); |
| @@ -2142,8 +2203,7 @@ void IHidServer::WritePalmaWaveEntry(HLERequestContext& ctx) { | |||
| 2142 | 2203 | ||
| 2143 | ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes"); | 2204 | ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes"); |
| 2144 | 2205 | ||
| 2145 | auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( | 2206 | auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle); |
| 2146 | t_mem_handle); | ||
| 2147 | 2207 | ||
| 2148 | if (t_mem.IsNull()) { | 2208 | if (t_mem.IsNull()) { |
| 2149 | LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); | 2209 | LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); |
| @@ -2318,10 +2378,10 @@ void IHidServer::SetNpadCommunicationMode(HLERequestContext& ctx) { | |||
| 2318 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 2378 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 2319 | const auto communication_mode{rp.PopEnum<NpadCommunicationMode>()}; | 2379 | const auto communication_mode{rp.PopEnum<NpadCommunicationMode>()}; |
| 2320 | 2380 | ||
| 2321 | GetResourceManager()->GetNpad()->SetNpadCommunicationMode(communication_mode); | 2381 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, communication_mode={}", |
| 2382 | applet_resource_user_id, communication_mode); | ||
| 2322 | 2383 | ||
| 2323 | LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, communication_mode={}", | 2384 | // This function has been stubbed since 2.0.0+ |
| 2324 | applet_resource_user_id, communication_mode); | ||
| 2325 | 2385 | ||
| 2326 | IPC::ResponseBuilder rb{ctx, 2}; | 2386 | IPC::ResponseBuilder rb{ctx, 2}; |
| 2327 | rb.Push(ResultSuccess); | 2387 | rb.Push(ResultSuccess); |
| @@ -2329,12 +2389,15 @@ void IHidServer::SetNpadCommunicationMode(HLERequestContext& ctx) { | |||
| 2329 | 2389 | ||
| 2330 | void IHidServer::GetNpadCommunicationMode(HLERequestContext& ctx) { | 2390 | void IHidServer::GetNpadCommunicationMode(HLERequestContext& ctx) { |
| 2331 | IPC::RequestParser rp{ctx}; | 2391 | IPC::RequestParser rp{ctx}; |
| 2392 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 2332 | 2393 | ||
| 2333 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 2394 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 2395 | |||
| 2396 | // This function has been stubbed since 2.0.0+ | ||
| 2334 | 2397 | ||
| 2335 | IPC::ResponseBuilder rb{ctx, 4}; | 2398 | IPC::ResponseBuilder rb{ctx, 4}; |
| 2336 | rb.Push(ResultSuccess); | 2399 | rb.Push(ResultSuccess); |
| 2337 | rb.PushEnum(GetResourceManager()->GetNpad()->GetNpadCommunicationMode()); | 2400 | rb.PushEnum(NpadCommunicationMode::Default); |
| 2338 | } | 2401 | } |
| 2339 | 2402 | ||
| 2340 | void IHidServer::SetTouchScreenConfiguration(HLERequestContext& ctx) { | 2403 | void IHidServer::SetTouchScreenConfiguration(HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/hid/hid_system_server.cpp b/src/core/hle/service/hid/hid_system_server.cpp index 5cc88c4a1..4823de743 100644 --- a/src/core/hle/service/hid/hid_system_server.cpp +++ b/src/core/hle/service/hid/hid_system_server.cpp | |||
| @@ -240,9 +240,12 @@ IHidSystemServer::~IHidSystemServer() { | |||
| 240 | }; | 240 | }; |
| 241 | 241 | ||
| 242 | void IHidSystemServer::ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) { | 242 | void IHidSystemServer::ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) { |
| 243 | LOG_WARNING(Service_HID, "called"); | 243 | IPC::RequestParser rp{ctx}; |
| 244 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 245 | |||
| 246 | LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | ||
| 244 | 247 | ||
| 245 | GetResourceManager()->GetNpad()->ApplyNpadSystemCommonPolicy(); | 248 | GetResourceManager()->GetNpad()->ApplyNpadSystemCommonPolicy(applet_resource_user_id); |
| 246 | 249 | ||
| 247 | IPC::ResponseBuilder rb{ctx, 2}; | 250 | IPC::ResponseBuilder rb{ctx, 2}; |
| 248 | rb.Push(ResultSuccess); | 251 | rb.Push(ResultSuccess); |
| @@ -271,9 +274,12 @@ void IHidSystemServer::GetLastActiveNpad(HLERequestContext& ctx) { | |||
| 271 | } | 274 | } |
| 272 | 275 | ||
| 273 | void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) { | 276 | void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) { |
| 274 | LOG_WARNING(Service_HID, "called"); | 277 | IPC::RequestParser rp{ctx}; |
| 278 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 275 | 279 | ||
| 276 | GetResourceManager()->GetNpad()->ApplyNpadSystemCommonPolicy(); | 280 | LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 281 | |||
| 282 | GetResourceManager()->GetNpad()->ApplyNpadSystemCommonPolicyFull(applet_resource_user_id); | ||
| 277 | 283 | ||
| 278 | IPC::ResponseBuilder rb{ctx, 2}; | 284 | IPC::ResponseBuilder rb{ctx, 2}; |
| 279 | rb.Push(ResultSuccess); | 285 | rb.Push(ResultSuccess); |
| @@ -298,28 +304,32 @@ void IHidSystemServer::GetNpadFullKeyGripColor(HLERequestContext& ctx) { | |||
| 298 | 304 | ||
| 299 | void IHidSystemServer::GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx) { | 305 | void IHidSystemServer::GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx) { |
| 300 | IPC::RequestParser rp{ctx}; | 306 | IPC::RequestParser rp{ctx}; |
| 307 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 301 | 308 | ||
| 302 | LOG_INFO(Service_HID, "(STUBBED) called"); | 309 | LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 303 | 310 | ||
| 304 | Core::HID::NpadStyleSet supported_styleset = | 311 | Core::HID::NpadStyleSet supported_styleset{}; |
| 305 | GetResourceManager()->GetNpad()->GetSupportedStyleSet().raw; | 312 | const auto& npad = GetResourceManager()->GetNpad(); |
| 313 | const Result result = | ||
| 314 | npad->GetMaskedSupportedNpadStyleSet(applet_resource_user_id, supported_styleset); | ||
| 306 | 315 | ||
| 307 | IPC::ResponseBuilder rb{ctx, 3}; | 316 | IPC::ResponseBuilder rb{ctx, 3}; |
| 308 | rb.Push(ResultSuccess); | 317 | rb.Push(result); |
| 309 | rb.PushEnum(supported_styleset); | 318 | rb.PushEnum(supported_styleset); |
| 310 | } | 319 | } |
| 311 | 320 | ||
| 312 | void IHidSystemServer::SetSupportedNpadStyleSetAll(HLERequestContext& ctx) { | 321 | void IHidSystemServer::SetSupportedNpadStyleSetAll(HLERequestContext& ctx) { |
| 313 | IPC::RequestParser rp{ctx}; | 322 | IPC::RequestParser rp{ctx}; |
| 323 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 314 | 324 | ||
| 315 | LOG_INFO(Service_HID, "(STUBBED) called"); | 325 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 316 | 326 | ||
| 317 | Core::HID::NpadStyleSet supported_styleset = | 327 | const auto& npad = GetResourceManager()->GetNpad(); |
| 318 | GetResourceManager()->GetNpad()->GetSupportedStyleSet().raw; | 328 | const auto result = |
| 329 | npad->SetSupportedNpadStyleSet(applet_resource_user_id, Core::HID::NpadStyleSet::All); | ||
| 319 | 330 | ||
| 320 | IPC::ResponseBuilder rb{ctx, 3}; | 331 | IPC::ResponseBuilder rb{ctx, 2}; |
| 321 | rb.Push(ResultSuccess); | 332 | rb.Push(result); |
| 322 | rb.PushEnum(supported_styleset); | ||
| 323 | } | 333 | } |
| 324 | 334 | ||
| 325 | void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) { | 335 | void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/hid/hid_util.h b/src/core/hle/service/hid/hid_util.h index b87cc10e3..6a2ed287a 100644 --- a/src/core/hle/service/hid/hid_util.h +++ b/src/core/hle/service/hid/hid_util.h | |||
| @@ -31,7 +31,7 @@ constexpr Result IsSixaxisHandleValid(const Core::HID::SixAxisSensorHandle& hand | |||
| 31 | const bool device_index = handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; | 31 | const bool device_index = handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; |
| 32 | 32 | ||
| 33 | if (!npad_id) { | 33 | if (!npad_id) { |
| 34 | return InvalidNpadId; | 34 | return ResultInvalidNpadId; |
| 35 | } | 35 | } |
| 36 | if (!device_index) { | 36 | if (!device_index) { |
| 37 | return NpadDeviceIndexOutOfRange; | 37 | return NpadDeviceIndexOutOfRange; |
| @@ -54,15 +54,15 @@ constexpr Result IsVibrationHandleValid(const Core::HID::VibrationDeviceHandle& | |||
| 54 | // These support vibration | 54 | // These support vibration |
| 55 | break; | 55 | break; |
| 56 | default: | 56 | default: |
| 57 | return VibrationInvalidStyleIndex; | 57 | return ResultVibrationInvalidStyleIndex; |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | if (!IsNpadIdValid(static_cast<Core::HID::NpadIdType>(handle.npad_id))) { | 60 | if (!IsNpadIdValid(static_cast<Core::HID::NpadIdType>(handle.npad_id))) { |
| 61 | return VibrationInvalidNpadId; | 61 | return ResultVibrationInvalidNpadId; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | if (handle.device_index >= Core::HID::DeviceIndex::MaxDeviceIndex) { | 64 | if (handle.device_index >= Core::HID::DeviceIndex::MaxDeviceIndex) { |
| 65 | return VibrationDeviceIndexOutOfRange; | 65 | return ResultVibrationDeviceIndexOutOfRange; |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | return ResultSuccess; | 68 | return ResultSuccess; |
diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp index 80aac221b..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) { |
| @@ -448,8 +448,7 @@ void HidBus::EnableJoyPollingReceiveMode(HLERequestContext& ctx) { | |||
| 448 | 448 | ||
| 449 | ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes"); | 449 | ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes"); |
| 450 | 450 | ||
| 451 | auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( | 451 | auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle); |
| 452 | t_mem_handle); | ||
| 453 | 452 | ||
| 454 | if (t_mem.IsNull()) { | 453 | if (t_mem.IsNull()) { |
| 455 | LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); | 454 | LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); |
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/irs.cpp b/src/core/hle/service/hid/irs.cpp index 39b9a4474..05ed31273 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp | |||
| @@ -197,8 +197,7 @@ void IRS::RunImageTransferProcessor(HLERequestContext& ctx) { | |||
| 197 | const auto parameters{rp.PopRaw<Parameters>()}; | 197 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 198 | const auto t_mem_handle{ctx.GetCopyHandle(0)}; | 198 | const auto t_mem_handle{ctx.GetCopyHandle(0)}; |
| 199 | 199 | ||
| 200 | auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( | 200 | auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle); |
| 201 | t_mem_handle); | ||
| 202 | 201 | ||
| 203 | if (t_mem.IsNull()) { | 202 | if (t_mem.IsNull()) { |
| 204 | LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); | 203 | LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); |
| @@ -316,7 +315,7 @@ void IRS::GetNpadIrCameraHandle(HLERequestContext& ctx) { | |||
| 316 | if (npad_id > Core::HID::NpadIdType::Player8 && npad_id != Core::HID::NpadIdType::Invalid && | 315 | if (npad_id > Core::HID::NpadIdType::Player8 && npad_id != Core::HID::NpadIdType::Invalid && |
| 317 | npad_id != Core::HID::NpadIdType::Handheld) { | 316 | npad_id != Core::HID::NpadIdType::Handheld) { |
| 318 | IPC::ResponseBuilder rb{ctx, 2}; | 317 | IPC::ResponseBuilder rb{ctx, 2}; |
| 319 | rb.Push(Service::HID::InvalidNpadId); | 318 | rb.Push(Service::HID::ResultInvalidNpadId); |
| 320 | return; | 319 | return; |
| 321 | } | 320 | } |
| 322 | 321 | ||
| @@ -444,8 +443,7 @@ void IRS::RunImageTransferExProcessor(HLERequestContext& ctx) { | |||
| 444 | const auto parameters{rp.PopRaw<Parameters>()}; | 443 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 445 | const auto t_mem_handle{ctx.GetCopyHandle(0)}; | 444 | const auto t_mem_handle{ctx.GetCopyHandle(0)}; |
| 446 | 445 | ||
| 447 | auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( | 446 | auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle); |
| 448 | t_mem_handle); | ||
| 449 | 447 | ||
| 450 | LOG_INFO(Service_IRS, | 448 | LOG_INFO(Service_IRS, |
| 451 | "called, npad_type={}, npad_id={}, transfer_memory_size={}, " | 449 | "called, npad_type={}, npad_id={}, transfer_memory_size={}, " |
diff --git a/src/core/hle/service/hid/resource_manager.cpp b/src/core/hle/service/hid/resource_manager.cpp index 6c6cbd802..1f41e645d 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 | 54 | ||
| 59 | debug_pad = std::make_shared<DebugPad>(system.HIDCore(), shared_memory->debug_pad); | 55 | InitializeHidCommonSampler(); |
| 60 | mouse = std::make_shared<Mouse>(system.HIDCore(), shared_memory->mouse); | 56 | InitializeTouchScreenSampler(); |
| 61 | debug_mouse = std::make_shared<DebugMouse>(system.HIDCore(), shared_memory->debug_mouse); | 57 | InitializeConsoleSixAxisSampler(); |
| 62 | keyboard = std::make_shared<Keyboard>(system.HIDCore(), shared_memory->keyboard); | 58 | InitializeAHidSampler(); |
| 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 | 59 | ||
| 68 | palma = std::make_shared<Palma>(system.HIDCore(), service_context); | 60 | is_initialized = true; |
| 69 | |||
| 70 | home_button = std::make_shared<HomeButton>(system.HIDCore(), shared_memory->home_button.header); | ||
| 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 { |
| @@ -153,28 +129,77 @@ std::shared_ptr<UniquePad> ResourceManager::GetUniquePad() const { | |||
| 153 | } | 129 | } |
| 154 | 130 | ||
| 155 | Result ResourceManager::CreateAppletResource(u64 aruid) { | 131 | Result ResourceManager::CreateAppletResource(u64 aruid) { |
| 156 | if (aruid == 0) { | 132 | if (aruid == SystemAruid) { |
| 157 | const auto result = RegisterCoreAppletResource(); | 133 | const auto result = RegisterCoreAppletResource(); |
| 158 | if (result.IsError()) { | 134 | if (result.IsError()) { |
| 159 | return result; | 135 | return result; |
| 160 | } | 136 | } |
| 161 | return GetNpad()->Activate(); | 137 | return GetNpad()->ActivateNpadResource(); |
| 162 | } | 138 | } |
| 163 | 139 | ||
| 164 | const auto result = CreateAppletResourceImpl(aruid); | 140 | const auto result = CreateAppletResourceImpl(aruid); |
| 165 | if (result.IsError()) { | 141 | if (result.IsError()) { |
| 166 | return result; | 142 | return result; |
| 167 | } | 143 | } |
| 168 | return GetNpad()->Activate(aruid); | 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 | |||
| 150 | return GetNpad()->ActivateNpadResource(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, &shared_mutex); | ||
| 175 | digitizer->SetAppletResource(applet_resource, &shared_mutex); | ||
| 176 | keyboard->SetAppletResource(applet_resource, &shared_mutex); | ||
| 177 | npad->SetNpadExternals(applet_resource, &shared_mutex); | ||
| 178 | six_axis->SetAppletResource(applet_resource, &shared_mutex); | ||
| 179 | mouse->SetAppletResource(applet_resource, &shared_mutex); | ||
| 180 | debug_mouse->SetAppletResource(applet_resource, &shared_mutex); | ||
| 181 | home_button->SetAppletResource(applet_resource, &shared_mutex); | ||
| 182 | sleep_button->SetAppletResource(applet_resource, &shared_mutex); | ||
| 183 | capture_button->SetAppletResource(applet_resource, &shared_mutex); | ||
| 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, &shared_mutex); | ||
| 191 | gesture->SetAppletResource(applet_resource, &shared_mutex); | ||
| 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, &shared_mutex); | ||
| 199 | } | ||
| 200 | |||
| 201 | void ResourceManager::InitializeAHidSampler() { | ||
| 202 | // TODO | ||
| 178 | } | 203 | } |
| 179 | 204 | ||
| 180 | Result ResourceManager::RegisterCoreAppletResource() { | 205 | Result ResourceManager::RegisterCoreAppletResource() { |
| @@ -189,7 +214,11 @@ Result ResourceManager::UnregisterCoreAppletResource() { | |||
| 189 | 214 | ||
| 190 | Result ResourceManager::RegisterAppletResourceUserId(u64 aruid, bool bool_value) { | 215 | Result ResourceManager::RegisterAppletResourceUserId(u64 aruid, bool bool_value) { |
| 191 | std::scoped_lock lock{shared_mutex}; | 216 | std::scoped_lock lock{shared_mutex}; |
| 192 | return applet_resource->RegisterAppletResourceUserId(aruid, bool_value); | 217 | auto result = applet_resource->RegisterAppletResourceUserId(aruid, bool_value); |
| 218 | if (result.IsSuccess()) { | ||
| 219 | result = npad->RegisterAppletResourceUserId(aruid); | ||
| 220 | } | ||
| 221 | return result; | ||
| 193 | } | 222 | } |
| 194 | 223 | ||
| 195 | void ResourceManager::UnregisterAppletResourceUserId(u64 aruid) { | 224 | void ResourceManager::UnregisterAppletResourceUserId(u64 aruid) { |
| @@ -227,8 +256,7 @@ void ResourceManager::EnableTouchScreen(u64 aruid, bool is_enabled) { | |||
| 227 | applet_resource->EnableTouchScreen(aruid, is_enabled); | 256 | applet_resource->EnableTouchScreen(aruid, is_enabled); |
| 228 | } | 257 | } |
| 229 | 258 | ||
| 230 | void ResourceManager::UpdateControllers(std::uintptr_t user_data, | 259 | void ResourceManager::UpdateControllers(std::chrono::nanoseconds ns_late) { |
| 231 | std::chrono::nanoseconds ns_late) { | ||
| 232 | auto& core_timing = system.CoreTiming(); | 260 | auto& core_timing = system.CoreTiming(); |
| 233 | debug_pad->OnUpdate(core_timing); | 261 | debug_pad->OnUpdate(core_timing); |
| 234 | digitizer->OnUpdate(core_timing); | 262 | digitizer->OnUpdate(core_timing); |
| @@ -241,20 +269,19 @@ void ResourceManager::UpdateControllers(std::uintptr_t user_data, | |||
| 241 | capture_button->OnUpdate(core_timing); | 269 | capture_button->OnUpdate(core_timing); |
| 242 | } | 270 | } |
| 243 | 271 | ||
| 244 | void ResourceManager::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 272 | void ResourceManager::UpdateNpad(std::chrono::nanoseconds ns_late) { |
| 245 | auto& core_timing = system.CoreTiming(); | 273 | auto& core_timing = system.CoreTiming(); |
| 246 | npad->OnUpdate(core_timing); | 274 | npad->OnUpdate(core_timing); |
| 247 | } | 275 | } |
| 248 | 276 | ||
| 249 | void ResourceManager::UpdateMouseKeyboard(std::uintptr_t user_data, | 277 | void ResourceManager::UpdateMouseKeyboard(std::chrono::nanoseconds ns_late) { |
| 250 | std::chrono::nanoseconds ns_late) { | ||
| 251 | auto& core_timing = system.CoreTiming(); | 278 | auto& core_timing = system.CoreTiming(); |
| 252 | mouse->OnUpdate(core_timing); | 279 | mouse->OnUpdate(core_timing); |
| 253 | debug_mouse->OnUpdate(core_timing); | 280 | debug_mouse->OnUpdate(core_timing); |
| 254 | keyboard->OnUpdate(core_timing); | 281 | keyboard->OnUpdate(core_timing); |
| 255 | } | 282 | } |
| 256 | 283 | ||
| 257 | void ResourceManager::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 284 | void ResourceManager::UpdateMotion(std::chrono::nanoseconds ns_late) { |
| 258 | auto& core_timing = system.CoreTiming(); | 285 | auto& core_timing = system.CoreTiming(); |
| 259 | six_axis->OnUpdate(core_timing); | 286 | six_axis->OnUpdate(core_timing); |
| 260 | seven_six_axis->OnUpdate(core_timing); | 287 | seven_six_axis->OnUpdate(core_timing); |
| @@ -273,34 +300,34 @@ IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<Resource | |||
| 273 | // Register update callbacks | 300 | // Register update callbacks |
| 274 | npad_update_event = Core::Timing::CreateEvent( | 301 | npad_update_event = Core::Timing::CreateEvent( |
| 275 | "HID::UpdatePadCallback", | 302 | "HID::UpdatePadCallback", |
| 276 | [this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late) | 303 | [this, resource]( |
| 277 | -> std::optional<std::chrono::nanoseconds> { | 304 | s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { |
| 278 | const auto guard = LockService(); | 305 | const auto guard = LockService(); |
| 279 | resource->UpdateNpad(user_data, ns_late); | 306 | resource->UpdateNpad(ns_late); |
| 280 | return std::nullopt; | 307 | return std::nullopt; |
| 281 | }); | 308 | }); |
| 282 | default_update_event = Core::Timing::CreateEvent( | 309 | default_update_event = Core::Timing::CreateEvent( |
| 283 | "HID::UpdateDefaultCallback", | 310 | "HID::UpdateDefaultCallback", |
| 284 | [this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late) | 311 | [this, resource]( |
| 285 | -> std::optional<std::chrono::nanoseconds> { | 312 | s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { |
| 286 | const auto guard = LockService(); | 313 | const auto guard = LockService(); |
| 287 | resource->UpdateControllers(user_data, ns_late); | 314 | resource->UpdateControllers(ns_late); |
| 288 | return std::nullopt; | 315 | return std::nullopt; |
| 289 | }); | 316 | }); |
| 290 | mouse_keyboard_update_event = Core::Timing::CreateEvent( | 317 | mouse_keyboard_update_event = Core::Timing::CreateEvent( |
| 291 | "HID::UpdateMouseKeyboardCallback", | 318 | "HID::UpdateMouseKeyboardCallback", |
| 292 | [this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late) | 319 | [this, resource]( |
| 293 | -> std::optional<std::chrono::nanoseconds> { | 320 | s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { |
| 294 | const auto guard = LockService(); | 321 | const auto guard = LockService(); |
| 295 | resource->UpdateMouseKeyboard(user_data, ns_late); | 322 | resource->UpdateMouseKeyboard(ns_late); |
| 296 | return std::nullopt; | 323 | return std::nullopt; |
| 297 | }); | 324 | }); |
| 298 | motion_update_event = Core::Timing::CreateEvent( | 325 | motion_update_event = Core::Timing::CreateEvent( |
| 299 | "HID::UpdateMotionCallback", | 326 | "HID::UpdateMotionCallback", |
| 300 | [this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late) | 327 | [this, resource]( |
| 301 | -> std::optional<std::chrono::nanoseconds> { | 328 | s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { |
| 302 | const auto guard = LockService(); | 329 | const auto guard = LockService(); |
| 303 | resource->UpdateMotion(user_data, ns_late); | 330 | resource->UpdateMotion(ns_late); |
| 304 | return std::nullopt; | 331 | return std::nullopt; |
| 305 | }); | 332 | }); |
| 306 | 333 | ||
| @@ -314,10 +341,10 @@ IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<Resource | |||
| 314 | } | 341 | } |
| 315 | 342 | ||
| 316 | IAppletResource::~IAppletResource() { | 343 | IAppletResource::~IAppletResource() { |
| 317 | system.CoreTiming().UnscheduleEvent(npad_update_event, 0); | 344 | system.CoreTiming().UnscheduleEvent(npad_update_event); |
| 318 | system.CoreTiming().UnscheduleEvent(default_update_event, 0); | 345 | system.CoreTiming().UnscheduleEvent(default_update_event); |
| 319 | system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0); | 346 | system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event); |
| 320 | system.CoreTiming().UnscheduleEvent(motion_update_event, 0); | 347 | system.CoreTiming().UnscheduleEvent(motion_update_event); |
| 321 | resource_manager->FreeAppletResourceId(aruid); | 348 | resource_manager->FreeAppletResourceId(aruid); |
| 322 | } | 349 | } |
| 323 | 350 | ||
diff --git a/src/core/hle/service/hid/resource_manager.h b/src/core/hle/service/hid/resource_manager.h index 5ad7cb564..7a21d8eb8 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,17 +79,21 @@ 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 | ||
| 94 | mutable std::mutex shared_mutex; | 96 | mutable std::recursive_mutex shared_mutex; |
| 95 | std::shared_ptr<AppletResource> applet_resource = nullptr; | 97 | std::shared_ptr<AppletResource> applet_resource = nullptr; |
| 96 | 98 | ||
| 97 | std::shared_ptr<CaptureButton> capture_button = nullptr; | 99 | std::shared_ptr<CaptureButton> capture_button = nullptr; |
diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp index 38955932c..39df77e43 100644 --- a/src/core/hle/service/hle_ipc.cpp +++ b/src/core/hle/service/hle_ipc.cpp | |||
| @@ -146,10 +146,7 @@ HLERequestContext::HLERequestContext(Kernel::KernelCore& kernel_, Core::Memory:: | |||
| 146 | 146 | ||
| 147 | HLERequestContext::~HLERequestContext() = default; | 147 | HLERequestContext::~HLERequestContext() = default; |
| 148 | 148 | ||
| 149 | void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf, | 149 | void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { |
| 150 | bool incoming) { | ||
| 151 | client_handle_table = &process.GetHandleTable(); | ||
| 152 | |||
| 153 | IPC::RequestParser rp(src_cmdbuf); | 150 | IPC::RequestParser rp(src_cmdbuf); |
| 154 | command_header = rp.PopRaw<IPC::CommandHeader>(); | 151 | command_header = rp.PopRaw<IPC::CommandHeader>(); |
| 155 | 152 | ||
| @@ -162,7 +159,7 @@ void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* sr | |||
| 162 | if (command_header->enable_handle_descriptor) { | 159 | if (command_header->enable_handle_descriptor) { |
| 163 | handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>(); | 160 | handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>(); |
| 164 | if (handle_descriptor_header->send_current_pid) { | 161 | if (handle_descriptor_header->send_current_pid) { |
| 165 | pid = process.GetProcessId(); | 162 | pid = thread->GetOwnerProcess()->GetProcessId(); |
| 166 | rp.Skip(2, false); | 163 | rp.Skip(2, false); |
| 167 | } | 164 | } |
| 168 | if (incoming) { | 165 | if (incoming) { |
| @@ -270,9 +267,10 @@ void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* sr | |||
| 270 | rp.Skip(1, false); // The command is actually an u64, but we don't use the high part. | 267 | rp.Skip(1, false); // The command is actually an u64, but we don't use the high part. |
| 271 | } | 268 | } |
| 272 | 269 | ||
| 273 | Result HLERequestContext::PopulateFromIncomingCommandBuffer(Kernel::KProcess& process, | 270 | Result HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf) { |
| 274 | u32_le* src_cmdbuf) { | 271 | client_handle_table = &thread->GetOwnerProcess()->GetHandleTable(); |
| 275 | ParseCommandBuffer(process, src_cmdbuf, true); | 272 | |
| 273 | ParseCommandBuffer(src_cmdbuf, true); | ||
| 276 | 274 | ||
| 277 | if (command_header->IsCloseCommand()) { | 275 | if (command_header->IsCloseCommand()) { |
| 278 | // Close does not populate the rest of the IPC header | 276 | // Close does not populate the rest of the IPC header |
| @@ -284,9 +282,9 @@ Result HLERequestContext::PopulateFromIncomingCommandBuffer(Kernel::KProcess& pr | |||
| 284 | return ResultSuccess; | 282 | return ResultSuccess; |
| 285 | } | 283 | } |
| 286 | 284 | ||
| 287 | Result HLERequestContext::WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread) { | 285 | Result HLERequestContext::WriteToOutgoingCommandBuffer() { |
| 288 | auto current_offset = handles_offset; | 286 | auto current_offset = handles_offset; |
| 289 | auto& owner_process = *requesting_thread.GetOwnerProcess(); | 287 | auto& owner_process = *thread->GetOwnerProcess(); |
| 290 | auto& handle_table = owner_process.GetHandleTable(); | 288 | auto& handle_table = owner_process.GetHandleTable(); |
| 291 | 289 | ||
| 292 | for (auto& object : outgoing_copy_objects) { | 290 | for (auto& object : outgoing_copy_objects) { |
| @@ -319,7 +317,7 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(Kernel::KThread& requesti | |||
| 319 | } | 317 | } |
| 320 | 318 | ||
| 321 | // Copy the translated command buffer back into the thread's command buffer area. | 319 | // Copy the translated command buffer back into the thread's command buffer area. |
| 322 | memory.WriteBlock(requesting_thread.GetTlsAddress(), cmd_buf.data(), write_size * sizeof(u32)); | 320 | memory.WriteBlock(thread->GetTlsAddress(), cmd_buf.data(), write_size * sizeof(u32)); |
| 323 | 321 | ||
| 324 | return ResultSuccess; | 322 | return ResultSuccess; |
| 325 | } | 323 | } |
diff --git a/src/core/hle/service/hle_ipc.h b/src/core/hle/service/hle_ipc.h index 18d464c63..40d86943e 100644 --- a/src/core/hle/service/hle_ipc.h +++ b/src/core/hle/service/hle_ipc.h | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include "common/concepts.h" | 17 | #include "common/concepts.h" |
| 18 | #include "common/swap.h" | 18 | #include "common/swap.h" |
| 19 | #include "core/hle/ipc.h" | 19 | #include "core/hle/ipc.h" |
| 20 | #include "core/hle/kernel/k_handle_table.h" | ||
| 20 | #include "core/hle/kernel/svc_common.h" | 21 | #include "core/hle/kernel/svc_common.h" |
| 21 | 22 | ||
| 22 | union Result; | 23 | union Result; |
| @@ -196,10 +197,10 @@ public: | |||
| 196 | } | 197 | } |
| 197 | 198 | ||
| 198 | /// Populates this context with data from the requesting process/thread. | 199 | /// Populates this context with data from the requesting process/thread. |
| 199 | Result PopulateFromIncomingCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf); | 200 | Result PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf); |
| 200 | 201 | ||
| 201 | /// Writes data from this context back to the requesting process/thread. | 202 | /// Writes data from this context back to the requesting process/thread. |
| 202 | Result WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread); | 203 | Result WriteToOutgoingCommandBuffer(); |
| 203 | 204 | ||
| 204 | [[nodiscard]] u32_le GetHipcCommand() const { | 205 | [[nodiscard]] u32_le GetHipcCommand() const { |
| 205 | return command; | 206 | return command; |
| @@ -359,8 +360,17 @@ public: | |||
| 359 | return *thread; | 360 | return *thread; |
| 360 | } | 361 | } |
| 361 | 362 | ||
| 362 | Kernel::KHandleTable& GetClientHandleTable() { | 363 | [[nodiscard]] Core::Memory::Memory& GetMemory() const { |
| 363 | return *client_handle_table; | 364 | return memory; |
| 365 | } | ||
| 366 | |||
| 367 | template <typename T> | ||
| 368 | Kernel::KScopedAutoObject<T> GetObjectFromHandle(u32 handle) { | ||
| 369 | auto obj = client_handle_table->GetObjectForIpc(handle, thread); | ||
| 370 | if (obj.IsNotNull()) { | ||
| 371 | return obj->DynamicCast<T*>(); | ||
| 372 | } | ||
| 373 | return nullptr; | ||
| 364 | } | 374 | } |
| 365 | 375 | ||
| 366 | [[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const { | 376 | [[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const { |
| @@ -378,7 +388,7 @@ public: | |||
| 378 | private: | 388 | private: |
| 379 | friend class IPC::ResponseBuilder; | 389 | friend class IPC::ResponseBuilder; |
| 380 | 390 | ||
| 381 | void ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf, bool incoming); | 391 | void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming); |
| 382 | 392 | ||
| 383 | std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; | 393 | std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; |
| 384 | Kernel::KServerSession* server_session{}; | 394 | Kernel::KServerSession* server_session{}; |
diff --git a/src/core/hle/service/ipc_helpers.h b/src/core/hle/service/ipc_helpers.h index 0e222362e..4b02872fb 100644 --- a/src/core/hle/service/ipc_helpers.h +++ b/src/core/hle/service/ipc_helpers.h | |||
| @@ -151,8 +151,8 @@ public: | |||
| 151 | if (manager->IsDomain()) { | 151 | if (manager->IsDomain()) { |
| 152 | context->AddDomainObject(std::move(iface)); | 152 | context->AddDomainObject(std::move(iface)); |
| 153 | } else { | 153 | } else { |
| 154 | kernel.ApplicationProcess()->GetResourceLimit()->Reserve( | 154 | ASSERT(Kernel::GetCurrentProcess(kernel).GetResourceLimit()->Reserve( |
| 155 | Kernel::LimitableResource::SessionCountMax, 1); | 155 | Kernel::LimitableResource::SessionCountMax, 1)); |
| 156 | 156 | ||
| 157 | auto* session = Kernel::KSession::Create(kernel); | 157 | auto* session = Kernel::KSession::Create(kernel); |
| 158 | session->Initialize(nullptr, 0); | 158 | session->Initialize(nullptr, 0); |
diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp index 65851fc05..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,9 +23,11 @@ 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 | : ServiceFramework{system_, "IJitEnvironment"}, process{std::move(process_)}, | ||
| 30 | user_rx{std::move(user_rx_)}, user_ro{std::move(user_ro_)}, | ||
| 29 | context{system_.ApplicationMemory()} { | 31 | context{system_.ApplicationMemory()} { |
| 30 | // clang-format off | 32 | // clang-format off |
| 31 | static const FunctionInfo functions[] = { | 33 | static const FunctionInfo functions[] = { |
| @@ -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) { |
| @@ -188,7 +193,7 @@ public: | |||
| 188 | return; | 193 | return; |
| 189 | } | 194 | } |
| 190 | 195 | ||
| 191 | auto tmem{process->GetHandleTable().GetObject<Kernel::KTransferMemory>(tmem_handle)}; | 196 | auto tmem{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(tmem_handle)}; |
| 192 | if (tmem.IsNull()) { | 197 | if (tmem.IsNull()) { |
| 193 | LOG_ERROR(Service_JIT, "attempted to load plugin with invalid transfer memory handle"); | 198 | LOG_ERROR(Service_JIT, "attempted to load plugin with invalid transfer memory handle"); |
| 194 | IPC::ResponseBuilder rb{ctx, 2}; | 199 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -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 | ||
| @@ -356,11 +364,7 @@ public: | |||
| 356 | return; | 364 | return; |
| 357 | } | 365 | } |
| 358 | 366 | ||
| 359 | // Fetch using the handle table for the application process here, | 367 | auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)}; |
| 360 | // since we are not multiprocess yet. | ||
| 361 | const auto& handle_table{system.ApplicationProcess()->GetHandleTable()}; | ||
| 362 | |||
| 363 | auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)}; | ||
| 364 | if (process.IsNull()) { | 368 | if (process.IsNull()) { |
| 365 | LOG_ERROR(Service_JIT, "process is null for handle=0x{:08X}", process_handle); | 369 | LOG_ERROR(Service_JIT, "process is null for handle=0x{:08X}", process_handle); |
| 366 | IPC::ResponseBuilder rb{ctx, 2}; | 370 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -368,7 +372,7 @@ public: | |||
| 368 | return; | 372 | return; |
| 369 | } | 373 | } |
| 370 | 374 | ||
| 371 | auto rx_mem{handle_table.GetObject<Kernel::KCodeMemory>(rx_mem_handle)}; | 375 | auto rx_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(rx_mem_handle)}; |
| 372 | if (rx_mem.IsNull()) { | 376 | if (rx_mem.IsNull()) { |
| 373 | LOG_ERROR(Service_JIT, "rx_mem is null for handle=0x{:08X}", rx_mem_handle); | 377 | LOG_ERROR(Service_JIT, "rx_mem is null for handle=0x{:08X}", rx_mem_handle); |
| 374 | IPC::ResponseBuilder rb{ctx, 2}; | 378 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -376,7 +380,7 @@ public: | |||
| 376 | return; | 380 | return; |
| 377 | } | 381 | } |
| 378 | 382 | ||
| 379 | auto ro_mem{handle_table.GetObject<Kernel::KCodeMemory>(ro_mem_handle)}; | 383 | auto ro_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(ro_mem_handle)}; |
| 380 | if (ro_mem.IsNull()) { | 384 | if (ro_mem.IsNull()) { |
| 381 | LOG_ERROR(Service_JIT, "ro_mem is null for handle=0x{:08X}", ro_mem_handle); | 385 | LOG_ERROR(Service_JIT, "ro_mem is null for handle=0x{:08X}", ro_mem_handle); |
| 382 | IPC::ResponseBuilder rb{ctx, 2}; | 386 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -384,20 +388,35 @@ public: | |||
| 384 | return; | 388 | return; |
| 385 | } | 389 | } |
| 386 | 390 | ||
| 387 | const CodeRange user_rx{ | 391 | CodeMemory rx, ro; |
| 388 | .offset = GetInteger(rx_mem->GetSourceAddress()), | 392 | Result res; |
| 389 | .size = parameters.rx_size, | ||
| 390 | }; | ||
| 391 | 393 | ||
| 392 | const CodeRange user_ro{ | 394 | res = rx.Initialize(*process, *rx_mem, parameters.rx_size, |
| 393 | .offset = GetInteger(ro_mem->GetSourceAddress()), | 395 | Kernel::Svc::MemoryPermission::ReadExecute, generate_random); |
| 394 | .size = parameters.ro_size, | 396 | if (R_FAILED(res)) { |
| 395 | }; | 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 | } | ||
| 396 | 411 | ||
| 397 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 412 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 398 | rb.Push(ResultSuccess); | 413 | rb.Push(ResultSuccess); |
| 399 | rb.PushIpcInterface<IJitEnvironment>(system, *process, user_rx, user_ro); | 414 | rb.PushIpcInterface<IJitEnvironment>(system, std::move(process), std::move(rx), |
| 415 | std::move(ro)); | ||
| 400 | } | 416 | } |
| 417 | |||
| 418 | private: | ||
| 419 | std::mt19937_64 generate_random{}; | ||
| 401 | }; | 420 | }; |
| 402 | 421 | ||
| 403 | 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/hle/service/ro/ro.cpp b/src/core/hle/service/ro/ro.cpp index 17110d3f1..f0658bb5d 100644 --- a/src/core/hle/service/ro/ro.cpp +++ b/src/core/hle/service/ro/ro.cpp | |||
| @@ -651,10 +651,9 @@ private: | |||
| 651 | void RegisterProcessHandle(HLERequestContext& ctx) { | 651 | void RegisterProcessHandle(HLERequestContext& ctx) { |
| 652 | LOG_DEBUG(Service_LDR, "(called)"); | 652 | LOG_DEBUG(Service_LDR, "(called)"); |
| 653 | 653 | ||
| 654 | auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0)); | 654 | auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0)); |
| 655 | auto client_pid = ctx.GetPID(); | 655 | auto client_pid = ctx.GetPID(); |
| 656 | auto result = interface.RegisterProcessHandle(client_pid, | 656 | auto result = interface.RegisterProcessHandle(client_pid, process.GetPointerUnsafe()); |
| 657 | process_h->DynamicCast<Kernel::KProcess*>()); | ||
| 658 | 657 | ||
| 659 | IPC::ResponseBuilder rb{ctx, 2}; | 658 | IPC::ResponseBuilder rb{ctx, 2}; |
| 660 | rb.Push(result); | 659 | rb.Push(result); |
| @@ -671,12 +670,11 @@ private: | |||
| 671 | 670 | ||
| 672 | IPC::RequestParser rp{ctx}; | 671 | IPC::RequestParser rp{ctx}; |
| 673 | auto params = rp.PopRaw<InputParameters>(); | 672 | auto params = rp.PopRaw<InputParameters>(); |
| 674 | auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0)); | 673 | auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0)); |
| 675 | 674 | ||
| 676 | auto client_pid = ctx.GetPID(); | 675 | auto client_pid = ctx.GetPID(); |
| 677 | auto result = | 676 | auto result = interface.RegisterProcessModuleInfo( |
| 678 | interface.RegisterProcessModuleInfo(client_pid, params.nrr_address, params.nrr_size, | 677 | client_pid, params.nrr_address, params.nrr_size, process.GetPointerUnsafe()); |
| 679 | process_h->DynamicCast<Kernel::KProcess*>()); | ||
| 680 | 678 | ||
| 681 | IPC::ResponseBuilder rb{ctx, 2}; | 679 | IPC::ResponseBuilder rb{ctx, 2}; |
| 682 | rb.Push(result); | 680 | rb.Push(result); |
diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp index 6808247a9..15edb23e0 100644 --- a/src/core/hle/service/server_manager.cpp +++ b/src/core/hle/service/server_manager.cpp | |||
| @@ -47,7 +47,7 @@ ServerManager::~ServerManager() { | |||
| 47 | m_stopped.Wait(); | 47 | m_stopped.Wait(); |
| 48 | m_threads.clear(); | 48 | m_threads.clear(); |
| 49 | 49 | ||
| 50 | // Clean up ports. | 50 | // Clean up server ports. |
| 51 | for (const auto& [port, handler] : m_ports) { | 51 | for (const auto& [port, handler] : m_ports) { |
| 52 | port->Close(); | 52 | port->Close(); |
| 53 | } | 53 | } |
| @@ -97,22 +97,15 @@ Result ServerManager::RegisterNamedService(const std::string& service_name, | |||
| 97 | u32 max_sessions) { | 97 | u32 max_sessions) { |
| 98 | ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects); | 98 | ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects); |
| 99 | 99 | ||
| 100 | // Add the new server to sm:. | 100 | // Add the new server to sm: and get the moved server port. |
| 101 | ASSERT(R_SUCCEEDED( | 101 | Kernel::KServerPort* server_port{}; |
| 102 | m_system.ServiceManager().RegisterService(service_name, max_sessions, handler_factory))); | 102 | R_ASSERT(m_system.ServiceManager().RegisterService(std::addressof(server_port), service_name, |
| 103 | 103 | max_sessions, handler_factory)); | |
| 104 | // Get the registered port. | ||
| 105 | Kernel::KPort* port{}; | ||
| 106 | ASSERT( | ||
| 107 | R_SUCCEEDED(m_system.ServiceManager().GetServicePort(std::addressof(port), service_name))); | ||
| 108 | |||
| 109 | // Open a new reference to the server port. | ||
| 110 | port->GetServerPort().Open(); | ||
| 111 | 104 | ||
| 112 | // Begin tracking the server port. | 105 | // Begin tracking the server port. |
| 113 | { | 106 | { |
| 114 | std::scoped_lock ll{m_list_mutex}; | 107 | std::scoped_lock ll{m_list_mutex}; |
| 115 | m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler_factory)); | 108 | m_ports.emplace(server_port, std::move(handler_factory)); |
| 116 | } | 109 | } |
| 117 | 110 | ||
| 118 | // Signal the wakeup event. | 111 | // Signal the wakeup event. |
| @@ -372,7 +365,7 @@ Result ServerManager::OnSessionEvent(Kernel::KServerSession* session, | |||
| 372 | 365 | ||
| 373 | // Try to receive a message. | 366 | // Try to receive a message. |
| 374 | std::shared_ptr<HLERequestContext> context; | 367 | std::shared_ptr<HLERequestContext> context; |
| 375 | rc = session->ReceiveRequest(&context, manager); | 368 | rc = session->ReceiveRequestHLE(&context, manager); |
| 376 | 369 | ||
| 377 | // If the session has been closed, we're done. | 370 | // If the session has been closed, we're done. |
| 378 | if (rc == Kernel::ResultSessionClosed) { | 371 | if (rc == Kernel::ResultSessionClosed) { |
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 00531b021..39124c5fd 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -203,7 +203,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session, | |||
| 203 | // If emulation was shutdown, we are closing service threads, do not write the response back to | 203 | // If emulation was shutdown, we are closing service threads, do not write the response back to |
| 204 | // memory that may be shutting down as well. | 204 | // memory that may be shutting down as well. |
| 205 | if (system.IsPoweredOn()) { | 205 | if (system.IsPoweredOn()) { |
| 206 | ctx.WriteToOutgoingCommandBuffer(ctx.GetThread()); | 206 | ctx.WriteToOutgoingCommandBuffer(); |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | return result; | 209 | return result; |
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp index 0653779d5..8e637f963 100644 --- a/src/core/hle/service/set/set_sys.cpp +++ b/src/core/hle/service/set/set_sys.cpp | |||
| @@ -507,6 +507,14 @@ void SET_SYS::SetTvSettings(HLERequestContext& ctx) { | |||
| 507 | rb.Push(ResultSuccess); | 507 | rb.Push(ResultSuccess); |
| 508 | } | 508 | } |
| 509 | 509 | ||
| 510 | void SET_SYS::GetDebugModeFlag(HLERequestContext& ctx) { | ||
| 511 | LOG_DEBUG(Service_SET, "called"); | ||
| 512 | |||
| 513 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 514 | rb.Push(ResultSuccess); | ||
| 515 | rb.Push<u32>(0); | ||
| 516 | } | ||
| 517 | |||
| 510 | void SET_SYS::GetQuestFlag(HLERequestContext& ctx) { | 518 | void SET_SYS::GetQuestFlag(HLERequestContext& ctx) { |
| 511 | LOG_WARNING(Service_SET, "(STUBBED) called"); | 519 | LOG_WARNING(Service_SET, "(STUBBED) called"); |
| 512 | 520 | ||
| @@ -926,7 +934,7 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"}, | |||
| 926 | {59, &SET_SYS::SetNetworkSystemClockContext, "SetNetworkSystemClockContext"}, | 934 | {59, &SET_SYS::SetNetworkSystemClockContext, "SetNetworkSystemClockContext"}, |
| 927 | {60, &SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled, "IsUserSystemClockAutomaticCorrectionEnabled"}, | 935 | {60, &SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled, "IsUserSystemClockAutomaticCorrectionEnabled"}, |
| 928 | {61, &SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled, "SetUserSystemClockAutomaticCorrectionEnabled"}, | 936 | {61, &SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled, "SetUserSystemClockAutomaticCorrectionEnabled"}, |
| 929 | {62, nullptr, "GetDebugModeFlag"}, | 937 | {62, &SET_SYS::GetDebugModeFlag, "GetDebugModeFlag"}, |
| 930 | {63, &SET_SYS::GetPrimaryAlbumStorage, "GetPrimaryAlbumStorage"}, | 938 | {63, &SET_SYS::GetPrimaryAlbumStorage, "GetPrimaryAlbumStorage"}, |
| 931 | {64, nullptr, "SetPrimaryAlbumStorage"}, | 939 | {64, nullptr, "SetPrimaryAlbumStorage"}, |
| 932 | {65, nullptr, "GetUsb30EnableFlag"}, | 940 | {65, nullptr, "GetUsb30EnableFlag"}, |
| @@ -1143,6 +1151,8 @@ void SET_SYS::StoreSettings() { | |||
| 1143 | } | 1151 | } |
| 1144 | 1152 | ||
| 1145 | void SET_SYS::StoreSettingsThreadFunc(std::stop_token stop_token) { | 1153 | void SET_SYS::StoreSettingsThreadFunc(std::stop_token stop_token) { |
| 1154 | Common::SetCurrentThreadName("SettingsStore"); | ||
| 1155 | |||
| 1146 | while (Common::StoppableTimedWait(stop_token, std::chrono::minutes(1))) { | 1156 | while (Common::StoppableTimedWait(stop_token, std::chrono::minutes(1))) { |
| 1147 | std::scoped_lock l{m_save_needed_mutex}; | 1157 | std::scoped_lock l{m_save_needed_mutex}; |
| 1148 | if (!std::exchange(m_save_needed, false)) { | 1158 | if (!std::exchange(m_save_needed, false)) { |
diff --git a/src/core/hle/service/set/set_sys.h b/src/core/hle/service/set/set_sys.h index 3785d93d8..853f76fce 100644 --- a/src/core/hle/service/set/set_sys.h +++ b/src/core/hle/service/set/set_sys.h | |||
| @@ -98,6 +98,7 @@ private: | |||
| 98 | void GetSettingsItemValue(HLERequestContext& ctx); | 98 | void GetSettingsItemValue(HLERequestContext& ctx); |
| 99 | void GetTvSettings(HLERequestContext& ctx); | 99 | void GetTvSettings(HLERequestContext& ctx); |
| 100 | void SetTvSettings(HLERequestContext& ctx); | 100 | void SetTvSettings(HLERequestContext& ctx); |
| 101 | void GetDebugModeFlag(HLERequestContext& ctx); | ||
| 101 | void GetQuestFlag(HLERequestContext& ctx); | 102 | void GetQuestFlag(HLERequestContext& ctx); |
| 102 | void GetDeviceTimeZoneLocationName(HLERequestContext& ctx); | 103 | void GetDeviceTimeZoneLocationName(HLERequestContext& ctx); |
| 103 | void SetDeviceTimeZoneLocationName(HLERequestContext& ctx); | 104 | void SetDeviceTimeZoneLocationName(HLERequestContext& ctx); |
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 296ee6e89..1095dcf6c 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp | |||
| @@ -29,8 +29,7 @@ ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} { | |||
| 29 | 29 | ||
| 30 | ServiceManager::~ServiceManager() { | 30 | ServiceManager::~ServiceManager() { |
| 31 | for (auto& [name, port] : service_ports) { | 31 | for (auto& [name, port] : service_ports) { |
| 32 | port->GetClientPort().Close(); | 32 | port->Close(); |
| 33 | port->GetServerPort().Close(); | ||
| 34 | } | 33 | } |
| 35 | 34 | ||
| 36 | if (deferral_event) { | 35 | if (deferral_event) { |
| @@ -50,8 +49,8 @@ static Result ValidateServiceName(const std::string& name) { | |||
| 50 | return ResultSuccess; | 49 | return ResultSuccess; |
| 51 | } | 50 | } |
| 52 | 51 | ||
| 53 | Result ServiceManager::RegisterService(std::string name, u32 max_sessions, | 52 | Result ServiceManager::RegisterService(Kernel::KServerPort** out_server_port, std::string name, |
| 54 | SessionRequestHandlerFactory handler) { | 53 | u32 max_sessions, SessionRequestHandlerFactory handler) { |
| 55 | R_TRY(ValidateServiceName(name)); | 54 | R_TRY(ValidateServiceName(name)); |
| 56 | 55 | ||
| 57 | std::scoped_lock lk{lock}; | 56 | std::scoped_lock lk{lock}; |
| @@ -66,13 +65,17 @@ Result ServiceManager::RegisterService(std::string name, u32 max_sessions, | |||
| 66 | // Register the port. | 65 | // Register the port. |
| 67 | Kernel::KPort::Register(kernel, port); | 66 | Kernel::KPort::Register(kernel, port); |
| 68 | 67 | ||
| 69 | service_ports.emplace(name, port); | 68 | service_ports.emplace(name, std::addressof(port->GetClientPort())); |
| 70 | registered_services.emplace(name, handler); | 69 | registered_services.emplace(name, handler); |
| 71 | if (deferral_event) { | 70 | if (deferral_event) { |
| 72 | deferral_event->Signal(); | 71 | deferral_event->Signal(); |
| 73 | } | 72 | } |
| 74 | 73 | ||
| 75 | return ResultSuccess; | 74 | // Set our output. |
| 75 | *out_server_port = std::addressof(port->GetServerPort()); | ||
| 76 | |||
| 77 | // We succeeded. | ||
| 78 | R_SUCCEED(); | ||
| 76 | } | 79 | } |
| 77 | 80 | ||
| 78 | Result ServiceManager::UnregisterService(const std::string& name) { | 81 | Result ServiceManager::UnregisterService(const std::string& name) { |
| @@ -91,7 +94,8 @@ Result ServiceManager::UnregisterService(const std::string& name) { | |||
| 91 | return ResultSuccess; | 94 | return ResultSuccess; |
| 92 | } | 95 | } |
| 93 | 96 | ||
| 94 | Result ServiceManager::GetServicePort(Kernel::KPort** out_port, const std::string& name) { | 97 | Result ServiceManager::GetServicePort(Kernel::KClientPort** out_client_port, |
| 98 | const std::string& name) { | ||
| 95 | R_TRY(ValidateServiceName(name)); | 99 | R_TRY(ValidateServiceName(name)); |
| 96 | 100 | ||
| 97 | std::scoped_lock lk{lock}; | 101 | std::scoped_lock lk{lock}; |
| @@ -101,7 +105,7 @@ Result ServiceManager::GetServicePort(Kernel::KPort** out_port, const std::strin | |||
| 101 | return Service::SM::ResultNotRegistered; | 105 | return Service::SM::ResultNotRegistered; |
| 102 | } | 106 | } |
| 103 | 107 | ||
| 104 | *out_port = it->second; | 108 | *out_client_port = it->second; |
| 105 | return ResultSuccess; | 109 | return ResultSuccess; |
| 106 | } | 110 | } |
| 107 | 111 | ||
| @@ -172,8 +176,8 @@ Result SM::GetServiceImpl(Kernel::KClientSession** out_client_session, HLEReques | |||
| 172 | std::string name(PopServiceName(rp)); | 176 | std::string name(PopServiceName(rp)); |
| 173 | 177 | ||
| 174 | // Find the named port. | 178 | // Find the named port. |
| 175 | Kernel::KPort* port{}; | 179 | Kernel::KClientPort* client_port{}; |
| 176 | auto port_result = service_manager.GetServicePort(&port, name); | 180 | auto port_result = service_manager.GetServicePort(&client_port, name); |
| 177 | if (port_result == Service::SM::ResultInvalidServiceName) { | 181 | if (port_result == Service::SM::ResultInvalidServiceName) { |
| 178 | LOG_ERROR(Service_SM, "Invalid service name '{}'", name); | 182 | LOG_ERROR(Service_SM, "Invalid service name '{}'", name); |
| 179 | return Service::SM::ResultInvalidServiceName; | 183 | return Service::SM::ResultInvalidServiceName; |
| @@ -187,7 +191,7 @@ Result SM::GetServiceImpl(Kernel::KClientSession** out_client_session, HLEReques | |||
| 187 | 191 | ||
| 188 | // Create a new session. | 192 | // Create a new session. |
| 189 | Kernel::KClientSession* session{}; | 193 | Kernel::KClientSession* session{}; |
| 190 | if (const auto result = port->GetClientPort().CreateSession(&session); result.IsError()) { | 194 | if (const auto result = client_port->CreateSession(&session); result.IsError()) { |
| 191 | LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw); | 195 | LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw); |
| 192 | return result; | 196 | return result; |
| 193 | } | 197 | } |
| @@ -221,7 +225,9 @@ void SM::RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_s | |||
| 221 | LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name, | 225 | LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name, |
| 222 | max_session_count, is_light); | 226 | max_session_count, is_light); |
| 223 | 227 | ||
| 224 | if (const auto result = service_manager.RegisterService(name, max_session_count, nullptr); | 228 | Kernel::KServerPort* server_port{}; |
| 229 | if (const auto result = service_manager.RegisterService(std::addressof(server_port), name, | ||
| 230 | max_session_count, nullptr); | ||
| 225 | result.IsError()) { | 231 | result.IsError()) { |
| 226 | LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", result.raw); | 232 | LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", result.raw); |
| 227 | IPC::ResponseBuilder rb{ctx, 2}; | 233 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -229,13 +235,9 @@ void SM::RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_s | |||
| 229 | return; | 235 | return; |
| 230 | } | 236 | } |
| 231 | 237 | ||
| 232 | auto* port = Kernel::KPort::Create(kernel); | ||
| 233 | port->Initialize(ServerSessionCountMax, is_light, 0); | ||
| 234 | SCOPE_EXIT({ port->GetClientPort().Close(); }); | ||
| 235 | |||
| 236 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; | 238 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; |
| 237 | rb.Push(ResultSuccess); | 239 | rb.Push(ResultSuccess); |
| 238 | rb.PushMoveObjects(port->GetServerPort()); | 240 | rb.PushMoveObjects(server_port); |
| 239 | } | 241 | } |
| 240 | 242 | ||
| 241 | void SM::UnregisterService(HLERequestContext& ctx) { | 243 | void SM::UnregisterService(HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index ff74f588a..4ae32a9c1 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h | |||
| @@ -56,10 +56,10 @@ public: | |||
| 56 | explicit ServiceManager(Kernel::KernelCore& kernel_); | 56 | explicit ServiceManager(Kernel::KernelCore& kernel_); |
| 57 | ~ServiceManager(); | 57 | ~ServiceManager(); |
| 58 | 58 | ||
| 59 | Result RegisterService(std::string name, u32 max_sessions, | 59 | Result RegisterService(Kernel::KServerPort** out_server_port, std::string name, |
| 60 | SessionRequestHandlerFactory handler_factory); | 60 | u32 max_sessions, SessionRequestHandlerFactory handler_factory); |
| 61 | Result UnregisterService(const std::string& name); | 61 | Result UnregisterService(const std::string& name); |
| 62 | Result GetServicePort(Kernel::KPort** out_port, const std::string& name); | 62 | Result GetServicePort(Kernel::KClientPort** out_client_port, const std::string& name); |
| 63 | 63 | ||
| 64 | template <Common::DerivedFrom<SessionRequestHandler> T> | 64 | template <Common::DerivedFrom<SessionRequestHandler> T> |
| 65 | std::shared_ptr<T> GetService(const std::string& service_name) const { | 65 | std::shared_ptr<T> GetService(const std::string& service_name) const { |
| @@ -84,7 +84,7 @@ private: | |||
| 84 | /// Map of registered services, retrieved using GetServicePort. | 84 | /// Map of registered services, retrieved using GetServicePort. |
| 85 | std::mutex lock; | 85 | std::mutex lock; |
| 86 | std::unordered_map<std::string, SessionRequestHandlerFactory> registered_services; | 86 | std::unordered_map<std::string, SessionRequestHandlerFactory> registered_services; |
| 87 | std::unordered_map<std::string, Kernel::KPort*> service_ports; | 87 | std::unordered_map<std::string, Kernel::KClientPort*> service_ports; |
| 88 | 88 | ||
| 89 | /// Kernel context | 89 | /// Kernel context |
| 90 | Kernel::KernelCore& kernel; | 90 | Kernel::KernelCore& kernel; |
diff --git a/src/core/hle/service/sm/sm_controller.cpp b/src/core/hle/service/sm/sm_controller.cpp index 7dce28fe0..7f0fb91d0 100644 --- a/src/core/hle/service/sm/sm_controller.cpp +++ b/src/core/hle/service/sm/sm_controller.cpp | |||
| @@ -28,7 +28,6 @@ void Controller::ConvertCurrentObjectToDomain(HLERequestContext& ctx) { | |||
| 28 | void Controller::CloneCurrentObject(HLERequestContext& ctx) { | 28 | void Controller::CloneCurrentObject(HLERequestContext& ctx) { |
| 29 | LOG_DEBUG(Service, "called"); | 29 | LOG_DEBUG(Service, "called"); |
| 30 | 30 | ||
| 31 | auto& process = *ctx.GetThread().GetOwnerProcess(); | ||
| 32 | auto session_manager = ctx.GetManager(); | 31 | auto session_manager = ctx.GetManager(); |
| 33 | 32 | ||
| 34 | // FIXME: this is duplicated from the SVC, it should just call it instead | 33 | // FIXME: this is duplicated from the SVC, it should just call it instead |
| @@ -36,11 +35,11 @@ void Controller::CloneCurrentObject(HLERequestContext& ctx) { | |||
| 36 | 35 | ||
| 37 | // Reserve a new session from the process resource limit. | 36 | // Reserve a new session from the process resource limit. |
| 38 | Kernel::KScopedResourceReservation session_reservation( | 37 | Kernel::KScopedResourceReservation session_reservation( |
| 39 | &process, Kernel::LimitableResource::SessionCountMax); | 38 | Kernel::GetCurrentProcessPointer(kernel), Kernel::LimitableResource::SessionCountMax); |
| 40 | ASSERT(session_reservation.Succeeded()); | 39 | ASSERT(session_reservation.Succeeded()); |
| 41 | 40 | ||
| 42 | // Create the session. | 41 | // Create the session. |
| 43 | Kernel::KSession* session = Kernel::KSession::Create(system.Kernel()); | 42 | Kernel::KSession* session = Kernel::KSession::Create(kernel); |
| 44 | ASSERT(session != nullptr); | 43 | ASSERT(session != nullptr); |
| 45 | 44 | ||
| 46 | // Initialize the session. | 45 | // Initialize the session. |
| @@ -50,7 +49,7 @@ void Controller::CloneCurrentObject(HLERequestContext& ctx) { | |||
| 50 | session_reservation.Commit(); | 49 | session_reservation.Commit(); |
| 51 | 50 | ||
| 52 | // Register the session. | 51 | // Register the session. |
| 53 | Kernel::KSession::Register(system.Kernel(), session); | 52 | Kernel::KSession::Register(kernel, session); |
| 54 | 53 | ||
| 55 | // Register with server manager. | 54 | // Register with server manager. |
| 56 | session_manager->GetServerManager().RegisterSession(&session->GetServerSession(), | 55 | session_manager->GetServerManager().RegisterSession(&session->GetServerSession(), |
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 60ee78e89..c9f8707b7 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp | |||
| @@ -129,9 +129,10 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 129 | } | 129 | } |
| 130 | metadata.Print(); | 130 | metadata.Print(); |
| 131 | 131 | ||
| 132 | // Enable NCE only for programs with 39-bit address space. | 132 | // Enable NCE only for applications with 39-bit address space. |
| 133 | const bool is_39bit = | 133 | const bool is_39bit = |
| 134 | metadata.GetAddressSpaceType() == FileSys::ProgramAddressSpaceType::Is39Bit; | 134 | metadata.GetAddressSpaceType() == FileSys::ProgramAddressSpaceType::Is39Bit; |
| 135 | const bool is_application = metadata.GetPoolPartition() == FileSys::PoolPartition::Application; | ||
| 135 | Settings::SetNceEnabled(is_39bit); | 136 | Settings::SetNceEnabled(is_39bit); |
| 136 | 137 | ||
| 137 | const std::array static_modules = {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", | 138 | const std::array static_modules = {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", |
| @@ -147,7 +148,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 147 | 148 | ||
| 148 | const auto GetPatcher = [&](size_t i) -> Core::NCE::Patcher* { | 149 | const auto GetPatcher = [&](size_t i) -> Core::NCE::Patcher* { |
| 149 | #ifdef HAS_NCE | 150 | #ifdef HAS_NCE |
| 150 | if (Settings::IsNceEnabled()) { | 151 | if (is_application && Settings::IsNceEnabled()) { |
| 151 | return &module_patchers[i]; | 152 | return &module_patchers[i]; |
| 152 | } | 153 | } |
| 153 | #endif | 154 | #endif |
| @@ -175,7 +176,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 175 | 176 | ||
| 176 | // Enable direct memory mapping in case of NCE. | 177 | // Enable direct memory mapping in case of NCE. |
| 177 | const u64 fastmem_base = [&]() -> size_t { | 178 | const u64 fastmem_base = [&]() -> size_t { |
| 178 | if (Settings::IsNceEnabled()) { | 179 | if (is_application && Settings::IsNceEnabled()) { |
| 179 | auto& buffer = system.DeviceMemory().buffer; | 180 | auto& buffer = system.DeviceMemory().buffer; |
| 180 | buffer.EnableDirectMappedAddress(); | 181 | buffer.EnableDirectMappedAddress(); |
| 181 | return reinterpret_cast<u64>(buffer.VirtualBasePointer()); | 182 | return reinterpret_cast<u64>(buffer.VirtualBasePointer()); |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 169bf4c8c..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" |
| @@ -45,11 +46,25 @@ struct Memory::Impl { | |||
| 45 | 46 | ||
| 46 | void SetCurrentPageTable(Kernel::KProcess& process) { | 47 | void SetCurrentPageTable(Kernel::KProcess& process) { |
| 47 | current_page_table = &process.GetPageTable().GetImpl(); | 48 | current_page_table = &process.GetPageTable().GetImpl(); |
| 48 | current_page_table->fastmem_arena = system.DeviceMemory().buffer.VirtualBasePointer(); | 49 | |
| 50 | if (std::addressof(process) == system.ApplicationProcess() && | ||
| 51 | Settings::IsFastmemEnabled()) { | ||
| 52 | current_page_table->fastmem_arena = system.DeviceMemory().buffer.VirtualBasePointer(); | ||
| 53 | } else { | ||
| 54 | current_page_table->fastmem_arena = nullptr; | ||
| 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 | ||
| 49 | } | 63 | } |
| 50 | 64 | ||
| 51 | void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, | 65 | void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, |
| 52 | Common::PhysicalAddress target, Common::MemoryPermission perms) { | 66 | Common::PhysicalAddress target, Common::MemoryPermission perms, |
| 67 | bool separate_heap) { | ||
| 53 | 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); |
| 54 | 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)); |
| 55 | ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}", | 70 | ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}", |
| @@ -57,20 +72,21 @@ struct Memory::Impl { | |||
| 57 | MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, target, | 72 | MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, target, |
| 58 | Common::PageType::Memory); | 73 | Common::PageType::Memory); |
| 59 | 74 | ||
| 60 | if (Settings::IsFastmemEnabled()) { | 75 | if (current_page_table->fastmem_arena) { |
| 61 | system.DeviceMemory().buffer.Map(GetInteger(base), | 76 | buffer->Map(GetInteger(base), GetInteger(target) - DramMemoryMap::Base, size, perms, |
| 62 | GetInteger(target) - DramMemoryMap::Base, size, perms); | 77 | separate_heap); |
| 63 | } | 78 | } |
| 64 | } | 79 | } |
| 65 | 80 | ||
| 66 | 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) { | ||
| 67 | 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); |
| 68 | 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)); |
| 69 | MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, 0, | 85 | MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, 0, |
| 70 | Common::PageType::Unmapped); | 86 | Common::PageType::Unmapped); |
| 71 | 87 | ||
| 72 | if (Settings::IsFastmemEnabled()) { | 88 | if (current_page_table->fastmem_arena) { |
| 73 | system.DeviceMemory().buffer.Unmap(GetInteger(base), size); | 89 | buffer->Unmap(GetInteger(base), size, separate_heap); |
| 74 | } | 90 | } |
| 75 | } | 91 | } |
| 76 | 92 | ||
| @@ -79,17 +95,7 @@ struct Memory::Impl { | |||
| 79 | ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size); | 95 | ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size); |
| 80 | ASSERT_MSG((vaddr & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", vaddr); | 96 | ASSERT_MSG((vaddr & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", vaddr); |
| 81 | 97 | ||
| 82 | if (!Settings::IsFastmemEnabled()) { | 98 | if (!current_page_table->fastmem_arena) { |
| 83 | return; | ||
| 84 | } | ||
| 85 | |||
| 86 | const bool is_r = True(perms & Common::MemoryPermission::Read); | ||
| 87 | const bool is_w = True(perms & Common::MemoryPermission::Write); | ||
| 88 | const bool is_x = | ||
| 89 | True(perms & Common::MemoryPermission::Execute) && Settings::IsNceEnabled(); | ||
| 90 | |||
| 91 | if (!current_page_table) { | ||
| 92 | system.DeviceMemory().buffer.Protect(vaddr, size, is_r, is_w, is_x); | ||
| 93 | return; | 99 | return; |
| 94 | } | 100 | } |
| 95 | 101 | ||
| @@ -101,8 +107,7 @@ struct Memory::Impl { | |||
| 101 | switch (page_type) { | 107 | switch (page_type) { |
| 102 | case Common::PageType::RasterizerCachedMemory: | 108 | case Common::PageType::RasterizerCachedMemory: |
| 103 | if (protect_bytes > 0) { | 109 | if (protect_bytes > 0) { |
| 104 | system.DeviceMemory().buffer.Protect(protect_begin, protect_bytes, is_r, is_w, | 110 | buffer->Protect(protect_begin, protect_bytes, perms); |
| 105 | is_x); | ||
| 106 | protect_bytes = 0; | 111 | protect_bytes = 0; |
| 107 | } | 112 | } |
| 108 | break; | 113 | break; |
| @@ -115,7 +120,7 @@ struct Memory::Impl { | |||
| 115 | } | 120 | } |
| 116 | 121 | ||
| 117 | if (protect_bytes > 0) { | 122 | if (protect_bytes > 0) { |
| 118 | system.DeviceMemory().buffer.Protect(protect_begin, protect_bytes, is_r, is_w, is_x); | 123 | buffer->Protect(protect_begin, protect_bytes, perms); |
| 119 | } | 124 | } |
| 120 | } | 125 | } |
| 121 | 126 | ||
| @@ -239,7 +244,7 @@ struct Memory::Impl { | |||
| 239 | 244 | ||
| 240 | bool WalkBlock(const Common::ProcessAddress addr, const std::size_t size, auto on_unmapped, | 245 | bool WalkBlock(const Common::ProcessAddress addr, const std::size_t size, auto on_unmapped, |
| 241 | auto on_memory, auto on_rasterizer, auto increment) { | 246 | auto on_memory, auto on_rasterizer, auto increment) { |
| 242 | const auto& page_table = system.ApplicationProcess()->GetPageTable().GetImpl(); | 247 | const auto& page_table = *current_page_table; |
| 243 | std::size_t remaining_size = size; | 248 | std::size_t remaining_size = size; |
| 244 | std::size_t page_index = addr >> YUZU_PAGEBITS; | 249 | std::size_t page_index = addr >> YUZU_PAGEBITS; |
| 245 | std::size_t page_offset = addr & YUZU_PAGEMASK; | 250 | std::size_t page_offset = addr & YUZU_PAGEMASK; |
| @@ -484,8 +489,10 @@ struct Memory::Impl { | |||
| 484 | return; | 489 | return; |
| 485 | } | 490 | } |
| 486 | 491 | ||
| 487 | if (Settings::IsFastmemEnabled()) { | 492 | if (current_page_table->fastmem_arena) { |
| 488 | 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); | ||
| 489 | } | 496 | } |
| 490 | 497 | ||
| 491 | // Iterate over a contiguous CPU address space, marking/unmarking the region. | 498 | // Iterate over a contiguous CPU address space, marking/unmarking the region. |
| @@ -541,10 +548,15 @@ struct Memory::Impl { | |||
| 541 | return; | 548 | return; |
| 542 | } | 549 | } |
| 543 | 550 | ||
| 544 | if (Settings::IsFastmemEnabled()) { | 551 | if (current_page_table->fastmem_arena) { |
| 545 | const bool is_read_enable = | 552 | Common::MemoryPermission perm{}; |
| 546 | !Settings::values.use_reactive_flushing.GetValue() || !cached; | 553 | if (!Settings::values.use_reactive_flushing.GetValue() || !cached) { |
| 547 | 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); | ||
| 548 | } | 560 | } |
| 549 | 561 | ||
| 550 | // 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 |
| @@ -855,6 +867,13 @@ struct Memory::Impl { | |||
| 855 | std::array<GPUDirtyState, Core::Hardware::NUM_CPU_CORES> rasterizer_write_areas{}; | 867 | std::array<GPUDirtyState, Core::Hardware::NUM_CPU_CORES> rasterizer_write_areas{}; |
| 856 | std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers; | 868 | std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers; |
| 857 | 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 | ||
| 858 | }; | 877 | }; |
| 859 | 878 | ||
| 860 | Memory::Memory(Core::System& system_) : system{system_} { | 879 | Memory::Memory(Core::System& system_) : system{system_} { |
| @@ -872,12 +891,14 @@ void Memory::SetCurrentPageTable(Kernel::KProcess& process) { | |||
| 872 | } | 891 | } |
| 873 | 892 | ||
| 874 | 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, |
| 875 | Common::PhysicalAddress target, Common::MemoryPermission perms) { | 894 | Common::PhysicalAddress target, Common::MemoryPermission perms, |
| 876 | impl->MapMemoryRegion(page_table, base, size, target, perms); | 895 | bool separate_heap) { |
| 896 | impl->MapMemoryRegion(page_table, base, size, target, perms, separate_heap); | ||
| 877 | } | 897 | } |
| 878 | 898 | ||
| 879 | 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, |
| 880 | impl->UnmapRegion(page_table, base, size); | 900 | bool separate_heap) { |
| 901 | impl->UnmapRegion(page_table, base, size, separate_heap); | ||
| 881 | } | 902 | } |
| 882 | 903 | ||
| 883 | 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, |
| @@ -886,8 +907,7 @@ void Memory::ProtectRegion(Common::PageTable& page_table, Common::ProcessAddress | |||
| 886 | } | 907 | } |
| 887 | 908 | ||
| 888 | bool Memory::IsValidVirtualAddress(const Common::ProcessAddress vaddr) const { | 909 | bool Memory::IsValidVirtualAddress(const Common::ProcessAddress vaddr) const { |
| 889 | const Kernel::KProcess& process = *system.ApplicationProcess(); | 910 | const auto& page_table = *impl->current_page_table; |
| 890 | const auto& page_table = process.GetPageTable().GetImpl(); | ||
| 891 | const size_t page = vaddr >> YUZU_PAGEBITS; | 911 | const size_t page = vaddr >> YUZU_PAGEBITS; |
| 892 | if (page >= page_table.pointers.size()) { | 912 | if (page >= page_table.pointers.size()) { |
| 893 | return false; | 913 | return false; |
| @@ -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..20de91ff4 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,59 @@ 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 | void Config::WriteDoubleSetting(const std::string& key, const double& value, |
| 756 | std::string string_default; | 766 | const std::optional<double>& default_value, |
| 757 | if constexpr (std::is_same_v<Type, std::string>) { | 767 | const std::optional<bool>& use_global) { |
| 758 | saved_value.append(AdjustOutputString(value)); | 768 | std::optional<std::string> string_default = std::nullopt; |
| 759 | if (default_value.has_value()) { | 769 | if (default_value.has_value()) { |
| 760 | string_default.append(AdjustOutputString(default_value.value())); | 770 | string_default = std::make_optional(ToString(default_value.value())); |
| 761 | } | ||
| 762 | } else { | ||
| 763 | saved_value.append(AdjustOutputString(ToString(value))); | ||
| 764 | if (default_value.has_value()) { | ||
| 765 | string_default.append(ToString(default_value.value())); | ||
| 766 | } | ||
| 767 | } | 771 | } |
| 772 | WritePreparedSetting(key, AdjustOutputString(ToString(value)), string_default, use_global); | ||
| 773 | } | ||
| 768 | 774 | ||
| 769 | if (default_value.has_value() && use_global.has_value()) { | 775 | void Config::WriteStringSetting(const std::string& key, const std::string& value, |
| 776 | const std::optional<std::string>& default_value, | ||
| 777 | const std::optional<bool>& use_global) { | ||
| 778 | std::optional string_default = default_value; | ||
| 779 | if (default_value.has_value()) { | ||
| 780 | string_default.value().append(AdjustOutputString(default_value.value())); | ||
| 781 | } | ||
| 782 | WritePreparedSetting(key, AdjustOutputString(value), string_default, use_global); | ||
| 783 | } | ||
| 784 | |||
| 785 | void Config::WritePreparedSetting(const std::string& key, const std::string& adjusted_value, | ||
| 786 | const std::optional<std::string>& adjusted_default_value, | ||
| 787 | const std::optional<bool>& use_global) { | ||
| 788 | std::string full_key = GetFullKey(key, false); | ||
| 789 | if (adjusted_default_value.has_value() && use_global.has_value()) { | ||
| 770 | if (!global) { | 790 | if (!global) { |
| 771 | WriteSettingInternal(std::string(full_key).append("\\global"), | 791 | WriteString(std::string(full_key).append("\\global"), ToString(use_global.value())); |
| 772 | ToString(use_global.value())); | ||
| 773 | } | 792 | } |
| 774 | if (global || use_global.value() == false) { | 793 | if (global || use_global.value() == false) { |
| 775 | WriteSettingInternal(std::string(full_key).append("\\default"), | 794 | WriteString(std::string(full_key).append("\\default"), |
| 776 | ToString(string_default == saved_value)); | 795 | ToString(adjusted_default_value == adjusted_value)); |
| 777 | WriteSettingInternal(full_key, saved_value); | 796 | WriteString(full_key, adjusted_value); |
| 778 | } | 797 | } |
| 779 | } else if (default_value.has_value() && !use_global.has_value()) { | 798 | } else if (adjusted_default_value.has_value() && !use_global.has_value()) { |
| 780 | WriteSettingInternal(std::string(full_key).append("\\default"), | 799 | WriteString(std::string(full_key).append("\\default"), |
| 781 | ToString(string_default == saved_value)); | 800 | ToString(adjusted_default_value == adjusted_value)); |
| 782 | WriteSettingInternal(full_key, saved_value); | 801 | WriteString(full_key, adjusted_value); |
| 783 | } else { | 802 | } else { |
| 784 | WriteSettingInternal(full_key, saved_value); | 803 | WriteString(full_key, adjusted_value); |
| 785 | } | 804 | } |
| 786 | } | 805 | } |
| 787 | 806 | ||
| 788 | void Config::WriteSettingInternal(const std::string& key, const std::string& value) { | 807 | void Config::WriteString(const std::string& key, const std::string& value) { |
| 789 | config->SetValue(GetSection().c_str(), key.c_str(), value.c_str()); | 808 | config->SetValue(GetSection().c_str(), key.c_str(), value.c_str()); |
| 790 | } | 809 | } |
| 791 | 810 | ||
| @@ -861,17 +880,18 @@ void Config::WriteSettingGeneric(const Settings::BasicSetting* const setting) { | |||
| 861 | std::string key = AdjustKey(setting->GetLabel()); | 880 | std::string key = AdjustKey(setting->GetLabel()); |
| 862 | if (setting->Switchable()) { | 881 | if (setting->Switchable()) { |
| 863 | if (!global) { | 882 | if (!global) { |
| 864 | WriteSetting(std::string(key).append("\\use_global"), setting->UsingGlobal()); | 883 | WriteBooleanSetting(std::string(key).append("\\use_global"), setting->UsingGlobal()); |
| 865 | } | 884 | } |
| 866 | if (global || !setting->UsingGlobal()) { | 885 | if (global || !setting->UsingGlobal()) { |
| 867 | WriteSetting(std::string(key).append("\\default"), | 886 | auto value = global ? setting->ToStringGlobal() : setting->ToString(); |
| 868 | setting->ToString() == setting->DefaultToString()); | 887 | WriteBooleanSetting(std::string(key).append("\\default"), |
| 869 | WriteSetting(key, setting->ToString()); | 888 | value == setting->DefaultToString()); |
| 889 | WriteStringSetting(key, value); | ||
| 870 | } | 890 | } |
| 871 | } else if (global) { | 891 | } else if (global) { |
| 872 | WriteSetting(std::string(key).append("\\default"), | 892 | WriteBooleanSetting(std::string(key).append("\\default"), |
| 873 | setting->ToString() == setting->DefaultToString()); | 893 | setting->ToString() == setting->DefaultToString()); |
| 874 | WriteSetting(key, setting->ToString()); | 894 | WriteStringSetting(key, setting->ToString()); |
| 875 | } | 895 | } |
| 876 | } | 896 | } |
| 877 | 897 | ||
diff --git a/src/frontend_common/config.h b/src/frontend_common/config.h index b3812af17..b01631649 100644 --- a/src/frontend_common/config.h +++ b/src/frontend_common/config.h | |||
| @@ -154,11 +154,26 @@ 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 | void WriteDoubleSetting(const std::string& key, const double& value, |
| 161 | void WriteSettingInternal(const std::string& key, const std::string& value); | 161 | const std::optional<double>& default_value = std::nullopt, |
| 162 | const std::optional<bool>& use_global = std::nullopt); | ||
| 163 | void WriteStringSetting(const std::string& key, const std::string& value, | ||
| 164 | const std::optional<std::string>& default_value = std::nullopt, | ||
| 165 | const std::optional<bool>& use_global = std::nullopt); | ||
| 166 | template <typename T> | ||
| 167 | std::enable_if_t<std::is_integral_v<T>> WriteIntegerSetting( | ||
| 168 | const std::string& key, const T& value, | ||
| 169 | const std::optional<T>& default_value = std::nullopt, | ||
| 170 | const std::optional<bool>& use_global = std::nullopt) { | ||
| 171 | std::optional<std::string> string_default = std::nullopt; | ||
| 172 | if (default_value.has_value()) { | ||
| 173 | string_default = std::make_optional(ToString(default_value.value())); | ||
| 174 | } | ||
| 175 | WritePreparedSetting(key, AdjustOutputString(ToString(value)), string_default, use_global); | ||
| 176 | } | ||
| 162 | 177 | ||
| 163 | void ReadCategory(Settings::Category category); | 178 | void ReadCategory(Settings::Category category); |
| 164 | void WriteCategory(Settings::Category category); | 179 | void WriteCategory(Settings::Category category); |
| @@ -175,8 +190,10 @@ protected: | |||
| 175 | return value_ ? "true" : "false"; | 190 | return value_ ? "true" : "false"; |
| 176 | } else if constexpr (std::is_same_v<T, u64>) { | 191 | } else if constexpr (std::is_same_v<T, u64>) { |
| 177 | return std::to_string(static_cast<u64>(value_)); | 192 | return std::to_string(static_cast<u64>(value_)); |
| 178 | } else { | 193 | } else if constexpr (std::is_same_v<T, s64>) { |
| 179 | return std::to_string(static_cast<s64>(value_)); | 194 | return std::to_string(static_cast<s64>(value_)); |
| 195 | } else { | ||
| 196 | return std::to_string(value_); | ||
| 180 | } | 197 | } |
| 181 | } | 198 | } |
| 182 | 199 | ||
| @@ -197,9 +214,13 @@ protected: | |||
| 197 | const bool global; | 214 | const bool global; |
| 198 | 215 | ||
| 199 | private: | 216 | private: |
| 200 | inline static std::array<char, 19> special_characters = {'!', '#', '$', '%', '^', '&', '*', | 217 | void WritePreparedSetting(const std::string& key, const std::string& adjusted_value, |
| 201 | '|', ';', '\'', '\"', ',', '<', '.', | 218 | const std::optional<std::string>& adjusted_default_value, |
| 202 | '>', '?', '`', '~', '='}; | 219 | const std::optional<bool>& use_global); |
| 220 | void WriteString(const std::string& key, const std::string& value); | ||
| 221 | |||
| 222 | inline static std::array<char, 18> special_characters = { | ||
| 223 | '!', '#', '$', '%', '^', '&', '*', '|', ';', '\'', '\"', ',', '<', '>', '?', '`', '~', '='}; | ||
| 203 | 224 | ||
| 204 | struct ConfigArray { | 225 | struct ConfigArray { |
| 205 | std::string name; | 226 | std::string name; |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp index e5a78a914..feca5105f 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp | |||
| @@ -74,6 +74,11 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) { | |||
| 74 | case IR::Attribute::ClipDistance7: { | 74 | case IR::Attribute::ClipDistance7: { |
| 75 | const u32 base{static_cast<u32>(IR::Attribute::ClipDistance0)}; | 75 | const u32 base{static_cast<u32>(IR::Attribute::ClipDistance0)}; |
| 76 | const u32 index{static_cast<u32>(attr) - base}; | 76 | const u32 index{static_cast<u32>(attr) - base}; |
| 77 | if (index >= ctx.profile.max_user_clip_distances) { | ||
| 78 | LOG_WARNING(Shader, "Ignoring clip distance store {} >= {} supported", index, | ||
| 79 | ctx.profile.max_user_clip_distances); | ||
| 80 | return std::nullopt; | ||
| 81 | } | ||
| 77 | const Id clip_num{ctx.Const(index)}; | 82 | const Id clip_num{ctx.Const(index)}; |
| 78 | return OutputAccessChain(ctx, ctx.output_f32, ctx.clip_distances, clip_num); | 83 | return OutputAccessChain(ctx, ctx.output_f32, ctx.clip_distances, clip_num); |
| 79 | } | 84 | } |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp index 22ceca19c..800754554 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp | |||
| @@ -214,16 +214,16 @@ Id TextureImage(EmitContext& ctx, IR::TextureInstInfo info, const IR::Value& ind | |||
| 214 | } | 214 | } |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | Id Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) { | 217 | std::pair<Id, bool> Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) { |
| 218 | if (!index.IsImmediate() || index.U32() != 0) { | 218 | if (!index.IsImmediate() || index.U32() != 0) { |
| 219 | throw NotImplementedException("Indirect image indexing"); | 219 | throw NotImplementedException("Indirect image indexing"); |
| 220 | } | 220 | } |
| 221 | if (info.type == TextureType::Buffer) { | 221 | if (info.type == TextureType::Buffer) { |
| 222 | const ImageBufferDefinition def{ctx.image_buffers.at(info.descriptor_index)}; | 222 | const ImageBufferDefinition def{ctx.image_buffers.at(info.descriptor_index)}; |
| 223 | return ctx.OpLoad(def.image_type, def.id); | 223 | return {ctx.OpLoad(def.image_type, def.id), def.is_integer}; |
| 224 | } else { | 224 | } else { |
| 225 | const ImageDefinition def{ctx.images.at(info.descriptor_index)}; | 225 | const ImageDefinition def{ctx.images.at(info.descriptor_index)}; |
| 226 | return ctx.OpLoad(def.image_type, def.id); | 226 | return {ctx.OpLoad(def.image_type, def.id), def.is_integer}; |
| 227 | } | 227 | } |
| 228 | } | 228 | } |
| 229 | 229 | ||
| @@ -566,13 +566,23 @@ Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id co | |||
| 566 | LOG_WARNING(Shader_SPIRV, "Typeless image read not supported by host"); | 566 | LOG_WARNING(Shader_SPIRV, "Typeless image read not supported by host"); |
| 567 | return ctx.ConstantNull(ctx.U32[4]); | 567 | return ctx.ConstantNull(ctx.U32[4]); |
| 568 | } | 568 | } |
| 569 | return Emit(&EmitContext::OpImageSparseRead, &EmitContext::OpImageRead, ctx, inst, ctx.U32[4], | 569 | const auto [image, is_integer] = Image(ctx, index, info); |
| 570 | Image(ctx, index, info), coords, std::nullopt, std::span<const Id>{}); | 570 | const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]}; |
| 571 | Id color{Emit(&EmitContext::OpImageSparseRead, &EmitContext::OpImageRead, ctx, inst, | ||
| 572 | result_type, image, coords, std::nullopt, std::span<const Id>{})}; | ||
| 573 | if (!is_integer) { | ||
| 574 | color = ctx.OpBitcast(ctx.U32[4], color); | ||
| 575 | } | ||
| 576 | return color; | ||
| 571 | } | 577 | } |
| 572 | 578 | ||
| 573 | void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color) { | 579 | void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color) { |
| 574 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | 580 | const auto info{inst->Flags<IR::TextureInstInfo>()}; |
| 575 | ctx.OpImageWrite(Image(ctx, index, info), coords, color); | 581 | const auto [image, is_integer] = Image(ctx, index, info); |
| 582 | if (!is_integer) { | ||
| 583 | color = ctx.OpBitcast(ctx.F32[4], color); | ||
| 584 | } | ||
| 585 | ctx.OpImageWrite(image, coords, color); | ||
| 576 | } | 586 | } |
| 577 | 587 | ||
| 578 | Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index) { | 588 | Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index) { |
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index eb3cc23cc..0442adc83 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp | |||
| @@ -74,20 +74,19 @@ spv::ImageFormat GetImageFormat(ImageFormat format) { | |||
| 74 | throw InvalidArgument("Invalid image format {}", format); | 74 | throw InvalidArgument("Invalid image format {}", format); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | Id ImageType(EmitContext& ctx, const ImageDescriptor& desc) { | 77 | Id ImageType(EmitContext& ctx, const ImageDescriptor& desc, Id sampled_type) { |
| 78 | const spv::ImageFormat format{GetImageFormat(desc.format)}; | 78 | const spv::ImageFormat format{GetImageFormat(desc.format)}; |
| 79 | const Id type{ctx.U32[1]}; | ||
| 80 | switch (desc.type) { | 79 | switch (desc.type) { |
| 81 | case TextureType::Color1D: | 80 | case TextureType::Color1D: |
| 82 | return ctx.TypeImage(type, spv::Dim::Dim1D, false, false, false, 2, format); | 81 | return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, false, false, 2, format); |
| 83 | case TextureType::ColorArray1D: | 82 | case TextureType::ColorArray1D: |
| 84 | return ctx.TypeImage(type, spv::Dim::Dim1D, false, true, false, 2, format); | 83 | return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, true, false, 2, format); |
| 85 | case TextureType::Color2D: | 84 | case TextureType::Color2D: |
| 86 | return ctx.TypeImage(type, spv::Dim::Dim2D, false, false, false, 2, format); | 85 | return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, false, false, 2, format); |
| 87 | case TextureType::ColorArray2D: | 86 | case TextureType::ColorArray2D: |
| 88 | return ctx.TypeImage(type, spv::Dim::Dim2D, false, true, false, 2, format); | 87 | return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, true, false, 2, format); |
| 89 | case TextureType::Color3D: | 88 | case TextureType::Color3D: |
| 90 | return ctx.TypeImage(type, spv::Dim::Dim3D, false, false, false, 2, format); | 89 | return ctx.TypeImage(sampled_type, spv::Dim::Dim3D, false, false, false, 2, format); |
| 91 | case TextureType::Buffer: | 90 | case TextureType::Buffer: |
| 92 | throw NotImplementedException("Image buffer"); | 91 | throw NotImplementedException("Image buffer"); |
| 93 | default: | 92 | default: |
| @@ -97,9 +96,9 @@ Id ImageType(EmitContext& ctx, const ImageDescriptor& desc) { | |||
| 97 | } | 96 | } |
| 98 | 97 | ||
| 99 | Id DefineVariable(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin, | 98 | Id DefineVariable(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin, |
| 100 | spv::StorageClass storage_class) { | 99 | spv::StorageClass storage_class, std::optional<Id> initializer = std::nullopt) { |
| 101 | const Id pointer_type{ctx.TypePointer(storage_class, type)}; | 100 | const Id pointer_type{ctx.TypePointer(storage_class, type)}; |
| 102 | const Id id{ctx.AddGlobalVariable(pointer_type, storage_class)}; | 101 | const Id id{ctx.AddGlobalVariable(pointer_type, storage_class, initializer)}; |
| 103 | if (builtin) { | 102 | if (builtin) { |
| 104 | ctx.Decorate(id, spv::Decoration::BuiltIn, *builtin); | 103 | ctx.Decorate(id, spv::Decoration::BuiltIn, *builtin); |
| 105 | } | 104 | } |
| @@ -145,11 +144,12 @@ Id DefineInput(EmitContext& ctx, Id type, bool per_invocation, | |||
| 145 | } | 144 | } |
| 146 | 145 | ||
| 147 | Id DefineOutput(EmitContext& ctx, Id type, std::optional<u32> invocations, | 146 | Id DefineOutput(EmitContext& ctx, Id type, std::optional<u32> invocations, |
| 148 | std::optional<spv::BuiltIn> builtin = std::nullopt) { | 147 | std::optional<spv::BuiltIn> builtin = std::nullopt, |
| 148 | std::optional<Id> initializer = std::nullopt) { | ||
| 149 | if (invocations && ctx.stage == Stage::TessellationControl) { | 149 | if (invocations && ctx.stage == Stage::TessellationControl) { |
| 150 | type = ctx.TypeArray(type, ctx.Const(*invocations)); | 150 | type = ctx.TypeArray(type, ctx.Const(*invocations)); |
| 151 | } | 151 | } |
| 152 | return DefineVariable(ctx, type, builtin, spv::StorageClass::Output); | 152 | return DefineVariable(ctx, type, builtin, spv::StorageClass::Output, initializer); |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invocations) { | 155 | void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invocations) { |
| @@ -812,10 +812,14 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) { | |||
| 812 | labels.push_back(OpLabel()); | 812 | labels.push_back(OpLabel()); |
| 813 | } | 813 | } |
| 814 | if (info.stores.ClipDistances()) { | 814 | if (info.stores.ClipDistances()) { |
| 815 | literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance0) >> 2); | 815 | if (profile.max_user_clip_distances >= 4) { |
| 816 | labels.push_back(OpLabel()); | 816 | literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance0) >> 2); |
| 817 | literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance4) >> 2); | 817 | labels.push_back(OpLabel()); |
| 818 | labels.push_back(OpLabel()); | 818 | } |
| 819 | if (profile.max_user_clip_distances >= 8) { | ||
| 820 | literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance4) >> 2); | ||
| 821 | labels.push_back(OpLabel()); | ||
| 822 | } | ||
| 819 | } | 823 | } |
| 820 | OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone); | 824 | OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone); |
| 821 | OpSwitch(compare_index, default_label, literals, labels); | 825 | OpSwitch(compare_index, default_label, literals, labels); |
| @@ -844,17 +848,21 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) { | |||
| 844 | ++label_index; | 848 | ++label_index; |
| 845 | } | 849 | } |
| 846 | if (info.stores.ClipDistances()) { | 850 | if (info.stores.ClipDistances()) { |
| 847 | AddLabel(labels[label_index]); | 851 | if (profile.max_user_clip_distances >= 4) { |
| 848 | const Id pointer{OpAccessChain(output_f32, clip_distances, masked_index)}; | 852 | AddLabel(labels[label_index]); |
| 849 | OpStore(pointer, store_value); | 853 | const Id pointer{OpAccessChain(output_f32, clip_distances, masked_index)}; |
| 850 | OpReturn(); | 854 | OpStore(pointer, store_value); |
| 851 | ++label_index; | 855 | OpReturn(); |
| 852 | AddLabel(labels[label_index]); | 856 | ++label_index; |
| 853 | const Id fixed_index{OpIAdd(U32[1], masked_index, Const(4U))}; | 857 | } |
| 854 | const Id pointer2{OpAccessChain(output_f32, clip_distances, fixed_index)}; | 858 | if (profile.max_user_clip_distances >= 8) { |
| 855 | OpStore(pointer2, store_value); | 859 | AddLabel(labels[label_index]); |
| 856 | OpReturn(); | 860 | const Id fixed_index{OpIAdd(U32[1], masked_index, Const(4U))}; |
| 857 | ++label_index; | 861 | const Id pointer{OpAccessChain(output_f32, clip_distances, fixed_index)}; |
| 862 | OpStore(pointer, store_value); | ||
| 863 | OpReturn(); | ||
| 864 | ++label_index; | ||
| 865 | } | ||
| 858 | } | 866 | } |
| 859 | AddLabel(end_block); | 867 | AddLabel(end_block); |
| 860 | OpUnreachable(); | 868 | OpUnreachable(); |
| @@ -1273,7 +1281,9 @@ void EmitContext::DefineImageBuffers(const Info& info, u32& binding) { | |||
| 1273 | throw NotImplementedException("Array of image buffers"); | 1281 | throw NotImplementedException("Array of image buffers"); |
| 1274 | } | 1282 | } |
| 1275 | const spv::ImageFormat format{GetImageFormat(desc.format)}; | 1283 | const spv::ImageFormat format{GetImageFormat(desc.format)}; |
| 1276 | const Id image_type{TypeImage(U32[1], spv::Dim::Buffer, false, false, false, 2, format)}; | 1284 | const Id sampled_type{desc.is_integer ? U32[1] : F32[1]}; |
| 1285 | const Id image_type{ | ||
| 1286 | TypeImage(sampled_type, spv::Dim::Buffer, false, false, false, 2, format)}; | ||
| 1277 | const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)}; | 1287 | const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)}; |
| 1278 | const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; | 1288 | const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; |
| 1279 | Decorate(id, spv::Decoration::Binding, binding); | 1289 | Decorate(id, spv::Decoration::Binding, binding); |
| @@ -1283,6 +1293,7 @@ void EmitContext::DefineImageBuffers(const Info& info, u32& binding) { | |||
| 1283 | .id = id, | 1293 | .id = id, |
| 1284 | .image_type = image_type, | 1294 | .image_type = image_type, |
| 1285 | .count = desc.count, | 1295 | .count = desc.count, |
| 1296 | .is_integer = desc.is_integer, | ||
| 1286 | }); | 1297 | }); |
| 1287 | if (profile.supported_spirv >= 0x00010400) { | 1298 | if (profile.supported_spirv >= 0x00010400) { |
| 1288 | interfaces.push_back(id); | 1299 | interfaces.push_back(id); |
| @@ -1327,7 +1338,8 @@ void EmitContext::DefineImages(const Info& info, u32& binding, u32& scaling_inde | |||
| 1327 | if (desc.count != 1) { | 1338 | if (desc.count != 1) { |
| 1328 | throw NotImplementedException("Array of images"); | 1339 | throw NotImplementedException("Array of images"); |
| 1329 | } | 1340 | } |
| 1330 | const Id image_type{ImageType(*this, desc)}; | 1341 | const Id sampled_type{desc.is_integer ? U32[1] : F32[1]}; |
| 1342 | const Id image_type{ImageType(*this, desc, sampled_type)}; | ||
| 1331 | const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)}; | 1343 | const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)}; |
| 1332 | const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; | 1344 | const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; |
| 1333 | Decorate(id, spv::Decoration::Binding, binding); | 1345 | Decorate(id, spv::Decoration::Binding, binding); |
| @@ -1337,6 +1349,7 @@ void EmitContext::DefineImages(const Info& info, u32& binding, u32& scaling_inde | |||
| 1337 | .id = id, | 1349 | .id = id, |
| 1338 | .image_type = image_type, | 1350 | .image_type = image_type, |
| 1339 | .count = desc.count, | 1351 | .count = desc.count, |
| 1352 | .is_integer = desc.is_integer, | ||
| 1340 | }); | 1353 | }); |
| 1341 | if (profile.supported_spirv >= 0x00010400) { | 1354 | if (profile.supported_spirv >= 0x00010400) { |
| 1342 | interfaces.push_back(id); | 1355 | interfaces.push_back(id); |
| @@ -1528,8 +1541,16 @@ void EmitContext::DefineOutputs(const IR::Program& program) { | |||
| 1528 | if (stage == Stage::Fragment) { | 1541 | if (stage == Stage::Fragment) { |
| 1529 | throw NotImplementedException("Storing ClipDistance in fragment stage"); | 1542 | throw NotImplementedException("Storing ClipDistance in fragment stage"); |
| 1530 | } | 1543 | } |
| 1531 | const Id type{TypeArray(F32[1], Const(8U))}; | 1544 | if (profile.max_user_clip_distances > 0) { |
| 1532 | clip_distances = DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance); | 1545 | const u32 used{std::min(profile.max_user_clip_distances, 8u)}; |
| 1546 | const std::array<Id, 8> zero{f32_zero_value, f32_zero_value, f32_zero_value, | ||
| 1547 | f32_zero_value, f32_zero_value, f32_zero_value, | ||
| 1548 | f32_zero_value, f32_zero_value}; | ||
| 1549 | const Id type{TypeArray(F32[1], Const(used))}; | ||
| 1550 | const Id initializer{ConstantComposite(type, std::span(zero).subspan(0, used))}; | ||
| 1551 | clip_distances = | ||
| 1552 | DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance, initializer); | ||
| 1553 | } | ||
| 1533 | } | 1554 | } |
| 1534 | if (info.stores[IR::Attribute::Layer] && | 1555 | if (info.stores[IR::Attribute::Layer] && |
| 1535 | (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) { | 1556 | (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) { |
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index 1aa79863d..56019ad89 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h | |||
| @@ -47,12 +47,14 @@ struct ImageBufferDefinition { | |||
| 47 | Id id; | 47 | Id id; |
| 48 | Id image_type; | 48 | Id image_type; |
| 49 | u32 count; | 49 | u32 count; |
| 50 | bool is_integer; | ||
| 50 | }; | 51 | }; |
| 51 | 52 | ||
| 52 | struct ImageDefinition { | 53 | struct ImageDefinition { |
| 53 | Id id; | 54 | Id id; |
| 54 | Id image_type; | 55 | Id image_type; |
| 55 | u32 count; | 56 | u32 count; |
| 57 | bool is_integer; | ||
| 56 | }; | 58 | }; |
| 57 | 59 | ||
| 58 | struct UniformDefinitions { | 60 | struct UniformDefinitions { |
diff --git a/src/shader_recompiler/environment.h b/src/shader_recompiler/environment.h index 15285ab0a..e30bf094a 100644 --- a/src/shader_recompiler/environment.h +++ b/src/shader_recompiler/environment.h | |||
| @@ -24,6 +24,8 @@ public: | |||
| 24 | 24 | ||
| 25 | [[nodiscard]] virtual TexturePixelFormat ReadTexturePixelFormat(u32 raw_handle) = 0; | 25 | [[nodiscard]] virtual TexturePixelFormat ReadTexturePixelFormat(u32 raw_handle) = 0; |
| 26 | 26 | ||
| 27 | [[nodiscard]] virtual bool IsTexturePixelFormatInteger(u32 raw_handle) = 0; | ||
| 28 | |||
| 27 | [[nodiscard]] virtual u32 ReadViewportTransformState() = 0; | 29 | [[nodiscard]] virtual u32 ReadViewportTransformState() = 0; |
| 28 | 30 | ||
| 29 | [[nodiscard]] virtual u32 TextureBoundBuffer() const = 0; | 31 | [[nodiscard]] virtual u32 TextureBoundBuffer() const = 0; |
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp index 70292686f..cb82a326c 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | |||
| @@ -913,7 +913,11 @@ void GatherInfoFromHeader(Environment& env, Info& info) { | |||
| 913 | } | 913 | } |
| 914 | for (size_t index = 0; index < 8; ++index) { | 914 | for (size_t index = 0; index < 8; ++index) { |
| 915 | const u16 mask{header.vtg.omap_systemc.clip_distances}; | 915 | const u16 mask{header.vtg.omap_systemc.clip_distances}; |
| 916 | info.stores.Set(IR::Attribute::ClipDistance0 + index, ((mask >> index) & 1) != 0); | 916 | const bool used{((mask >> index) & 1) != 0}; |
| 917 | info.stores.Set(IR::Attribute::ClipDistance0 + index, used); | ||
| 918 | if (used) { | ||
| 919 | info.used_clip_distances = static_cast<u32>(index) + 1; | ||
| 920 | } | ||
| 917 | } | 921 | } |
| 918 | info.stores.Set(IR::Attribute::PrimitiveId, | 922 | info.stores.Set(IR::Attribute::PrimitiveId, |
| 919 | header.vtg.omap_systemb.primitive_array_id != 0); | 923 | header.vtg.omap_systemb.primitive_array_id != 0); |
diff --git a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp index ec12c843a..e4a73a360 100644 --- a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp +++ b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp | |||
| @@ -815,6 +815,15 @@ bool FindGradient3DDerivatives(std::array<IR::Value, 3>& results, IR::Value coor | |||
| 815 | return true; | 815 | return true; |
| 816 | } | 816 | } |
| 817 | 817 | ||
| 818 | void ConvertDerivatives(std::array<IR::Value, 3>& results, IR::IREmitter& ir) { | ||
| 819 | for (size_t i = 0; i < 3; i++) { | ||
| 820 | if (results[i].Type() == IR::Type::U32) { | ||
| 821 | results[i] = results[i].IsImmediate() ? ir.Imm32(Common::BitCast<f32>(results[i].U32())) | ||
| 822 | : ir.BitCast<IR::F32>(IR::U32(results[i])); | ||
| 823 | } | ||
| 824 | } | ||
| 825 | } | ||
| 826 | |||
| 818 | void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) { | 827 | void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) { |
| 819 | IR::TextureInstInfo info = inst.Flags<IR::TextureInstInfo>(); | 828 | IR::TextureInstInfo info = inst.Flags<IR::TextureInstInfo>(); |
| 820 | auto orig_opcode = inst.GetOpcode(); | 829 | auto orig_opcode = inst.GetOpcode(); |
| @@ -831,12 +840,14 @@ void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) { | |||
| 831 | if (!offset.IsImmediate()) { | 840 | if (!offset.IsImmediate()) { |
| 832 | return; | 841 | return; |
| 833 | } | 842 | } |
| 843 | IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; | ||
| 834 | IR::Inst* const inst2 = coords.InstRecursive(); | 844 | IR::Inst* const inst2 = coords.InstRecursive(); |
| 835 | std::array<std::array<IR::Value, 3>, 3> results_matrix; | 845 | std::array<std::array<IR::Value, 3>, 3> results_matrix; |
| 836 | for (size_t i = 0; i < 3; i++) { | 846 | for (size_t i = 0; i < 3; i++) { |
| 837 | if (!FindGradient3DDerivatives(results_matrix[i], inst2->Arg(i).Resolve())) { | 847 | if (!FindGradient3DDerivatives(results_matrix[i], inst2->Arg(i).Resolve())) { |
| 838 | return; | 848 | return; |
| 839 | } | 849 | } |
| 850 | ConvertDerivatives(results_matrix[i], ir); | ||
| 840 | } | 851 | } |
| 841 | IR::F32 lod_clamp{}; | 852 | IR::F32 lod_clamp{}; |
| 842 | if (info.has_lod_clamp != 0) { | 853 | if (info.has_lod_clamp != 0) { |
| @@ -846,7 +857,6 @@ void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) { | |||
| 846 | lod_clamp = IR::F32{bias_lc}; | 857 | lod_clamp = IR::F32{bias_lc}; |
| 847 | } | 858 | } |
| 848 | } | 859 | } |
| 849 | IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; | ||
| 850 | IR::Value new_coords = | 860 | IR::Value new_coords = |
| 851 | ir.CompositeConstruct(results_matrix[0][0], results_matrix[1][0], results_matrix[2][0]); | 861 | ir.CompositeConstruct(results_matrix[0][0], results_matrix[1][0], results_matrix[2][0]); |
| 852 | IR::Value derivatives_1 = ir.CompositeConstruct(results_matrix[0][1], results_matrix[0][2], | 862 | IR::Value derivatives_1 = ir.CompositeConstruct(results_matrix[0][1], results_matrix[0][2], |
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp index d374c976a..100437f0e 100644 --- a/src/shader_recompiler/ir_opt/texture_pass.cpp +++ b/src/shader_recompiler/ir_opt/texture_pass.cpp | |||
| @@ -372,6 +372,10 @@ TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAdd | |||
| 372 | return env.ReadTexturePixelFormat(GetTextureHandle(env, cbuf)); | 372 | return env.ReadTexturePixelFormat(GetTextureHandle(env, cbuf)); |
| 373 | } | 373 | } |
| 374 | 374 | ||
| 375 | bool IsTexturePixelFormatInteger(Environment& env, const ConstBufferAddr& cbuf) { | ||
| 376 | return env.IsTexturePixelFormatInteger(GetTextureHandle(env, cbuf)); | ||
| 377 | } | ||
| 378 | |||
| 375 | class Descriptors { | 379 | class Descriptors { |
| 376 | public: | 380 | public: |
| 377 | explicit Descriptors(TextureBufferDescriptors& texture_buffer_descriptors_, | 381 | explicit Descriptors(TextureBufferDescriptors& texture_buffer_descriptors_, |
| @@ -403,6 +407,7 @@ public: | |||
| 403 | })}; | 407 | })}; |
| 404 | image_buffer_descriptors[index].is_written |= desc.is_written; | 408 | image_buffer_descriptors[index].is_written |= desc.is_written; |
| 405 | image_buffer_descriptors[index].is_read |= desc.is_read; | 409 | image_buffer_descriptors[index].is_read |= desc.is_read; |
| 410 | image_buffer_descriptors[index].is_integer |= desc.is_integer; | ||
| 406 | return index; | 411 | return index; |
| 407 | } | 412 | } |
| 408 | 413 | ||
| @@ -432,6 +437,7 @@ public: | |||
| 432 | })}; | 437 | })}; |
| 433 | image_descriptors[index].is_written |= desc.is_written; | 438 | image_descriptors[index].is_written |= desc.is_written; |
| 434 | image_descriptors[index].is_read |= desc.is_read; | 439 | image_descriptors[index].is_read |= desc.is_read; |
| 440 | image_descriptors[index].is_integer |= desc.is_integer; | ||
| 435 | return index; | 441 | return index; |
| 436 | } | 442 | } |
| 437 | 443 | ||
| @@ -469,6 +475,20 @@ void PatchImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) { | |||
| 469 | ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 1)))))); | 475 | ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 1)))))); |
| 470 | } | 476 | } |
| 471 | 477 | ||
| 478 | bool IsPixelFormatSNorm(TexturePixelFormat pixel_format) { | ||
| 479 | switch (pixel_format) { | ||
| 480 | case TexturePixelFormat::A8B8G8R8_SNORM: | ||
| 481 | case TexturePixelFormat::R8G8_SNORM: | ||
| 482 | case TexturePixelFormat::R8_SNORM: | ||
| 483 | case TexturePixelFormat::R16G16B16A16_SNORM: | ||
| 484 | case TexturePixelFormat::R16G16_SNORM: | ||
| 485 | case TexturePixelFormat::R16_SNORM: | ||
| 486 | return true; | ||
| 487 | default: | ||
| 488 | return false; | ||
| 489 | } | ||
| 490 | } | ||
| 491 | |||
| 472 | void PatchTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_format) { | 492 | void PatchTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_format) { |
| 473 | const auto it{IR::Block::InstructionList::s_iterator_to(inst)}; | 493 | const auto it{IR::Block::InstructionList::s_iterator_to(inst)}; |
| 474 | IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; | 494 | IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; |
| @@ -587,11 +607,13 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo | |||
| 587 | } | 607 | } |
| 588 | const bool is_written{inst->GetOpcode() != IR::Opcode::ImageRead}; | 608 | const bool is_written{inst->GetOpcode() != IR::Opcode::ImageRead}; |
| 589 | const bool is_read{inst->GetOpcode() != IR::Opcode::ImageWrite}; | 609 | const bool is_read{inst->GetOpcode() != IR::Opcode::ImageWrite}; |
| 610 | const bool is_integer{IsTexturePixelFormatInteger(env, cbuf)}; | ||
| 590 | if (flags.type == TextureType::Buffer) { | 611 | if (flags.type == TextureType::Buffer) { |
| 591 | index = descriptors.Add(ImageBufferDescriptor{ | 612 | index = descriptors.Add(ImageBufferDescriptor{ |
| 592 | .format = flags.image_format, | 613 | .format = flags.image_format, |
| 593 | .is_written = is_written, | 614 | .is_written = is_written, |
| 594 | .is_read = is_read, | 615 | .is_read = is_read, |
| 616 | .is_integer = is_integer, | ||
| 595 | .cbuf_index = cbuf.index, | 617 | .cbuf_index = cbuf.index, |
| 596 | .cbuf_offset = cbuf.offset, | 618 | .cbuf_offset = cbuf.offset, |
| 597 | .count = cbuf.count, | 619 | .count = cbuf.count, |
| @@ -603,6 +625,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo | |||
| 603 | .format = flags.image_format, | 625 | .format = flags.image_format, |
| 604 | .is_written = is_written, | 626 | .is_written = is_written, |
| 605 | .is_read = is_read, | 627 | .is_read = is_read, |
| 628 | .is_integer = is_integer, | ||
| 606 | .cbuf_index = cbuf.index, | 629 | .cbuf_index = cbuf.index, |
| 607 | .cbuf_offset = cbuf.offset, | 630 | .cbuf_offset = cbuf.offset, |
| 608 | .count = cbuf.count, | 631 | .count = cbuf.count, |
| @@ -658,7 +681,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo | |||
| 658 | if (!host_info.support_snorm_render_buffer && inst->GetOpcode() == IR::Opcode::ImageFetch && | 681 | if (!host_info.support_snorm_render_buffer && inst->GetOpcode() == IR::Opcode::ImageFetch && |
| 659 | flags.type == TextureType::Buffer) { | 682 | flags.type == TextureType::Buffer) { |
| 660 | const auto pixel_format = ReadTexturePixelFormat(env, cbuf); | 683 | const auto pixel_format = ReadTexturePixelFormat(env, cbuf); |
| 661 | if (pixel_format != TexturePixelFormat::OTHER) { | 684 | if (IsPixelFormatSNorm(pixel_format)) { |
| 662 | PatchTexelFetch(*texture_inst.block, *texture_inst.inst, pixel_format); | 685 | PatchTexelFetch(*texture_inst.block, *texture_inst.inst, pixel_format); |
| 663 | } | 686 | } |
| 664 | } | 687 | } |
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h index 66901a965..7578d41cc 100644 --- a/src/shader_recompiler/profile.h +++ b/src/shader_recompiler/profile.h | |||
| @@ -87,6 +87,8 @@ struct Profile { | |||
| 87 | bool has_broken_robust{}; | 87 | bool has_broken_robust{}; |
| 88 | 88 | ||
| 89 | u64 min_ssbo_alignment{}; | 89 | u64 min_ssbo_alignment{}; |
| 90 | |||
| 91 | u32 max_user_clip_distances{}; | ||
| 90 | }; | 92 | }; |
| 91 | 93 | ||
| 92 | } // namespace Shader | 94 | } // namespace Shader |
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index b4b4afd37..ed13e6820 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h | |||
| @@ -35,14 +35,109 @@ enum class TextureType : u32 { | |||
| 35 | }; | 35 | }; |
| 36 | constexpr u32 NUM_TEXTURE_TYPES = 9; | 36 | constexpr u32 NUM_TEXTURE_TYPES = 9; |
| 37 | 37 | ||
| 38 | enum class TexturePixelFormat : u32 { | 38 | enum class TexturePixelFormat { |
| 39 | A8B8G8R8_UNORM, | ||
| 39 | A8B8G8R8_SNORM, | 40 | A8B8G8R8_SNORM, |
| 41 | A8B8G8R8_SINT, | ||
| 42 | A8B8G8R8_UINT, | ||
| 43 | R5G6B5_UNORM, | ||
| 44 | B5G6R5_UNORM, | ||
| 45 | A1R5G5B5_UNORM, | ||
| 46 | A2B10G10R10_UNORM, | ||
| 47 | A2B10G10R10_UINT, | ||
| 48 | A2R10G10B10_UNORM, | ||
| 49 | A1B5G5R5_UNORM, | ||
| 50 | A5B5G5R1_UNORM, | ||
| 51 | R8_UNORM, | ||
| 40 | R8_SNORM, | 52 | R8_SNORM, |
| 41 | R8G8_SNORM, | 53 | R8_SINT, |
| 54 | R8_UINT, | ||
| 55 | R16G16B16A16_FLOAT, | ||
| 56 | R16G16B16A16_UNORM, | ||
| 42 | R16G16B16A16_SNORM, | 57 | R16G16B16A16_SNORM, |
| 43 | R16G16_SNORM, | 58 | R16G16B16A16_SINT, |
| 59 | R16G16B16A16_UINT, | ||
| 60 | B10G11R11_FLOAT, | ||
| 61 | R32G32B32A32_UINT, | ||
| 62 | BC1_RGBA_UNORM, | ||
| 63 | BC2_UNORM, | ||
| 64 | BC3_UNORM, | ||
| 65 | BC4_UNORM, | ||
| 66 | BC4_SNORM, | ||
| 67 | BC5_UNORM, | ||
| 68 | BC5_SNORM, | ||
| 69 | BC7_UNORM, | ||
| 70 | BC6H_UFLOAT, | ||
| 71 | BC6H_SFLOAT, | ||
| 72 | ASTC_2D_4X4_UNORM, | ||
| 73 | B8G8R8A8_UNORM, | ||
| 74 | R32G32B32A32_FLOAT, | ||
| 75 | R32G32B32A32_SINT, | ||
| 76 | R32G32_FLOAT, | ||
| 77 | R32G32_SINT, | ||
| 78 | R32_FLOAT, | ||
| 79 | R16_FLOAT, | ||
| 80 | R16_UNORM, | ||
| 44 | R16_SNORM, | 81 | R16_SNORM, |
| 45 | OTHER | 82 | R16_UINT, |
| 83 | R16_SINT, | ||
| 84 | R16G16_UNORM, | ||
| 85 | R16G16_FLOAT, | ||
| 86 | R16G16_UINT, | ||
| 87 | R16G16_SINT, | ||
| 88 | R16G16_SNORM, | ||
| 89 | R32G32B32_FLOAT, | ||
| 90 | A8B8G8R8_SRGB, | ||
| 91 | R8G8_UNORM, | ||
| 92 | R8G8_SNORM, | ||
| 93 | R8G8_SINT, | ||
| 94 | R8G8_UINT, | ||
| 95 | R32G32_UINT, | ||
| 96 | R16G16B16X16_FLOAT, | ||
| 97 | R32_UINT, | ||
| 98 | R32_SINT, | ||
| 99 | ASTC_2D_8X8_UNORM, | ||
| 100 | ASTC_2D_8X5_UNORM, | ||
| 101 | ASTC_2D_5X4_UNORM, | ||
| 102 | B8G8R8A8_SRGB, | ||
| 103 | BC1_RGBA_SRGB, | ||
| 104 | BC2_SRGB, | ||
| 105 | BC3_SRGB, | ||
| 106 | BC7_SRGB, | ||
| 107 | A4B4G4R4_UNORM, | ||
| 108 | G4R4_UNORM, | ||
| 109 | ASTC_2D_4X4_SRGB, | ||
| 110 | ASTC_2D_8X8_SRGB, | ||
| 111 | ASTC_2D_8X5_SRGB, | ||
| 112 | ASTC_2D_5X4_SRGB, | ||
| 113 | ASTC_2D_5X5_UNORM, | ||
| 114 | ASTC_2D_5X5_SRGB, | ||
| 115 | ASTC_2D_10X8_UNORM, | ||
| 116 | ASTC_2D_10X8_SRGB, | ||
| 117 | ASTC_2D_6X6_UNORM, | ||
| 118 | ASTC_2D_6X6_SRGB, | ||
| 119 | ASTC_2D_10X6_UNORM, | ||
| 120 | ASTC_2D_10X6_SRGB, | ||
| 121 | ASTC_2D_10X5_UNORM, | ||
| 122 | ASTC_2D_10X5_SRGB, | ||
| 123 | ASTC_2D_10X10_UNORM, | ||
| 124 | ASTC_2D_10X10_SRGB, | ||
| 125 | ASTC_2D_12X10_UNORM, | ||
| 126 | ASTC_2D_12X10_SRGB, | ||
| 127 | ASTC_2D_12X12_UNORM, | ||
| 128 | ASTC_2D_12X12_SRGB, | ||
| 129 | ASTC_2D_8X6_UNORM, | ||
| 130 | ASTC_2D_8X6_SRGB, | ||
| 131 | ASTC_2D_6X5_UNORM, | ||
| 132 | ASTC_2D_6X5_SRGB, | ||
| 133 | E5B9G9R9_FLOAT, | ||
| 134 | D32_FLOAT, | ||
| 135 | D16_UNORM, | ||
| 136 | X8_D24_UNORM, | ||
| 137 | S8_UINT, | ||
| 138 | D24_UNORM_S8_UINT, | ||
| 139 | S8_UINT_D24_UNORM, | ||
| 140 | D32_FLOAT_S8_UINT, | ||
| 46 | }; | 141 | }; |
| 47 | 142 | ||
| 48 | enum class ImageFormat : u32 { | 143 | enum class ImageFormat : u32 { |
| @@ -97,6 +192,7 @@ struct ImageBufferDescriptor { | |||
| 97 | ImageFormat format; | 192 | ImageFormat format; |
| 98 | bool is_written; | 193 | bool is_written; |
| 99 | bool is_read; | 194 | bool is_read; |
| 195 | bool is_integer; | ||
| 100 | u32 cbuf_index; | 196 | u32 cbuf_index; |
| 101 | u32 cbuf_offset; | 197 | u32 cbuf_offset; |
| 102 | u32 count; | 198 | u32 count; |
| @@ -129,6 +225,7 @@ struct ImageDescriptor { | |||
| 129 | ImageFormat format; | 225 | ImageFormat format; |
| 130 | bool is_written; | 226 | bool is_written; |
| 131 | bool is_read; | 227 | bool is_read; |
| 228 | bool is_integer; | ||
| 132 | u32 cbuf_index; | 229 | u32 cbuf_index; |
| 133 | u32 cbuf_offset; | 230 | u32 cbuf_offset; |
| 134 | u32 count; | 231 | u32 count; |
| @@ -227,6 +324,8 @@ struct Info { | |||
| 227 | bool requires_layer_emulation{}; | 324 | bool requires_layer_emulation{}; |
| 228 | IR::Attribute emulated_layer{}; | 325 | IR::Attribute emulated_layer{}; |
| 229 | 326 | ||
| 327 | u32 used_clip_distances{}; | ||
| 328 | |||
| 230 | boost::container::static_vector<ConstantBufferDescriptor, MAX_CBUFS> | 329 | boost::container::static_vector<ConstantBufferDescriptor, MAX_CBUFS> |
| 231 | constant_buffer_descriptors; | 330 | constant_buffer_descriptors; |
| 232 | boost::container::static_vector<StorageBufferDescriptor, MAX_SSBOS> storage_buffers_descriptors; | 331 | boost::container::static_vector<StorageBufferDescriptor, MAX_SSBOS> storage_buffers_descriptors; |
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_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 592c28ba3..95ba4f76c 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -586,14 +586,22 @@ void Maxwell3D::ProcessQueryCondition() { | |||
| 586 | } | 586 | } |
| 587 | 587 | ||
| 588 | void Maxwell3D::ProcessCounterReset() { | 588 | void Maxwell3D::ProcessCounterReset() { |
| 589 | switch (regs.clear_report_value) { | 589 | const auto query_type = [clear_report = regs.clear_report_value]() { |
| 590 | case Regs::ClearReport::ZPassPixelCount: | 590 | switch (clear_report) { |
| 591 | rasterizer->ResetCounter(VideoCommon::QueryType::ZPassPixelCount64); | 591 | case Tegra::Engines::Maxwell3D::Regs::ClearReport::ZPassPixelCount: |
| 592 | break; | 592 | return VideoCommon::QueryType::ZPassPixelCount64; |
| 593 | default: | 593 | case Tegra::Engines::Maxwell3D::Regs::ClearReport::StreamingPrimitivesSucceeded: |
| 594 | LOG_DEBUG(Render_OpenGL, "Unimplemented counter reset={}", regs.clear_report_value); | 594 | return VideoCommon::QueryType::StreamingPrimitivesSucceeded; |
| 595 | break; | 595 | case Tegra::Engines::Maxwell3D::Regs::ClearReport::PrimitivesGenerated: |
| 596 | } | 596 | return VideoCommon::QueryType::PrimitivesGenerated; |
| 597 | case Tegra::Engines::Maxwell3D::Regs::ClearReport::VtgPrimitivesOut: | ||
| 598 | return VideoCommon::QueryType::VtgPrimitivesOut; | ||
| 599 | default: | ||
| 600 | LOG_DEBUG(HW_GPU, "Unimplemented counter reset={}", clear_report); | ||
| 601 | return VideoCommon::QueryType::Payload; | ||
| 602 | } | ||
| 603 | }(); | ||
| 604 | rasterizer->ResetCounter(query_type); | ||
| 597 | } | 605 | } |
| 598 | 606 | ||
| 599 | void Maxwell3D::ProcessSyncPoint() { | 607 | void Maxwell3D::ProcessSyncPoint() { |
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/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp index 046c8085e..46e853e04 100644 --- a/src/video_core/macro/macro_hle.cpp +++ b/src/video_core/macro/macro_hle.cpp | |||
| @@ -327,12 +327,13 @@ public: | |||
| 327 | explicit HLE_DrawIndirectByteCount(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} | 327 | explicit HLE_DrawIndirectByteCount(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} |
| 328 | 328 | ||
| 329 | void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override { | 329 | void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override { |
| 330 | const bool force = maxwell3d.Rasterizer().HasDrawTransformFeedback(); | ||
| 331 | |||
| 330 | auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0xFFFFU); | 332 | auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0xFFFFU); |
| 331 | if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) { | 333 | if (!force && (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology))) { |
| 332 | Fallback(parameters); | 334 | Fallback(parameters); |
| 333 | return; | 335 | return; |
| 334 | } | 336 | } |
| 335 | |||
| 336 | auto& params = maxwell3d.draw_manager->GetIndirectParams(); | 337 | auto& params = maxwell3d.draw_manager->GetIndirectParams(); |
| 337 | params.is_byte_count = true; | 338 | params.is_byte_count = true; |
| 338 | params.is_indexed = false; | 339 | params.is_indexed = false; |
| @@ -503,6 +504,8 @@ public: | |||
| 503 | maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true); | 504 | maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true); |
| 504 | maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(inline_data)), | 505 | maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(inline_data)), |
| 505 | regs.transform_feedback.controls[0].stride, true); | 506 | regs.transform_feedback.controls[0].stride, true); |
| 507 | |||
| 508 | maxwell3d.Rasterizer().RegisterTransformFeedback(regs.upload.dest.Address()); | ||
| 506 | } | 509 | } |
| 507 | }; | 510 | }; |
| 508 | 511 | ||
diff --git a/src/video_core/query_cache.h b/src/video_core/query_cache.h index 9fcaeeac7..a64404ce4 100644 --- a/src/video_core/query_cache.h +++ b/src/video_core/query_cache.h | |||
| @@ -28,8 +28,11 @@ | |||
| 28 | namespace VideoCore { | 28 | namespace VideoCore { |
| 29 | enum class QueryType { | 29 | enum class QueryType { |
| 30 | SamplesPassed, | 30 | SamplesPassed, |
| 31 | PrimitivesGenerated, | ||
| 32 | TfbPrimitivesWritten, | ||
| 33 | Count, | ||
| 31 | }; | 34 | }; |
| 32 | constexpr std::size_t NumQueryTypes = 1; | 35 | constexpr std::size_t NumQueryTypes = static_cast<size_t>(QueryType::Count); |
| 33 | } // namespace VideoCore | 36 | } // namespace VideoCore |
| 34 | 37 | ||
| 35 | namespace VideoCommon { | 38 | namespace VideoCommon { |
| @@ -44,15 +47,6 @@ public: | |||
| 44 | explicit CounterStreamBase(QueryCache& cache_, VideoCore::QueryType type_) | 47 | explicit CounterStreamBase(QueryCache& cache_, VideoCore::QueryType type_) |
| 45 | : cache{cache_}, type{type_} {} | 48 | : cache{cache_}, type{type_} {} |
| 46 | 49 | ||
| 47 | /// Updates the state of the stream, enabling or disabling as needed. | ||
| 48 | void Update(bool enabled) { | ||
| 49 | if (enabled) { | ||
| 50 | Enable(); | ||
| 51 | } else { | ||
| 52 | Disable(); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | /// Resets the stream to zero. It doesn't disable the query after resetting. | 50 | /// Resets the stream to zero. It doesn't disable the query after resetting. |
| 57 | void Reset() { | 51 | void Reset() { |
| 58 | if (current) { | 52 | if (current) { |
| @@ -80,7 +74,6 @@ public: | |||
| 80 | return current != nullptr; | 74 | return current != nullptr; |
| 81 | } | 75 | } |
| 82 | 76 | ||
| 83 | private: | ||
| 84 | /// Enables the stream. | 77 | /// Enables the stream. |
| 85 | void Enable() { | 78 | void Enable() { |
| 86 | if (current) { | 79 | if (current) { |
| @@ -97,6 +90,7 @@ private: | |||
| 97 | last = std::exchange(current, nullptr); | 90 | last = std::exchange(current, nullptr); |
| 98 | } | 91 | } |
| 99 | 92 | ||
| 93 | private: | ||
| 100 | QueryCache& cache; | 94 | QueryCache& cache; |
| 101 | const VideoCore::QueryType type; | 95 | const VideoCore::QueryType type; |
| 102 | 96 | ||
| @@ -112,8 +106,14 @@ public: | |||
| 112 | : rasterizer{rasterizer_}, | 106 | : rasterizer{rasterizer_}, |
| 113 | // Use reinterpret_cast instead of static_cast as workaround for | 107 | // Use reinterpret_cast instead of static_cast as workaround for |
| 114 | // UBSan bug (https://github.com/llvm/llvm-project/issues/59060) | 108 | // UBSan bug (https://github.com/llvm/llvm-project/issues/59060) |
| 115 | cpu_memory{cpu_memory_}, streams{{CounterStream{reinterpret_cast<QueryCache&>(*this), | 109 | cpu_memory{cpu_memory_}, streams{{ |
| 116 | VideoCore::QueryType::SamplesPassed}}} { | 110 | {CounterStream{reinterpret_cast<QueryCache&>(*this), |
| 111 | VideoCore::QueryType::SamplesPassed}}, | ||
| 112 | {CounterStream{reinterpret_cast<QueryCache&>(*this), | ||
| 113 | VideoCore::QueryType::PrimitivesGenerated}}, | ||
| 114 | {CounterStream{reinterpret_cast<QueryCache&>(*this), | ||
| 115 | VideoCore::QueryType::TfbPrimitivesWritten}}, | ||
| 116 | }} { | ||
| 117 | (void)slot_async_jobs.insert(); // Null value | 117 | (void)slot_async_jobs.insert(); // Null value |
| 118 | } | 118 | } |
| 119 | 119 | ||
| @@ -157,12 +157,11 @@ public: | |||
| 157 | AsyncFlushQuery(query, timestamp, lock); | 157 | AsyncFlushQuery(query, timestamp, lock); |
| 158 | } | 158 | } |
| 159 | 159 | ||
| 160 | /// Updates counters from GPU state. Expected to be called once per draw, clear or dispatch. | 160 | /// Enables all available GPU counters |
| 161 | void UpdateCounters() { | 161 | void EnableCounters() { |
| 162 | std::unique_lock lock{mutex}; | 162 | std::unique_lock lock{mutex}; |
| 163 | if (maxwell3d) { | 163 | for (auto& stream : streams) { |
| 164 | const auto& regs = maxwell3d->regs; | 164 | stream.Enable(); |
| 165 | Stream(VideoCore::QueryType::SamplesPassed).Update(regs.zpass_pixel_count_enable); | ||
| 166 | } | 165 | } |
| 167 | } | 166 | } |
| 168 | 167 | ||
| @@ -176,7 +175,7 @@ public: | |||
| 176 | void DisableStreams() { | 175 | void DisableStreams() { |
| 177 | std::unique_lock lock{mutex}; | 176 | std::unique_lock lock{mutex}; |
| 178 | for (auto& stream : streams) { | 177 | for (auto& stream : streams) { |
| 179 | stream.Update(false); | 178 | stream.Disable(); |
| 180 | } | 179 | } |
| 181 | } | 180 | } |
| 182 | 181 | ||
| @@ -353,7 +352,7 @@ private: | |||
| 353 | 352 | ||
| 354 | std::shared_ptr<std::vector<AsyncJobId>> uncommitted_flushes{}; | 353 | std::shared_ptr<std::vector<AsyncJobId>> uncommitted_flushes{}; |
| 355 | std::list<std::shared_ptr<std::vector<AsyncJobId>>> committed_flushes; | 354 | std::list<std::shared_ptr<std::vector<AsyncJobId>>> committed_flushes; |
| 356 | }; | 355 | }; // namespace VideoCommon |
| 357 | 356 | ||
| 358 | template <class QueryCache, class HostCounter> | 357 | template <class QueryCache, class HostCounter> |
| 359 | class HostCounterBase { | 358 | class HostCounterBase { |
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index af1469147..49224ca85 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h | |||
| @@ -173,5 +173,13 @@ public: | |||
| 173 | virtual void BindChannel(Tegra::Control::ChannelState& channel) {} | 173 | virtual void BindChannel(Tegra::Control::ChannelState& channel) {} |
| 174 | 174 | ||
| 175 | virtual void ReleaseChannel(s32 channel_id) {} | 175 | virtual void ReleaseChannel(s32 channel_id) {} |
| 176 | |||
| 177 | /// Register the address as a Transform Feedback Object | ||
| 178 | virtual void RegisterTransformFeedback(GPUVAddr tfb_object_addr) {} | ||
| 179 | |||
| 180 | /// Returns true when the rasterizer has Draw Transform Feedback capabilities | ||
| 181 | virtual bool HasDrawTransformFeedback() { | ||
| 182 | return false; | ||
| 183 | } | ||
| 176 | }; | 184 | }; |
| 177 | } // namespace VideoCore | 185 | } // namespace VideoCore |
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp index b787b6994..517ac14dd 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp | |||
| @@ -376,4 +376,15 @@ void BufferCacheRuntime::BindImageBuffer(Buffer& buffer, u32 offset, u32 size, P | |||
| 376 | *image_handles++ = buffer.View(offset, size, format); | 376 | *image_handles++ = buffer.View(offset, size, format); |
| 377 | } | 377 | } |
| 378 | 378 | ||
| 379 | void BufferCacheRuntime::BindTransformFeedbackObject(GPUVAddr tfb_object_addr) { | ||
| 380 | OGLTransformFeedback& tfb_object = tfb_objects[tfb_object_addr]; | ||
| 381 | tfb_object.Create(); | ||
| 382 | glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfb_object.handle); | ||
| 383 | } | ||
| 384 | |||
| 385 | GLuint BufferCacheRuntime::GetTransformFeedbackObject(GPUVAddr tfb_object_addr) { | ||
| 386 | ASSERT(tfb_objects.contains(tfb_object_addr)); | ||
| 387 | return tfb_objects[tfb_object_addr].handle; | ||
| 388 | } | ||
| 389 | |||
| 379 | } // namespace OpenGL | 390 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h index 1e8708f59..2c18de166 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.h +++ b/src/video_core/renderer_opengl/gl_buffer_cache.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include <array> | 6 | #include <array> |
| 7 | #include <span> | 7 | #include <span> |
| 8 | #include <unordered_map> | ||
| 8 | 9 | ||
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 10 | #include "video_core/buffer_cache/buffer_cache_base.h" | 11 | #include "video_core/buffer_cache/buffer_cache_base.h" |
| @@ -121,6 +122,9 @@ public: | |||
| 121 | void BindImageBuffer(Buffer& buffer, u32 offset, u32 size, | 122 | void BindImageBuffer(Buffer& buffer, u32 offset, u32 size, |
| 122 | VideoCore::Surface::PixelFormat format); | 123 | VideoCore::Surface::PixelFormat format); |
| 123 | 124 | ||
| 125 | void BindTransformFeedbackObject(GPUVAddr tfb_object_addr); | ||
| 126 | GLuint GetTransformFeedbackObject(GPUVAddr tfb_object_addr); | ||
| 127 | |||
| 124 | u64 GetDeviceMemoryUsage() const; | 128 | u64 GetDeviceMemoryUsage() const; |
| 125 | 129 | ||
| 126 | void BindFastUniformBuffer(size_t stage, u32 binding_index, u32 size) { | 130 | void BindFastUniformBuffer(size_t stage, u32 binding_index, u32 size) { |
| @@ -233,6 +237,7 @@ private: | |||
| 233 | u32 index_buffer_offset = 0; | 237 | u32 index_buffer_offset = 0; |
| 234 | 238 | ||
| 235 | u64 device_access_memory; | 239 | u64 device_access_memory; |
| 240 | std::unordered_map<GPUVAddr, OGLTransformFeedback> tfb_objects; | ||
| 236 | }; | 241 | }; |
| 237 | 242 | ||
| 238 | struct BufferCacheParams { | 243 | struct BufferCacheParams { |
diff --git a/src/video_core/renderer_opengl/gl_query_cache.cpp b/src/video_core/renderer_opengl/gl_query_cache.cpp index ec142d48e..fef7360ed 100644 --- a/src/video_core/renderer_opengl/gl_query_cache.cpp +++ b/src/video_core/renderer_opengl/gl_query_cache.cpp | |||
| @@ -18,16 +18,27 @@ namespace OpenGL { | |||
| 18 | 18 | ||
| 19 | namespace { | 19 | namespace { |
| 20 | 20 | ||
| 21 | constexpr std::array<GLenum, VideoCore::NumQueryTypes> QueryTargets = {GL_SAMPLES_PASSED}; | ||
| 22 | |||
| 23 | constexpr GLenum GetTarget(VideoCore::QueryType type) { | 21 | constexpr GLenum GetTarget(VideoCore::QueryType type) { |
| 24 | return QueryTargets[static_cast<std::size_t>(type)]; | 22 | switch (type) { |
| 23 | case VideoCore::QueryType::SamplesPassed: | ||
| 24 | return GL_SAMPLES_PASSED; | ||
| 25 | case VideoCore::QueryType::PrimitivesGenerated: | ||
| 26 | return GL_PRIMITIVES_GENERATED; | ||
| 27 | case VideoCore::QueryType::TfbPrimitivesWritten: | ||
| 28 | return GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN; | ||
| 29 | default: | ||
| 30 | break; | ||
| 31 | } | ||
| 32 | UNIMPLEMENTED_MSG("Query type {}", type); | ||
| 33 | return 0; | ||
| 25 | } | 34 | } |
| 26 | 35 | ||
| 27 | } // Anonymous namespace | 36 | } // Anonymous namespace |
| 28 | 37 | ||
| 29 | QueryCache::QueryCache(RasterizerOpenGL& rasterizer_, Core::Memory::Memory& cpu_memory_) | 38 | QueryCache::QueryCache(RasterizerOpenGL& rasterizer_, Core::Memory::Memory& cpu_memory_) |
| 30 | : QueryCacheLegacy(rasterizer_, cpu_memory_), gl_rasterizer{rasterizer_} {} | 39 | : QueryCacheLegacy(rasterizer_, cpu_memory_), gl_rasterizer{rasterizer_} { |
| 40 | EnableCounters(); | ||
| 41 | } | ||
| 31 | 42 | ||
| 32 | QueryCache::~QueryCache() = default; | 43 | QueryCache::~QueryCache() = default; |
| 33 | 44 | ||
| @@ -103,13 +114,13 @@ u64 CachedQuery::Flush([[maybe_unused]] bool async) { | |||
| 103 | auto& stream = cache->Stream(type); | 114 | auto& stream = cache->Stream(type); |
| 104 | const bool slice_counter = WaitPending() && stream.IsEnabled(); | 115 | const bool slice_counter = WaitPending() && stream.IsEnabled(); |
| 105 | if (slice_counter) { | 116 | if (slice_counter) { |
| 106 | stream.Update(false); | 117 | stream.Disable(); |
| 107 | } | 118 | } |
| 108 | 119 | ||
| 109 | auto result = VideoCommon::CachedQueryBase<HostCounter>::Flush(); | 120 | auto result = VideoCommon::CachedQueryBase<HostCounter>::Flush(); |
| 110 | 121 | ||
| 111 | if (slice_counter) { | 122 | if (slice_counter) { |
| 112 | stream.Update(true); | 123 | stream.Enable(); |
| 113 | } | 124 | } |
| 114 | 125 | ||
| 115 | return result; | 126 | return result; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 4832c03c5..7a5fad735 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -51,6 +51,22 @@ constexpr size_t NUM_SUPPORTED_VERTEX_ATTRIBUTES = 16; | |||
| 51 | void oglEnable(GLenum cap, bool state) { | 51 | void oglEnable(GLenum cap, bool state) { |
| 52 | (state ? glEnable : glDisable)(cap); | 52 | (state ? glEnable : glDisable)(cap); |
| 53 | } | 53 | } |
| 54 | |||
| 55 | std::optional<VideoCore::QueryType> MaxwellToVideoCoreQuery(VideoCommon::QueryType type) { | ||
| 56 | switch (type) { | ||
| 57 | case VideoCommon::QueryType::PrimitivesGenerated: | ||
| 58 | case VideoCommon::QueryType::VtgPrimitivesOut: | ||
| 59 | return VideoCore::QueryType::PrimitivesGenerated; | ||
| 60 | case VideoCommon::QueryType::ZPassPixelCount64: | ||
| 61 | return VideoCore::QueryType::SamplesPassed; | ||
| 62 | case VideoCommon::QueryType::StreamingPrimitivesSucceeded: | ||
| 63 | // case VideoCommon::QueryType::StreamingByteCount: | ||
| 64 | // TODO: StreamingByteCount = StreamingPrimitivesSucceeded * num_verts * vert_stride | ||
| 65 | return VideoCore::QueryType::TfbPrimitivesWritten; | ||
| 66 | default: | ||
| 67 | return std::nullopt; | ||
| 68 | } | ||
| 69 | } | ||
| 54 | } // Anonymous namespace | 70 | } // Anonymous namespace |
| 55 | 71 | ||
| 56 | RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, | 72 | RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, |
| @@ -216,7 +232,6 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) { | |||
| 216 | 232 | ||
| 217 | SCOPE_EXIT({ gpu.TickWork(); }); | 233 | SCOPE_EXIT({ gpu.TickWork(); }); |
| 218 | gpu_memory->FlushCaching(); | 234 | gpu_memory->FlushCaching(); |
| 219 | query_cache.UpdateCounters(); | ||
| 220 | 235 | ||
| 221 | GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()}; | 236 | GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()}; |
| 222 | if (!pipeline) { | 237 | if (!pipeline) { |
| @@ -294,6 +309,13 @@ void RasterizerOpenGL::DrawIndirect() { | |||
| 294 | const auto& params = maxwell3d->draw_manager->GetIndirectParams(); | 309 | const auto& params = maxwell3d->draw_manager->GetIndirectParams(); |
| 295 | buffer_cache.SetDrawIndirect(¶ms); | 310 | buffer_cache.SetDrawIndirect(¶ms); |
| 296 | PrepareDraw(params.is_indexed, [this, ¶ms](GLenum primitive_mode) { | 311 | PrepareDraw(params.is_indexed, [this, ¶ms](GLenum primitive_mode) { |
| 312 | if (params.is_byte_count) { | ||
| 313 | const GPUVAddr tfb_object_base_addr = params.indirect_start_address - 4U; | ||
| 314 | const GLuint tfb_object = | ||
| 315 | buffer_cache_runtime.GetTransformFeedbackObject(tfb_object_base_addr); | ||
| 316 | glDrawTransformFeedback(primitive_mode, tfb_object); | ||
| 317 | return; | ||
| 318 | } | ||
| 297 | const auto [buffer, offset] = buffer_cache.GetDrawIndirectBuffer(); | 319 | const auto [buffer, offset] = buffer_cache.GetDrawIndirectBuffer(); |
| 298 | const GLvoid* const gl_offset = | 320 | const GLvoid* const gl_offset = |
| 299 | reinterpret_cast<const GLvoid*>(static_cast<uintptr_t>(offset)); | 321 | reinterpret_cast<const GLvoid*>(static_cast<uintptr_t>(offset)); |
| @@ -334,7 +356,6 @@ void RasterizerOpenGL::DrawTexture() { | |||
| 334 | MICROPROFILE_SCOPE(OpenGL_Drawing); | 356 | MICROPROFILE_SCOPE(OpenGL_Drawing); |
| 335 | 357 | ||
| 336 | SCOPE_EXIT({ gpu.TickWork(); }); | 358 | SCOPE_EXIT({ gpu.TickWork(); }); |
| 337 | query_cache.UpdateCounters(); | ||
| 338 | 359 | ||
| 339 | texture_cache.SynchronizeGraphicsDescriptors(); | 360 | texture_cache.SynchronizeGraphicsDescriptors(); |
| 340 | texture_cache.UpdateRenderTargets(false); | 361 | texture_cache.UpdateRenderTargets(false); |
| @@ -401,21 +422,28 @@ void RasterizerOpenGL::DispatchCompute() { | |||
| 401 | } | 422 | } |
| 402 | 423 | ||
| 403 | void RasterizerOpenGL::ResetCounter(VideoCommon::QueryType type) { | 424 | void RasterizerOpenGL::ResetCounter(VideoCommon::QueryType type) { |
| 404 | if (type == VideoCommon::QueryType::ZPassPixelCount64) { | 425 | const auto query_cache_type = MaxwellToVideoCoreQuery(type); |
| 405 | query_cache.ResetCounter(VideoCore::QueryType::SamplesPassed); | 426 | if (!query_cache_type.has_value()) { |
| 427 | UNIMPLEMENTED_IF_MSG(type != VideoCommon::QueryType::Payload, "Reset query type: {}", type); | ||
| 428 | return; | ||
| 406 | } | 429 | } |
| 430 | query_cache.ResetCounter(*query_cache_type); | ||
| 407 | } | 431 | } |
| 408 | 432 | ||
| 409 | void RasterizerOpenGL::Query(GPUVAddr gpu_addr, VideoCommon::QueryType type, | 433 | void RasterizerOpenGL::Query(GPUVAddr gpu_addr, VideoCommon::QueryType type, |
| 410 | VideoCommon::QueryPropertiesFlags flags, u32 payload, u32 subreport) { | 434 | VideoCommon::QueryPropertiesFlags flags, u32 payload, u32 subreport) { |
| 411 | if (type == VideoCommon::QueryType::ZPassPixelCount64) { | 435 | const auto query_cache_type = MaxwellToVideoCoreQuery(type); |
| 412 | if (True(flags & VideoCommon::QueryPropertiesFlags::HasTimeout)) { | 436 | if (!query_cache_type.has_value()) { |
| 413 | query_cache.Query(gpu_addr, VideoCore::QueryType::SamplesPassed, {gpu.GetTicks()}); | 437 | return QueryFallback(gpu_addr, type, flags, payload, subreport); |
| 414 | } else { | ||
| 415 | query_cache.Query(gpu_addr, VideoCore::QueryType::SamplesPassed, std::nullopt); | ||
| 416 | } | ||
| 417 | return; | ||
| 418 | } | 438 | } |
| 439 | const bool has_timeout = True(flags & VideoCommon::QueryPropertiesFlags::HasTimeout); | ||
| 440 | const auto timestamp = has_timeout ? std::optional<u64>{gpu.GetTicks()} : std::nullopt; | ||
| 441 | query_cache.Query(gpu_addr, *query_cache_type, timestamp); | ||
| 442 | } | ||
| 443 | |||
| 444 | void RasterizerOpenGL::QueryFallback(GPUVAddr gpu_addr, VideoCommon::QueryType type, | ||
| 445 | VideoCommon::QueryPropertiesFlags flags, u32 payload, | ||
| 446 | u32 subreport) { | ||
| 419 | if (type != VideoCommon::QueryType::Payload) { | 447 | if (type != VideoCommon::QueryType::Payload) { |
| 420 | payload = 1u; | 448 | payload = 1u; |
| 421 | } | 449 | } |
| @@ -1350,6 +1378,10 @@ void RasterizerOpenGL::ReleaseChannel(s32 channel_id) { | |||
| 1350 | query_cache.EraseChannel(channel_id); | 1378 | query_cache.EraseChannel(channel_id); |
| 1351 | } | 1379 | } |
| 1352 | 1380 | ||
| 1381 | void RasterizerOpenGL::RegisterTransformFeedback(GPUVAddr tfb_object_addr) { | ||
| 1382 | buffer_cache_runtime.BindTransformFeedbackObject(tfb_object_addr); | ||
| 1383 | } | ||
| 1384 | |||
| 1353 | AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_, TextureCache& texture_cache_) | 1385 | AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_, TextureCache& texture_cache_) |
| 1354 | : buffer_cache{buffer_cache_}, texture_cache{texture_cache_} {} | 1386 | : buffer_cache{buffer_cache_}, texture_cache{texture_cache_} {} |
| 1355 | 1387 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index ceffe1f1e..ce3460938 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -139,6 +139,12 @@ public: | |||
| 139 | 139 | ||
| 140 | void ReleaseChannel(s32 channel_id) override; | 140 | void ReleaseChannel(s32 channel_id) override; |
| 141 | 141 | ||
| 142 | void RegisterTransformFeedback(GPUVAddr tfb_object_addr) override; | ||
| 143 | |||
| 144 | bool HasDrawTransformFeedback() override { | ||
| 145 | return true; | ||
| 146 | } | ||
| 147 | |||
| 142 | private: | 148 | private: |
| 143 | static constexpr size_t MAX_TEXTURES = 192; | 149 | static constexpr size_t MAX_TEXTURES = 192; |
| 144 | static constexpr size_t MAX_IMAGES = 48; | 150 | static constexpr size_t MAX_IMAGES = 48; |
| @@ -225,6 +231,9 @@ private: | |||
| 225 | /// End a transform feedback | 231 | /// End a transform feedback |
| 226 | void EndTransformFeedback(); | 232 | void EndTransformFeedback(); |
| 227 | 233 | ||
| 234 | void QueryFallback(GPUVAddr gpu_addr, VideoCommon::QueryType type, | ||
| 235 | VideoCommon::QueryPropertiesFlags flags, u32 payload, u32 subreport); | ||
| 236 | |||
| 228 | Tegra::GPU& gpu; | 237 | Tegra::GPU& gpu; |
| 229 | 238 | ||
| 230 | const Device& device; | 239 | const Device& device; |
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp index eae8fd110..1d2c9b70a 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.cpp +++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp | |||
| @@ -207,4 +207,21 @@ void OGLQuery::Release() { | |||
| 207 | handle = 0; | 207 | handle = 0; |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | void OGLTransformFeedback::Create() { | ||
| 211 | if (handle != 0) | ||
| 212 | return; | ||
| 213 | |||
| 214 | MICROPROFILE_SCOPE(OpenGL_ResourceCreation); | ||
| 215 | glCreateTransformFeedbacks(1, &handle); | ||
| 216 | } | ||
| 217 | |||
| 218 | void OGLTransformFeedback::Release() { | ||
| 219 | if (handle == 0) | ||
| 220 | return; | ||
| 221 | |||
| 222 | MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); | ||
| 223 | glDeleteTransformFeedbacks(1, &handle); | ||
| 224 | handle = 0; | ||
| 225 | } | ||
| 226 | |||
| 210 | } // namespace OpenGL | 227 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h index 77362acd2..6ca8227bd 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.h +++ b/src/video_core/renderer_opengl/gl_resource_manager.h | |||
| @@ -323,4 +323,31 @@ public: | |||
| 323 | GLuint handle = 0; | 323 | GLuint handle = 0; |
| 324 | }; | 324 | }; |
| 325 | 325 | ||
| 326 | class OGLTransformFeedback final { | ||
| 327 | public: | ||
| 328 | YUZU_NON_COPYABLE(OGLTransformFeedback); | ||
| 329 | |||
| 330 | OGLTransformFeedback() = default; | ||
| 331 | |||
| 332 | OGLTransformFeedback(OGLTransformFeedback&& o) noexcept : handle(std::exchange(o.handle, 0)) {} | ||
| 333 | |||
| 334 | ~OGLTransformFeedback() { | ||
| 335 | Release(); | ||
| 336 | } | ||
| 337 | |||
| 338 | OGLTransformFeedback& operator=(OGLTransformFeedback&& o) noexcept { | ||
| 339 | Release(); | ||
| 340 | handle = std::exchange(o.handle, 0); | ||
| 341 | return *this; | ||
| 342 | } | ||
| 343 | |||
| 344 | /// Creates a new internal OpenGL resource and stores the handle | ||
| 345 | void Create(); | ||
| 346 | |||
| 347 | /// Deletes the internal OpenGL resource | ||
| 348 | void Release(); | ||
| 349 | |||
| 350 | GLuint handle = 0; | ||
| 351 | }; | ||
| 352 | |||
| 326 | } // namespace OpenGL | 353 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 26f2d0ea7..30df41b7d 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -51,7 +51,7 @@ using VideoCommon::LoadPipelines; | |||
| 51 | using VideoCommon::SerializePipeline; | 51 | using VideoCommon::SerializePipeline; |
| 52 | using Context = ShaderContext::Context; | 52 | using Context = ShaderContext::Context; |
| 53 | 53 | ||
| 54 | constexpr u32 CACHE_VERSION = 9; | 54 | constexpr u32 CACHE_VERSION = 10; |
| 55 | 55 | ||
| 56 | template <typename Container> | 56 | template <typename Container> |
| 57 | auto MakeSpan(Container& container) { | 57 | auto MakeSpan(Container& container) { |
| @@ -233,6 +233,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo | |||
| 233 | .ignore_nan_fp_comparisons = true, | 233 | .ignore_nan_fp_comparisons = true, |
| 234 | .gl_max_compute_smem_size = device.GetMaxComputeSharedMemorySize(), | 234 | .gl_max_compute_smem_size = device.GetMaxComputeSharedMemorySize(), |
| 235 | .min_ssbo_alignment = device.GetShaderStorageBufferAlignment(), | 235 | .min_ssbo_alignment = device.GetShaderStorageBufferAlignment(), |
| 236 | .max_user_clip_distances = 8, | ||
| 236 | }, | 237 | }, |
| 237 | host_info{ | 238 | host_info{ |
| 238 | .support_float64 = true, | 239 | .support_float64 = true, |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 5958f52f7..3c61799fa 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp | |||
| @@ -78,8 +78,15 @@ vk::Buffer CreateBuffer(const Device& device, const MemoryAllocator& memory_allo | |||
| 78 | } | 78 | } |
| 79 | } // Anonymous namespace | 79 | } // Anonymous namespace |
| 80 | 80 | ||
| 81 | Buffer::Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams null_params) | 81 | Buffer::Buffer(BufferCacheRuntime& runtime, VideoCommon::NullBufferParams null_params) |
| 82 | : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(null_params), tracker{4096} {} | 82 | : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(null_params), tracker{4096} { |
| 83 | if (runtime.device.HasNullDescriptor()) { | ||
| 84 | return; | ||
| 85 | } | ||
| 86 | device = &runtime.device; | ||
| 87 | buffer = runtime.CreateNullBuffer(); | ||
| 88 | is_null = true; | ||
| 89 | } | ||
| 83 | 90 | ||
| 84 | Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_, | 91 | Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_, |
| 85 | VAddr cpu_addr_, u64 size_bytes_) | 92 | VAddr cpu_addr_, u64 size_bytes_) |
| @@ -93,8 +100,12 @@ Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rast | |||
| 93 | 100 | ||
| 94 | VkBufferView Buffer::View(u32 offset, u32 size, VideoCore::Surface::PixelFormat format) { | 101 | VkBufferView Buffer::View(u32 offset, u32 size, VideoCore::Surface::PixelFormat format) { |
| 95 | if (!device) { | 102 | if (!device) { |
| 96 | // Null buffer, return a null descriptor | 103 | // Null buffer supported, return a null descriptor |
| 97 | return VK_NULL_HANDLE; | 104 | return VK_NULL_HANDLE; |
| 105 | } else if (is_null) { | ||
| 106 | // Null buffer not supported, adjust offset and size | ||
| 107 | offset = 0; | ||
| 108 | size = 0; | ||
| 98 | } | 109 | } |
| 99 | const auto it{std::ranges::find_if(views, [offset, size, format](const BufferView& view) { | 110 | const auto it{std::ranges::find_if(views, [offset, size, format](const BufferView& view) { |
| 100 | return offset == view.offset && size == view.size && format == view.format; | 111 | return offset == view.offset && size == view.size && format == view.format; |
| @@ -563,22 +574,27 @@ void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bi | |||
| 563 | } | 574 | } |
| 564 | buffer_handles.push_back(handle); | 575 | buffer_handles.push_back(handle); |
| 565 | } | 576 | } |
| 577 | const u32 device_max = device.GetMaxVertexInputBindings(); | ||
| 578 | const u32 min_binding = std::min(bindings.min_index, device_max); | ||
| 579 | const u32 max_binding = std::min(bindings.max_index, device_max); | ||
| 580 | const u32 binding_count = max_binding - min_binding; | ||
| 581 | if (binding_count == 0) { | ||
| 582 | return; | ||
| 583 | } | ||
| 566 | if (device.IsExtExtendedDynamicStateSupported()) { | 584 | if (device.IsExtExtendedDynamicStateSupported()) { |
| 567 | scheduler.Record([this, bindings_ = std::move(bindings), | 585 | scheduler.Record([bindings_ = std::move(bindings), |
| 568 | buffer_handles_ = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) { | 586 | buffer_handles_ = std::move(buffer_handles), |
| 569 | cmdbuf.BindVertexBuffers2EXT(bindings_.min_index, | 587 | binding_count](vk::CommandBuffer cmdbuf) { |
| 570 | std::min(bindings_.max_index - bindings_.min_index, | 588 | cmdbuf.BindVertexBuffers2EXT(bindings_.min_index, binding_count, buffer_handles_.data(), |
| 571 | device.GetMaxVertexInputBindings()), | 589 | bindings_.offsets.data(), bindings_.sizes.data(), |
| 572 | buffer_handles_.data(), bindings_.offsets.data(), | 590 | bindings_.strides.data()); |
| 573 | bindings_.sizes.data(), bindings_.strides.data()); | ||
| 574 | }); | 591 | }); |
| 575 | } else { | 592 | } else { |
| 576 | scheduler.Record([this, bindings_ = std::move(bindings), | 593 | scheduler.Record([bindings_ = std::move(bindings), |
| 577 | buffer_handles_ = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) { | 594 | buffer_handles_ = std::move(buffer_handles), |
| 578 | cmdbuf.BindVertexBuffers(bindings_.min_index, | 595 | binding_count](vk::CommandBuffer cmdbuf) { |
| 579 | std::min(bindings_.max_index - bindings_.min_index, | 596 | cmdbuf.BindVertexBuffers(bindings_.min_index, binding_count, buffer_handles_.data(), |
| 580 | device.GetMaxVertexInputBindings()), | 597 | bindings_.offsets.data()); |
| 581 | buffer_handles_.data(), bindings_.offsets.data()); | ||
| 582 | }); | 598 | }); |
| 583 | } | 599 | } |
| 584 | } | 600 | } |
| @@ -622,9 +638,12 @@ void BufferCacheRuntime::BindTransformFeedbackBuffers(VideoCommon::HostBindings< | |||
| 622 | } | 638 | } |
| 623 | 639 | ||
| 624 | void BufferCacheRuntime::ReserveNullBuffer() { | 640 | void BufferCacheRuntime::ReserveNullBuffer() { |
| 625 | if (null_buffer) { | 641 | if (!null_buffer) { |
| 626 | return; | 642 | null_buffer = CreateNullBuffer(); |
| 627 | } | 643 | } |
| 644 | } | ||
| 645 | |||
| 646 | vk::Buffer BufferCacheRuntime::CreateNullBuffer() { | ||
| 628 | VkBufferCreateInfo create_info{ | 647 | VkBufferCreateInfo create_info{ |
| 629 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 648 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 630 | .pNext = nullptr, | 649 | .pNext = nullptr, |
| @@ -639,15 +658,17 @@ void BufferCacheRuntime::ReserveNullBuffer() { | |||
| 639 | if (device.IsExtTransformFeedbackSupported()) { | 658 | if (device.IsExtTransformFeedbackSupported()) { |
| 640 | create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; | 659 | create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; |
| 641 | } | 660 | } |
| 642 | null_buffer = memory_allocator.CreateBuffer(create_info, MemoryUsage::DeviceLocal); | 661 | vk::Buffer ret = memory_allocator.CreateBuffer(create_info, MemoryUsage::DeviceLocal); |
| 643 | if (device.HasDebuggingToolAttached()) { | 662 | if (device.HasDebuggingToolAttached()) { |
| 644 | null_buffer.SetObjectNameEXT("Null buffer"); | 663 | ret.SetObjectNameEXT("Null buffer"); |
| 645 | } | 664 | } |
| 646 | 665 | ||
| 647 | scheduler.RequestOutsideRenderPassOperationContext(); | 666 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 648 | scheduler.Record([buffer = *null_buffer](vk::CommandBuffer cmdbuf) { | 667 | scheduler.Record([buffer = *ret](vk::CommandBuffer cmdbuf) { |
| 649 | cmdbuf.FillBuffer(buffer, 0, VK_WHOLE_SIZE, 0); | 668 | cmdbuf.FillBuffer(buffer, 0, VK_WHOLE_SIZE, 0); |
| 650 | }); | 669 | }); |
| 670 | |||
| 671 | return ret; | ||
| 651 | } | 672 | } |
| 652 | 673 | ||
| 653 | } // namespace Vulkan | 674 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index 0b3fbd6d0..dc300d7cb 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h | |||
| @@ -63,6 +63,7 @@ private: | |||
| 63 | vk::Buffer buffer; | 63 | vk::Buffer buffer; |
| 64 | std::vector<BufferView> views; | 64 | std::vector<BufferView> views; |
| 65 | VideoCommon::UsageTracker tracker; | 65 | VideoCommon::UsageTracker tracker; |
| 66 | bool is_null{}; | ||
| 66 | }; | 67 | }; |
| 67 | 68 | ||
| 68 | class QuadArrayIndexBuffer; | 69 | class QuadArrayIndexBuffer; |
| @@ -151,6 +152,7 @@ private: | |||
| 151 | } | 152 | } |
| 152 | 153 | ||
| 153 | void ReserveNullBuffer(); | 154 | void ReserveNullBuffer(); |
| 155 | vk::Buffer CreateNullBuffer(); | ||
| 154 | 156 | ||
| 155 | const Device& device; | 157 | const Device& device; |
| 156 | MemoryAllocator& memory_allocator; | 158 | MemoryAllocator& memory_allocator; |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 2a13b2a72..d1841198d 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -54,7 +54,7 @@ using VideoCommon::FileEnvironment; | |||
| 54 | using VideoCommon::GenericEnvironment; | 54 | using VideoCommon::GenericEnvironment; |
| 55 | using VideoCommon::GraphicsEnvironment; | 55 | using VideoCommon::GraphicsEnvironment; |
| 56 | 56 | ||
| 57 | constexpr u32 CACHE_VERSION = 10; | 57 | constexpr u32 CACHE_VERSION = 11; |
| 58 | constexpr std::array<char, 8> VULKAN_CACHE_MAGIC_NUMBER{'y', 'u', 'z', 'u', 'v', 'k', 'c', 'h'}; | 58 | constexpr std::array<char, 8> VULKAN_CACHE_MAGIC_NUMBER{'y', 'u', 'z', 'u', 'v', 'k', 'c', 'h'}; |
| 59 | 59 | ||
| 60 | template <typename Container> | 60 | template <typename Container> |
| @@ -374,6 +374,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device | |||
| 374 | .has_broken_robust = | 374 | .has_broken_robust = |
| 375 | device.IsNvidia() && device.GetNvidiaArch() <= NvidiaArchitecture::Arch_Pascal, | 375 | device.IsNvidia() && device.GetNvidiaArch() <= NvidiaArchitecture::Arch_Pascal, |
| 376 | .min_ssbo_alignment = device.GetStorageBufferAlignment(), | 376 | .min_ssbo_alignment = device.GetStorageBufferAlignment(), |
| 377 | .max_user_clip_distances = device.GetMaxUserClipDistances(), | ||
| 377 | }; | 378 | }; |
| 378 | 379 | ||
| 379 | host_info = Shader::HostTranslateInfo{ | 380 | host_info = Shader::HostTranslateInfo{ |
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/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index 078777cdd..95954ade7 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp | |||
| @@ -289,12 +289,15 @@ public: | |||
| 289 | } | 289 | } |
| 290 | 290 | ||
| 291 | if (has_multi_queries) { | 291 | if (has_multi_queries) { |
| 292 | size_t intermediary_buffer_index = ObtainBuffer<false>(num_slots_used); | 292 | const size_t min_accumulation_limit = |
| 293 | std::min(first_accumulation_checkpoint, num_slots_used); | ||
| 294 | const size_t max_accumulation_limit = | ||
| 295 | std::max(last_accumulation_checkpoint, num_slots_used); | ||
| 296 | const size_t intermediary_buffer_index = ObtainBuffer<false>(num_slots_used); | ||
| 293 | resolve_buffers.push_back(intermediary_buffer_index); | 297 | resolve_buffers.push_back(intermediary_buffer_index); |
| 294 | queries_prefix_scan_pass->Run(*accumulation_buffer, *buffers[intermediary_buffer_index], | 298 | queries_prefix_scan_pass->Run(*accumulation_buffer, *buffers[intermediary_buffer_index], |
| 295 | *buffers[resolve_buffer_index], num_slots_used, | 299 | *buffers[resolve_buffer_index], num_slots_used, |
| 296 | std::min(first_accumulation_checkpoint, num_slots_used), | 300 | min_accumulation_limit, max_accumulation_limit); |
| 297 | last_accumulation_checkpoint); | ||
| 298 | 301 | ||
| 299 | } else { | 302 | } else { |
| 300 | scheduler.RequestOutsideRenderPassOperationContext(); | 303 | scheduler.RequestOutsideRenderPassOperationContext(); |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 59829c88b..241fc34be 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -485,6 +485,10 @@ void RasterizerVulkan::DispatchCompute() { | |||
| 485 | } | 485 | } |
| 486 | 486 | ||
| 487 | void RasterizerVulkan::ResetCounter(VideoCommon::QueryType type) { | 487 | void RasterizerVulkan::ResetCounter(VideoCommon::QueryType type) { |
| 488 | if (type != VideoCommon::QueryType::ZPassPixelCount64) { | ||
| 489 | LOG_DEBUG(Render_Vulkan, "Unimplemented counter reset={}", type); | ||
| 490 | return; | ||
| 491 | } | ||
| 488 | query_cache.CounterReset(type); | 492 | query_cache.CounterReset(type); |
| 489 | } | 493 | } |
| 490 | 494 | ||
diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp index 4edbe5700..492440ac4 100644 --- a/src/video_core/shader_environment.cpp +++ b/src/video_core/shader_environment.cpp | |||
| @@ -62,23 +62,9 @@ static Shader::TextureType ConvertTextureType(const Tegra::Texture::TICEntry& en | |||
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static Shader::TexturePixelFormat ConvertTexturePixelFormat(const Tegra::Texture::TICEntry& entry) { | 64 | static Shader::TexturePixelFormat ConvertTexturePixelFormat(const Tegra::Texture::TICEntry& entry) { |
| 65 | switch (PixelFormatFromTextureInfo(entry.format, entry.r_type, entry.g_type, entry.b_type, | 65 | return static_cast<Shader::TexturePixelFormat>( |
| 66 | entry.a_type, entry.srgb_conversion)) { | 66 | PixelFormatFromTextureInfo(entry.format, entry.r_type, entry.g_type, entry.b_type, |
| 67 | case VideoCore::Surface::PixelFormat::A8B8G8R8_SNORM: | 67 | entry.a_type, entry.srgb_conversion)); |
| 68 | return Shader::TexturePixelFormat::A8B8G8R8_SNORM; | ||
| 69 | case VideoCore::Surface::PixelFormat::R8_SNORM: | ||
| 70 | return Shader::TexturePixelFormat::R8_SNORM; | ||
| 71 | case VideoCore::Surface::PixelFormat::R8G8_SNORM: | ||
| 72 | return Shader::TexturePixelFormat::R8G8_SNORM; | ||
| 73 | case VideoCore::Surface::PixelFormat::R16G16B16A16_SNORM: | ||
| 74 | return Shader::TexturePixelFormat::R16G16B16A16_SNORM; | ||
| 75 | case VideoCore::Surface::PixelFormat::R16G16_SNORM: | ||
| 76 | return Shader::TexturePixelFormat::R16G16_SNORM; | ||
| 77 | case VideoCore::Surface::PixelFormat::R16_SNORM: | ||
| 78 | return Shader::TexturePixelFormat::R16_SNORM; | ||
| 79 | default: | ||
| 80 | return Shader::TexturePixelFormat::OTHER; | ||
| 81 | } | ||
| 82 | } | 68 | } |
| 83 | 69 | ||
| 84 | static std::string_view StageToPrefix(Shader::Stage stage) { | 70 | static std::string_view StageToPrefix(Shader::Stage stage) { |
| @@ -398,6 +384,11 @@ Shader::TexturePixelFormat GraphicsEnvironment::ReadTexturePixelFormat(u32 handl | |||
| 398 | return result; | 384 | return result; |
| 399 | } | 385 | } |
| 400 | 386 | ||
| 387 | bool GraphicsEnvironment::IsTexturePixelFormatInteger(u32 handle) { | ||
| 388 | return VideoCore::Surface::IsPixelFormatInteger( | ||
| 389 | static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle))); | ||
| 390 | } | ||
| 391 | |||
| 401 | u32 GraphicsEnvironment::ReadViewportTransformState() { | 392 | u32 GraphicsEnvironment::ReadViewportTransformState() { |
| 402 | const auto& regs{maxwell3d->regs}; | 393 | const auto& regs{maxwell3d->regs}; |
| 403 | viewport_transform_state = regs.viewport_scale_offset_enabled; | 394 | viewport_transform_state = regs.viewport_scale_offset_enabled; |
| @@ -448,6 +439,11 @@ Shader::TexturePixelFormat ComputeEnvironment::ReadTexturePixelFormat(u32 handle | |||
| 448 | return result; | 439 | return result; |
| 449 | } | 440 | } |
| 450 | 441 | ||
| 442 | bool ComputeEnvironment::IsTexturePixelFormatInteger(u32 handle) { | ||
| 443 | return VideoCore::Surface::IsPixelFormatInteger( | ||
| 444 | static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle))); | ||
| 445 | } | ||
| 446 | |||
| 451 | u32 ComputeEnvironment::ReadViewportTransformState() { | 447 | u32 ComputeEnvironment::ReadViewportTransformState() { |
| 452 | return viewport_transform_state; | 448 | return viewport_transform_state; |
| 453 | } | 449 | } |
| @@ -551,6 +547,11 @@ Shader::TexturePixelFormat FileEnvironment::ReadTexturePixelFormat(u32 handle) { | |||
| 551 | return it->second; | 547 | return it->second; |
| 552 | } | 548 | } |
| 553 | 549 | ||
| 550 | bool FileEnvironment::IsTexturePixelFormatInteger(u32 handle) { | ||
| 551 | return VideoCore::Surface::IsPixelFormatInteger( | ||
| 552 | static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle))); | ||
| 553 | } | ||
| 554 | |||
| 554 | u32 FileEnvironment::ReadViewportTransformState() { | 555 | u32 FileEnvironment::ReadViewportTransformState() { |
| 555 | return viewport_transform_state; | 556 | return viewport_transform_state; |
| 556 | } | 557 | } |
diff --git a/src/video_core/shader_environment.h b/src/video_core/shader_environment.h index b90f3d44e..6b372e336 100644 --- a/src/video_core/shader_environment.h +++ b/src/video_core/shader_environment.h | |||
| @@ -115,6 +115,8 @@ public: | |||
| 115 | 115 | ||
| 116 | Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; | 116 | Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; |
| 117 | 117 | ||
| 118 | bool IsTexturePixelFormatInteger(u32 handle) override; | ||
| 119 | |||
| 118 | u32 ReadViewportTransformState() override; | 120 | u32 ReadViewportTransformState() override; |
| 119 | 121 | ||
| 120 | std::optional<Shader::ReplaceConstant> GetReplaceConstBuffer(u32 bank, u32 offset) override; | 122 | std::optional<Shader::ReplaceConstant> GetReplaceConstBuffer(u32 bank, u32 offset) override; |
| @@ -139,6 +141,8 @@ public: | |||
| 139 | 141 | ||
| 140 | Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; | 142 | Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; |
| 141 | 143 | ||
| 144 | bool IsTexturePixelFormatInteger(u32 handle) override; | ||
| 145 | |||
| 142 | u32 ReadViewportTransformState() override; | 146 | u32 ReadViewportTransformState() override; |
| 143 | 147 | ||
| 144 | std::optional<Shader::ReplaceConstant> GetReplaceConstBuffer( | 148 | std::optional<Shader::ReplaceConstant> GetReplaceConstBuffer( |
| @@ -171,6 +175,8 @@ public: | |||
| 171 | 175 | ||
| 172 | [[nodiscard]] Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; | 176 | [[nodiscard]] Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; |
| 173 | 177 | ||
| 178 | [[nodiscard]] bool IsTexturePixelFormatInteger(u32 handle) override; | ||
| 179 | |||
| 174 | [[nodiscard]] u32 ReadViewportTransformState() override; | 180 | [[nodiscard]] u32 ReadViewportTransformState() override; |
| 175 | 181 | ||
| 176 | [[nodiscard]] u32 LocalMemorySize() const override; | 182 | [[nodiscard]] u32 LocalMemorySize() const override; |
diff --git a/src/video_core/texture_cache/decode_bc.cpp b/src/video_core/texture_cache/decode_bc.cpp index 3e26474a3..a018c6df4 100644 --- a/src/video_core/texture_cache/decode_bc.cpp +++ b/src/video_core/texture_cache/decode_bc.cpp | |||
| @@ -60,66 +60,72 @@ u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format) { | |||
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | template <auto decompress, PixelFormat pixel_format> | 62 | template <auto decompress, PixelFormat pixel_format> |
| 63 | void DecompressBlocks(std::span<const u8> input, std::span<u8> output, Extent3D extent, | 63 | void DecompressBlocks(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy, |
| 64 | bool is_signed = false) { | 64 | bool is_signed = false) { |
| 65 | const u32 out_bpp = ConvertedBytesPerBlock(pixel_format); | 65 | const u32 out_bpp = ConvertedBytesPerBlock(pixel_format); |
| 66 | const u32 block_width = std::min(extent.width, BLOCK_SIZE); | 66 | const u32 block_size = BlockSize(pixel_format); |
| 67 | const u32 block_height = std::min(extent.height, BLOCK_SIZE); | 67 | const u32 width = copy.image_extent.width; |
| 68 | const u32 pitch = extent.width * out_bpp; | 68 | const u32 height = copy.image_extent.height * copy.image_subresource.num_layers; |
| 69 | const u32 depth = copy.image_extent.depth; | ||
| 70 | const u32 block_width = std::min(width, BLOCK_SIZE); | ||
| 71 | const u32 block_height = std::min(height, BLOCK_SIZE); | ||
| 72 | const u32 pitch = width * out_bpp; | ||
| 69 | size_t input_offset = 0; | 73 | size_t input_offset = 0; |
| 70 | size_t output_offset = 0; | 74 | size_t output_offset = 0; |
| 71 | for (u32 slice = 0; slice < extent.depth; ++slice) { | 75 | for (u32 slice = 0; slice < depth; ++slice) { |
| 72 | for (u32 y = 0; y < extent.height; y += block_height) { | 76 | for (u32 y = 0; y < height; y += block_height) { |
| 73 | size_t row_offset = 0; | 77 | size_t src_offset = input_offset; |
| 74 | for (u32 x = 0; x < extent.width; | 78 | size_t dst_offset = output_offset; |
| 75 | x += block_width, row_offset += block_width * out_bpp) { | 79 | for (u32 x = 0; x < width; x += block_width) { |
| 76 | const u8* src = input.data() + input_offset; | 80 | const u8* src = input.data() + src_offset; |
| 77 | u8* const dst = output.data() + output_offset + row_offset; | 81 | u8* const dst = output.data() + dst_offset; |
| 78 | if constexpr (IsSigned(pixel_format)) { | 82 | if constexpr (IsSigned(pixel_format)) { |
| 79 | decompress(src, dst, x, y, extent.width, extent.height, is_signed); | 83 | decompress(src, dst, x, y, width, height, is_signed); |
| 80 | } else { | 84 | } else { |
| 81 | decompress(src, dst, x, y, extent.width, extent.height); | 85 | decompress(src, dst, x, y, width, height); |
| 82 | } | 86 | } |
| 83 | input_offset += BlockSize(pixel_format); | 87 | src_offset += block_size; |
| 88 | dst_offset += block_width * out_bpp; | ||
| 84 | } | 89 | } |
| 90 | input_offset += copy.buffer_row_length * block_size / block_width; | ||
| 85 | output_offset += block_height * pitch; | 91 | output_offset += block_height * pitch; |
| 86 | } | 92 | } |
| 87 | } | 93 | } |
| 88 | } | 94 | } |
| 89 | 95 | ||
| 90 | void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent, | 96 | void DecompressBCn(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy, |
| 91 | VideoCore::Surface::PixelFormat pixel_format) { | 97 | VideoCore::Surface::PixelFormat pixel_format) { |
| 92 | switch (pixel_format) { | 98 | switch (pixel_format) { |
| 93 | case PixelFormat::BC1_RGBA_UNORM: | 99 | case PixelFormat::BC1_RGBA_UNORM: |
| 94 | case PixelFormat::BC1_RGBA_SRGB: | 100 | case PixelFormat::BC1_RGBA_SRGB: |
| 95 | DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, extent); | 101 | DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, copy); |
| 96 | break; | 102 | break; |
| 97 | case PixelFormat::BC2_UNORM: | 103 | case PixelFormat::BC2_UNORM: |
| 98 | case PixelFormat::BC2_SRGB: | 104 | case PixelFormat::BC2_SRGB: |
| 99 | DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, extent); | 105 | DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, copy); |
| 100 | break; | 106 | break; |
| 101 | case PixelFormat::BC3_UNORM: | 107 | case PixelFormat::BC3_UNORM: |
| 102 | case PixelFormat::BC3_SRGB: | 108 | case PixelFormat::BC3_SRGB: |
| 103 | DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, extent); | 109 | DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, copy); |
| 104 | break; | 110 | break; |
| 105 | case PixelFormat::BC4_SNORM: | 111 | case PixelFormat::BC4_SNORM: |
| 106 | case PixelFormat::BC4_UNORM: | 112 | case PixelFormat::BC4_UNORM: |
| 107 | DecompressBlocks<bcn::DecodeBc4, PixelFormat::BC4_UNORM>( | 113 | DecompressBlocks<bcn::DecodeBc4, PixelFormat::BC4_UNORM>( |
| 108 | input, output, extent, pixel_format == PixelFormat::BC4_SNORM); | 114 | input, output, copy, pixel_format == PixelFormat::BC4_SNORM); |
| 109 | break; | 115 | break; |
| 110 | case PixelFormat::BC5_SNORM: | 116 | case PixelFormat::BC5_SNORM: |
| 111 | case PixelFormat::BC5_UNORM: | 117 | case PixelFormat::BC5_UNORM: |
| 112 | DecompressBlocks<bcn::DecodeBc5, PixelFormat::BC5_UNORM>( | 118 | DecompressBlocks<bcn::DecodeBc5, PixelFormat::BC5_UNORM>( |
| 113 | input, output, extent, pixel_format == PixelFormat::BC5_SNORM); | 119 | input, output, copy, pixel_format == PixelFormat::BC5_SNORM); |
| 114 | break; | 120 | break; |
| 115 | case PixelFormat::BC6H_SFLOAT: | 121 | case PixelFormat::BC6H_SFLOAT: |
| 116 | case PixelFormat::BC6H_UFLOAT: | 122 | case PixelFormat::BC6H_UFLOAT: |
| 117 | DecompressBlocks<bcn::DecodeBc6, PixelFormat::BC6H_UFLOAT>( | 123 | DecompressBlocks<bcn::DecodeBc6, PixelFormat::BC6H_UFLOAT>( |
| 118 | input, output, extent, pixel_format == PixelFormat::BC6H_SFLOAT); | 124 | input, output, copy, pixel_format == PixelFormat::BC6H_SFLOAT); |
| 119 | break; | 125 | break; |
| 120 | case PixelFormat::BC7_SRGB: | 126 | case PixelFormat::BC7_SRGB: |
| 121 | case PixelFormat::BC7_UNORM: | 127 | case PixelFormat::BC7_UNORM: |
| 122 | DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, extent); | 128 | DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, copy); |
| 123 | break; | 129 | break; |
| 124 | default: | 130 | default: |
| 125 | LOG_WARNING(HW_GPU, "Unimplemented BCn decompression {}", pixel_format); | 131 | LOG_WARNING(HW_GPU, "Unimplemented BCn decompression {}", pixel_format); |
diff --git a/src/video_core/texture_cache/decode_bc.h b/src/video_core/texture_cache/decode_bc.h index 41d1ec0a3..4e3b9b8ac 100644 --- a/src/video_core/texture_cache/decode_bc.h +++ b/src/video_core/texture_cache/decode_bc.h | |||
| @@ -13,7 +13,7 @@ namespace VideoCommon { | |||
| 13 | 13 | ||
| 14 | [[nodiscard]] u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format); | 14 | [[nodiscard]] u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format); |
| 15 | 15 | ||
| 16 | void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent, | 16 | void DecompressBCn(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy, |
| 17 | VideoCore::Surface::PixelFormat pixel_format); | 17 | VideoCore::Surface::PixelFormat pixel_format); |
| 18 | 18 | ||
| 19 | } // namespace VideoCommon | 19 | } // namespace VideoCommon |
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index 15596c925..fcf70068e 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp | |||
| @@ -837,6 +837,7 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory | |||
| 837 | std::span<u8> output) { | 837 | std::span<u8> output) { |
| 838 | const size_t guest_size_bytes = input.size_bytes(); | 838 | const size_t guest_size_bytes = input.size_bytes(); |
| 839 | const u32 bpp_log2 = BytesPerBlockLog2(info.format); | 839 | const u32 bpp_log2 = BytesPerBlockLog2(info.format); |
| 840 | const Extent2D tile_size = DefaultBlockSize(info.format); | ||
| 840 | const Extent3D size = info.size; | 841 | const Extent3D size = info.size; |
| 841 | 842 | ||
| 842 | if (info.type == ImageType::Linear) { | 843 | if (info.type == ImageType::Linear) { |
| @@ -847,7 +848,7 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory | |||
| 847 | return {{ | 848 | return {{ |
| 848 | .buffer_offset = 0, | 849 | .buffer_offset = 0, |
| 849 | .buffer_size = guest_size_bytes, | 850 | .buffer_size = guest_size_bytes, |
| 850 | .buffer_row_length = info.pitch >> bpp_log2, | 851 | .buffer_row_length = info.pitch * tile_size.width >> bpp_log2, |
| 851 | .buffer_image_height = size.height, | 852 | .buffer_image_height = size.height, |
| 852 | .image_subresource = | 853 | .image_subresource = |
| 853 | { | 854 | { |
| @@ -862,7 +863,6 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory | |||
| 862 | const LevelInfo level_info = MakeLevelInfo(info); | 863 | const LevelInfo level_info = MakeLevelInfo(info); |
| 863 | const s32 num_layers = info.resources.layers; | 864 | const s32 num_layers = info.resources.layers; |
| 864 | const s32 num_levels = info.resources.levels; | 865 | const s32 num_levels = info.resources.levels; |
| 865 | const Extent2D tile_size = DefaultBlockSize(info.format); | ||
| 866 | const std::array level_sizes = CalculateLevelSizes(level_info, num_levels); | 866 | const std::array level_sizes = CalculateLevelSizes(level_info, num_levels); |
| 867 | const Extent2D gob = GobSize(bpp_log2, info.block.height, info.tile_width_spacing); | 867 | const Extent2D gob = GobSize(bpp_log2, info.block.height, info.tile_width_spacing); |
| 868 | const u32 layer_size = CalculateLevelBytes(level_sizes, num_levels); | 868 | const u32 layer_size = CalculateLevelBytes(level_sizes, num_levels); |
| @@ -926,8 +926,6 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8 | |||
| 926 | 926 | ||
| 927 | const auto input_offset = input.subspan(copy.buffer_offset); | 927 | const auto input_offset = input.subspan(copy.buffer_offset); |
| 928 | copy.buffer_offset = output_offset; | 928 | copy.buffer_offset = output_offset; |
| 929 | copy.buffer_row_length = mip_size.width; | ||
| 930 | copy.buffer_image_height = mip_size.height; | ||
| 931 | 929 | ||
| 932 | const auto recompression_setting = Settings::values.astc_recompression.GetValue(); | 930 | const auto recompression_setting = Settings::values.astc_recompression.GetValue(); |
| 933 | const bool astc = IsPixelFormatASTC(info.format); | 931 | const bool astc = IsPixelFormatASTC(info.format); |
| @@ -972,16 +970,14 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8 | |||
| 972 | bpp_div; | 970 | bpp_div; |
| 973 | output_offset += static_cast<u32>(copy.buffer_size); | 971 | output_offset += static_cast<u32>(copy.buffer_size); |
| 974 | } else { | 972 | } else { |
| 975 | const Extent3D image_extent{ | 973 | DecompressBCn(input_offset, output.subspan(output_offset), copy, info.format); |
| 976 | .width = copy.image_extent.width, | ||
| 977 | .height = copy.image_extent.height * copy.image_subresource.num_layers, | ||
| 978 | .depth = copy.image_extent.depth, | ||
| 979 | }; | ||
| 980 | DecompressBCn(input_offset, output.subspan(output_offset), image_extent, info.format); | ||
| 981 | output_offset += copy.image_extent.width * copy.image_extent.height * | 974 | output_offset += copy.image_extent.width * copy.image_extent.height * |
| 982 | copy.image_subresource.num_layers * | 975 | copy.image_subresource.num_layers * |
| 983 | ConvertedBytesPerBlock(info.format); | 976 | ConvertedBytesPerBlock(info.format); |
| 984 | } | 977 | } |
| 978 | |||
| 979 | copy.buffer_row_length = mip_size.width; | ||
| 980 | copy.buffer_image_height = mip_size.height; | ||
| 985 | } | 981 | } |
| 986 | } | 982 | } |
| 987 | 983 | ||
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 1fda0042d..727bbd98d 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp | |||
| @@ -695,6 +695,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 695 | std::min(properties.properties.limits.maxVertexInputBindings, 16U); | 695 | std::min(properties.properties.limits.maxVertexInputBindings, 16U); |
| 696 | } | 696 | } |
| 697 | 697 | ||
| 698 | if (is_turnip) { | ||
| 699 | LOG_WARNING(Render_Vulkan, "Turnip requires higher-than-reported binding limits"); | ||
| 700 | properties.properties.limits.maxVertexInputBindings = 32; | ||
| 701 | } | ||
| 702 | |||
| 698 | if (!extensions.extended_dynamic_state && extensions.extended_dynamic_state2) { | 703 | if (!extensions.extended_dynamic_state && extensions.extended_dynamic_state2) { |
| 699 | LOG_INFO(Render_Vulkan, | 704 | LOG_INFO(Render_Vulkan, |
| 700 | "Removing extendedDynamicState2 due to missing extendedDynamicState"); | 705 | "Removing extendedDynamicState2 due to missing extendedDynamicState"); |
| @@ -750,10 +755,10 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags | |||
| 750 | // The wanted format is not supported by hardware, search for alternatives | 755 | // The wanted format is not supported by hardware, search for alternatives |
| 751 | const VkFormat* alternatives = GetFormatAlternatives(wanted_format); | 756 | const VkFormat* alternatives = GetFormatAlternatives(wanted_format); |
| 752 | if (alternatives == nullptr) { | 757 | if (alternatives == nullptr) { |
| 753 | ASSERT_MSG(false, | 758 | LOG_ERROR(Render_Vulkan, |
| 754 | "Format={} with usage={} and type={} has no defined alternatives and host " | 759 | "Format={} with usage={} and type={} has no defined alternatives and host " |
| 755 | "hardware does not support it", | 760 | "hardware does not support it", |
| 756 | wanted_format, wanted_usage, format_type); | 761 | wanted_format, wanted_usage, format_type); |
| 757 | return wanted_format; | 762 | return wanted_format; |
| 758 | } | 763 | } |
| 759 | 764 | ||
| @@ -769,10 +774,10 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags | |||
| 769 | } | 774 | } |
| 770 | 775 | ||
| 771 | // No alternatives found, panic | 776 | // No alternatives found, panic |
| 772 | ASSERT_MSG(false, | 777 | LOG_ERROR(Render_Vulkan, |
| 773 | "Format={} with usage={} and type={} is not supported by the host hardware and " | 778 | "Format={} with usage={} and type={} is not supported by the host hardware and " |
| 774 | "doesn't support any of the alternatives", | 779 | "doesn't support any of the alternatives", |
| 775 | wanted_format, wanted_usage, format_type); | 780 | wanted_format, wanted_usage, format_type); |
| 776 | return wanted_format; | 781 | return wanted_format; |
| 777 | } | 782 | } |
| 778 | 783 | ||
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 4f3846345..701817086 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h | |||
| @@ -665,6 +665,10 @@ public: | |||
| 665 | return properties.properties.limits.maxViewports; | 665 | return properties.properties.limits.maxViewports; |
| 666 | } | 666 | } |
| 667 | 667 | ||
| 668 | u32 GetMaxUserClipDistances() const { | ||
| 669 | return properties.properties.limits.maxClipDistances; | ||
| 670 | } | ||
| 671 | |||
| 668 | bool SupportsConditionalBarriers() const { | 672 | bool SupportsConditionalBarriers() const { |
| 669 | return supports_conditional_barriers; | 673 | return supports_conditional_barriers; |
| 670 | } | 674 | } |
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 70cf14afa..074aed964 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp | |||
| @@ -246,7 +246,9 @@ void SetObjectName(const DeviceDispatch* dld, VkDevice device, T handle, VkObjec | |||
| 246 | .objectHandle = reinterpret_cast<u64>(handle), | 246 | .objectHandle = reinterpret_cast<u64>(handle), |
| 247 | .pObjectName = name, | 247 | .pObjectName = name, |
| 248 | }; | 248 | }; |
| 249 | Check(dld->vkSetDebugUtilsObjectNameEXT(device, &name_info)); | 249 | if (dld->vkSetDebugUtilsObjectNameEXT) { |
| 250 | Check(dld->vkSetDebugUtilsObjectNameEXT(device, &name_info)); | ||
| 251 | } | ||
| 250 | } | 252 | } |
| 251 | 253 | ||
| 252 | } // Anonymous namespace | 254 | } // Anonymous namespace |
| @@ -377,6 +379,8 @@ const char* ToString(VkResult result) noexcept { | |||
| 377 | return "VK_OPERATION_DEFERRED_KHR"; | 379 | return "VK_OPERATION_DEFERRED_KHR"; |
| 378 | case VkResult::VK_OPERATION_NOT_DEFERRED_KHR: | 380 | case VkResult::VK_OPERATION_NOT_DEFERRED_KHR: |
| 379 | return "VK_OPERATION_NOT_DEFERRED_KHR"; | 381 | return "VK_OPERATION_NOT_DEFERRED_KHR"; |
| 382 | case VkResult::VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR: | ||
| 383 | return "VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR"; | ||
| 380 | case VkResult::VK_PIPELINE_COMPILE_REQUIRED_EXT: | 384 | case VkResult::VK_PIPELINE_COMPILE_REQUIRED_EXT: |
| 381 | return "VK_PIPELINE_COMPILE_REQUIRED_EXT"; | 385 | return "VK_PIPELINE_COMPILE_REQUIRED_EXT"; |
| 382 | case VkResult::VK_RESULT_MAX_ENUM: | 386 | case VkResult::VK_RESULT_MAX_ENUM: |
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index fd6bebf0f..0836bcb7e 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp | |||
| @@ -106,32 +106,30 @@ ConfigureGraphics::ConfigureGraphics( | |||
| 106 | Settings::values.bg_green.GetValue(), | 106 | Settings::values.bg_green.GetValue(), |
| 107 | Settings::values.bg_blue.GetValue())); | 107 | Settings::values.bg_blue.GetValue())); |
| 108 | UpdateAPILayout(); | 108 | UpdateAPILayout(); |
| 109 | PopulateVSyncModeSelection(); //< must happen after UpdateAPILayout | 109 | PopulateVSyncModeSelection(false); //< must happen after UpdateAPILayout |
| 110 | 110 | ||
| 111 | // VSync setting needs to be determined after populating the VSync combobox | 111 | // VSync setting needs to be determined after populating the VSync combobox |
| 112 | if (Settings::IsConfiguringGlobal()) { | 112 | const auto vsync_mode_setting = Settings::values.vsync_mode.GetValue(); |
| 113 | const auto vsync_mode_setting = Settings::values.vsync_mode.GetValue(); | 113 | const auto vsync_mode = VSyncSettingToMode(vsync_mode_setting); |
| 114 | const auto vsync_mode = VSyncSettingToMode(vsync_mode_setting); | 114 | int index{}; |
| 115 | int index{}; | 115 | for (const auto mode : vsync_mode_combobox_enum_map) { |
| 116 | for (const auto mode : vsync_mode_combobox_enum_map) { | 116 | if (mode == vsync_mode) { |
| 117 | if (mode == vsync_mode) { | 117 | break; |
| 118 | break; | ||
| 119 | } | ||
| 120 | index++; | ||
| 121 | } | ||
| 122 | if (static_cast<unsigned long>(index) < vsync_mode_combobox_enum_map.size()) { | ||
| 123 | vsync_mode_combobox->setCurrentIndex(index); | ||
| 124 | } | 118 | } |
| 119 | index++; | ||
| 120 | } | ||
| 121 | if (static_cast<unsigned long>(index) < vsync_mode_combobox_enum_map.size()) { | ||
| 122 | vsync_mode_combobox->setCurrentIndex(index); | ||
| 125 | } | 123 | } |
| 126 | 124 | ||
| 127 | connect(api_combobox, qOverload<int>(&QComboBox::activated), this, [this] { | 125 | connect(api_combobox, qOverload<int>(&QComboBox::activated), this, [this] { |
| 128 | UpdateAPILayout(); | 126 | UpdateAPILayout(); |
| 129 | PopulateVSyncModeSelection(); | 127 | PopulateVSyncModeSelection(false); |
| 130 | }); | 128 | }); |
| 131 | connect(vulkan_device_combobox, qOverload<int>(&QComboBox::activated), this, | 129 | connect(vulkan_device_combobox, qOverload<int>(&QComboBox::activated), this, |
| 132 | [this](int device) { | 130 | [this](int device) { |
| 133 | UpdateDeviceSelection(device); | 131 | UpdateDeviceSelection(device); |
| 134 | PopulateVSyncModeSelection(); | 132 | PopulateVSyncModeSelection(false); |
| 135 | }); | 133 | }); |
| 136 | connect(shader_backend_combobox, qOverload<int>(&QComboBox::activated), this, | 134 | connect(shader_backend_combobox, qOverload<int>(&QComboBox::activated), this, |
| 137 | [this](int backend) { UpdateShaderBackendSelection(backend); }); | 135 | [this](int backend) { UpdateShaderBackendSelection(backend); }); |
| @@ -147,8 +145,9 @@ ConfigureGraphics::ConfigureGraphics( | |||
| 147 | const auto& update_screenshot_info = [this, &builder]() { | 145 | const auto& update_screenshot_info = [this, &builder]() { |
| 148 | const auto& combobox_enumerations = builder.ComboboxTranslations().at( | 146 | const auto& combobox_enumerations = builder.ComboboxTranslations().at( |
| 149 | Settings::EnumMetadata<Settings::AspectRatio>::Index()); | 147 | Settings::EnumMetadata<Settings::AspectRatio>::Index()); |
| 150 | const auto index = aspect_ratio_combobox->currentIndex(); | 148 | const auto ratio_index = aspect_ratio_combobox->currentIndex(); |
| 151 | const auto ratio = static_cast<Settings::AspectRatio>(combobox_enumerations[index].first); | 149 | const auto ratio = |
| 150 | static_cast<Settings::AspectRatio>(combobox_enumerations[ratio_index].first); | ||
| 152 | 151 | ||
| 153 | const auto& combobox_enumerations_resolution = builder.ComboboxTranslations().at( | 152 | const auto& combobox_enumerations_resolution = builder.ComboboxTranslations().at( |
| 154 | Settings::EnumMetadata<Settings::ResolutionSetup>::Index()); | 153 | Settings::EnumMetadata<Settings::ResolutionSetup>::Index()); |
| @@ -174,11 +173,7 @@ ConfigureGraphics::ConfigureGraphics( | |||
| 174 | } | 173 | } |
| 175 | } | 174 | } |
| 176 | 175 | ||
| 177 | void ConfigureGraphics::PopulateVSyncModeSelection() { | 176 | void ConfigureGraphics::PopulateVSyncModeSelection(bool use_setting) { |
| 178 | if (!Settings::IsConfiguringGlobal()) { | ||
| 179 | return; | ||
| 180 | } | ||
| 181 | |||
| 182 | const Settings::RendererBackend backend{GetCurrentGraphicsBackend()}; | 177 | const Settings::RendererBackend backend{GetCurrentGraphicsBackend()}; |
| 183 | if (backend == Settings::RendererBackend::Null) { | 178 | if (backend == Settings::RendererBackend::Null) { |
| 184 | vsync_mode_combobox->setEnabled(false); | 179 | vsync_mode_combobox->setEnabled(false); |
| @@ -189,8 +184,9 @@ void ConfigureGraphics::PopulateVSyncModeSelection() { | |||
| 189 | const int current_index = //< current selected vsync mode from combobox | 184 | const int current_index = //< current selected vsync mode from combobox |
| 190 | vsync_mode_combobox->currentIndex(); | 185 | vsync_mode_combobox->currentIndex(); |
| 191 | const auto current_mode = //< current selected vsync mode as a VkPresentModeKHR | 186 | const auto current_mode = //< current selected vsync mode as a VkPresentModeKHR |
| 192 | current_index == -1 ? VSyncSettingToMode(Settings::values.vsync_mode.GetValue()) | 187 | current_index == -1 || use_setting |
| 193 | : vsync_mode_combobox_enum_map[current_index]; | 188 | ? VSyncSettingToMode(Settings::values.vsync_mode.GetValue()) |
| 189 | : vsync_mode_combobox_enum_map[current_index]; | ||
| 194 | int index{}; | 190 | int index{}; |
| 195 | const int device{vulkan_device_combobox->currentIndex()}; //< current selected Vulkan device | 191 | const int device{vulkan_device_combobox->currentIndex()}; //< current selected Vulkan device |
| 196 | 192 | ||
| @@ -214,6 +210,23 @@ void ConfigureGraphics::PopulateVSyncModeSelection() { | |||
| 214 | } | 210 | } |
| 215 | index++; | 211 | index++; |
| 216 | } | 212 | } |
| 213 | |||
| 214 | if (!Settings::IsConfiguringGlobal()) { | ||
| 215 | vsync_restore_global_button->setVisible(!Settings::values.vsync_mode.UsingGlobal()); | ||
| 216 | |||
| 217 | const Settings::VSyncMode global_vsync_mode = Settings::values.vsync_mode.GetValue(true); | ||
| 218 | vsync_restore_global_button->setEnabled( | ||
| 219 | (backend == Settings::RendererBackend::OpenGL && | ||
| 220 | (global_vsync_mode == Settings::VSyncMode::Immediate || | ||
| 221 | global_vsync_mode == Settings::VSyncMode::Fifo)) || | ||
| 222 | backend == Settings::RendererBackend::Vulkan); | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | void ConfigureGraphics::UpdateVsyncSetting() const { | ||
| 227 | const auto mode = vsync_mode_combobox_enum_map[vsync_mode_combobox->currentIndex()]; | ||
| 228 | const auto vsync_mode = PresentModeToSetting(mode); | ||
| 229 | Settings::values.vsync_mode.SetValue(vsync_mode); | ||
| 217 | } | 230 | } |
| 218 | 231 | ||
| 219 | void ConfigureGraphics::UpdateDeviceSelection(int device) { | 232 | void ConfigureGraphics::UpdateDeviceSelection(int device) { |
| @@ -299,6 +312,33 @@ void ConfigureGraphics::Setup(const ConfigurationShared::Builder& builder) { | |||
| 299 | } else if (setting->Id() == Settings::values.vsync_mode.Id()) { | 312 | } else if (setting->Id() == Settings::values.vsync_mode.Id()) { |
| 300 | // Keep track of vsync_mode's combobox so we can populate it | 313 | // Keep track of vsync_mode's combobox so we can populate it |
| 301 | vsync_mode_combobox = widget->combobox; | 314 | vsync_mode_combobox = widget->combobox; |
| 315 | |||
| 316 | // Since vsync is populated at runtime, we have to manually set up the button for | ||
| 317 | // restoring the global setting. | ||
| 318 | if (!Settings::IsConfiguringGlobal()) { | ||
| 319 | QPushButton* restore_button = | ||
| 320 | ConfigurationShared::Widget::CreateRestoreGlobalButton( | ||
| 321 | Settings::values.vsync_mode.UsingGlobal(), widget); | ||
| 322 | restore_button->setEnabled(true); | ||
| 323 | widget->layout()->addWidget(restore_button); | ||
| 324 | |||
| 325 | QObject::connect(restore_button, &QAbstractButton::clicked, | ||
| 326 | [restore_button, this](bool) { | ||
| 327 | Settings::values.vsync_mode.SetGlobal(true); | ||
| 328 | PopulateVSyncModeSelection(true); | ||
| 329 | |||
| 330 | restore_button->setVisible(false); | ||
| 331 | }); | ||
| 332 | |||
| 333 | std::function<void()> set_non_global = [restore_button, this]() { | ||
| 334 | Settings::values.vsync_mode.SetGlobal(false); | ||
| 335 | UpdateVsyncSetting(); | ||
| 336 | restore_button->setVisible(true); | ||
| 337 | }; | ||
| 338 | QObject::connect(widget->combobox, QOverload<int>::of(&QComboBox::activated), | ||
| 339 | [set_non_global]() { set_non_global(); }); | ||
| 340 | vsync_restore_global_button = restore_button; | ||
| 341 | } | ||
| 302 | hold_graphics.emplace(setting->Id(), widget); | 342 | hold_graphics.emplace(setting->Id(), widget); |
| 303 | } else if (setting->Id() == Settings::values.aspect_ratio.Id()) { | 343 | } else if (setting->Id() == Settings::values.aspect_ratio.Id()) { |
| 304 | // Keep track of the aspect ratio combobox to update other UI tabs that need it | 344 | // Keep track of the aspect ratio combobox to update other UI tabs that need it |
| @@ -400,11 +440,7 @@ void ConfigureGraphics::ApplyConfiguration() { | |||
| 400 | func(powered_on); | 440 | func(powered_on); |
| 401 | } | 441 | } |
| 402 | 442 | ||
| 403 | if (Settings::IsConfiguringGlobal()) { | 443 | UpdateVsyncSetting(); |
| 404 | const auto mode = vsync_mode_combobox_enum_map[vsync_mode_combobox->currentIndex()]; | ||
| 405 | const auto vsync_mode = PresentModeToSetting(mode); | ||
| 406 | Settings::values.vsync_mode.SetValue(vsync_mode); | ||
| 407 | } | ||
| 408 | 444 | ||
| 409 | Settings::values.vulkan_device.SetGlobal(true); | 445 | Settings::values.vulkan_device.SetGlobal(true); |
| 410 | Settings::values.shader_backend.SetGlobal(true); | 446 | Settings::values.shader_backend.SetGlobal(true); |
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index 9c24a56db..5c8286836 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h | |||
| @@ -62,7 +62,8 @@ private: | |||
| 62 | 62 | ||
| 63 | void Setup(const ConfigurationShared::Builder& builder); | 63 | void Setup(const ConfigurationShared::Builder& builder); |
| 64 | 64 | ||
| 65 | void PopulateVSyncModeSelection(); | 65 | void PopulateVSyncModeSelection(bool use_setting); |
| 66 | void UpdateVsyncSetting() const; | ||
| 66 | void UpdateBackgroundColorButton(QColor color); | 67 | void UpdateBackgroundColorButton(QColor color); |
| 67 | void UpdateAPILayout(); | 68 | void UpdateAPILayout(); |
| 68 | void UpdateDeviceSelection(int device); | 69 | void UpdateDeviceSelection(int device); |
| @@ -104,6 +105,7 @@ private: | |||
| 104 | QComboBox* api_combobox; | 105 | QComboBox* api_combobox; |
| 105 | QComboBox* shader_backend_combobox; | 106 | QComboBox* shader_backend_combobox; |
| 106 | QComboBox* vsync_mode_combobox; | 107 | QComboBox* vsync_mode_combobox; |
| 108 | QPushButton* vsync_restore_global_button; | ||
| 107 | QWidget* vulkan_device_widget; | 109 | QWidget* vulkan_device_widget; |
| 108 | QWidget* api_widget; | 110 | QWidget* api_widget; |
| 109 | QWidget* shader_backend_widget; | 111 | QWidget* shader_backend_widget; |
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/main.cpp b/src/yuzu/main.cpp index 059fcf041..c789c1e59 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -5342,6 +5342,10 @@ int main(int argc, char* argv[]) { | |||
| 5342 | if (QString::fromLocal8Bit(qgetenv("DISPLAY")).isEmpty()) { | 5342 | if (QString::fromLocal8Bit(qgetenv("DISPLAY")).isEmpty()) { |
| 5343 | qputenv("DISPLAY", ":0"); | 5343 | qputenv("DISPLAY", ":0"); |
| 5344 | } | 5344 | } |
| 5345 | |||
| 5346 | // Fix the Wayland appId. This needs to match the name of the .desktop file without the .desktop | ||
| 5347 | // suffix. | ||
| 5348 | QGuiApplication::setDesktopFileName(QStringLiteral("org.yuzu_emu.yuzu")); | ||
| 5345 | #endif | 5349 | #endif |
| 5346 | 5350 | ||
| 5347 | SetHighDPIAttributes(); | 5351 | SetHighDPIAttributes(); |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 530e445f9..366e806d5 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -168,14 +168,6 @@ class GMainWindow : public QMainWindow { | |||
| 168 | /// Max number of recently loaded items to keep track of | 168 | /// Max number of recently loaded items to keep track of |
| 169 | static const int max_recent_files_item = 10; | 169 | static const int max_recent_files_item = 10; |
| 170 | 170 | ||
| 171 | // TODO: Make use of this! | ||
| 172 | enum { | ||
| 173 | UI_IDLE, | ||
| 174 | UI_EMU_BOOTING, | ||
| 175 | UI_EMU_RUNNING, | ||
| 176 | UI_EMU_STOPPING, | ||
| 177 | }; | ||
| 178 | |||
| 179 | enum { | 171 | enum { |
| 180 | CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, | 172 | CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, |
| 181 | CREATE_SHORTCUT_MSGBOX_SUCCESS, | 173 | CREATE_SHORTCUT_MSGBOX_SUCCESS, |
diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp index a415a953f..74da97e21 100644 --- a/src/yuzu/multiplayer/direct_connect.cpp +++ b/src/yuzu/multiplayer/direct_connect.cpp | |||
| @@ -94,7 +94,7 @@ void DirectConnectWindow::Connect() { | |||
| 94 | // Store settings | 94 | // Store settings |
| 95 | UISettings::values.multiplayer_nickname = ui->nickname->text().toStdString(); | 95 | UISettings::values.multiplayer_nickname = ui->nickname->text().toStdString(); |
| 96 | UISettings::values.multiplayer_ip = ui->ip->text().toStdString(); | 96 | UISettings::values.multiplayer_ip = ui->ip->text().toStdString(); |
| 97 | if (ui->port->isModified() && !ui->port->text().isEmpty()) { | 97 | if (!ui->port->text().isEmpty()) { |
| 98 | UISettings::values.multiplayer_port = ui->port->text().toInt(); | 98 | UISettings::values.multiplayer_port = ui->port->text().toInt(); |
| 99 | } else { | 99 | } else { |
| 100 | UISettings::values.multiplayer_port = UISettings::values.multiplayer_port.GetDefault(); | 100 | UISettings::values.multiplayer_port = UISettings::values.multiplayer_port.GetDefault(); |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 5153cdb79..1a35d471c 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | |||
| @@ -20,7 +20,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_, Co | |||
| 20 | : input_subsystem{input_subsystem_}, system{system_} { | 20 | : input_subsystem{input_subsystem_}, system{system_} { |
| 21 | input_subsystem->Initialize(); | 21 | input_subsystem->Initialize(); |
| 22 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) { | 22 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) { |
| 23 | LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); | 23 | LOG_CRITICAL(Frontend, "Failed to initialize SDL2: {}, Exiting...", SDL_GetError()); |
| 24 | exit(1); | 24 | exit(1); |
| 25 | } | 25 | } |
| 26 | SDL_SetMainReady(); | 26 | SDL_SetMainReady(); |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp index 9ed47d453..8b916f05c 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp | |||
| @@ -28,7 +28,8 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste | |||
| 28 | SDL_SysWMinfo wm; | 28 | SDL_SysWMinfo wm; |
| 29 | SDL_VERSION(&wm.version); | 29 | SDL_VERSION(&wm.version); |
| 30 | if (SDL_GetWindowWMInfo(render_window, &wm) == SDL_FALSE) { | 30 | if (SDL_GetWindowWMInfo(render_window, &wm) == SDL_FALSE) { |
| 31 | LOG_CRITICAL(Frontend, "Failed to get information from the window manager"); | 31 | LOG_CRITICAL(Frontend, "Failed to get information from the window manager: {}", |
| 32 | SDL_GetError()); | ||
| 32 | std::exit(EXIT_FAILURE); | 33 | std::exit(EXIT_FAILURE); |
| 33 | } | 34 | } |
| 34 | 35 | ||
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) { |