diff options
343 files changed, 11631 insertions, 5613 deletions
diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml index 7890b30ca..b037fc055 100644 --- a/src/android/app/src/main/AndroidManifest.xml +++ b/src/android/app/src/main/AndroidManifest.xml | |||
| @@ -14,6 +14,7 @@ SPDX-License-Identifier: GPL-3.0-or-later | |||
| 14 | <uses-permission android:name="android.permission.INTERNET" /> | 14 | <uses-permission android:name="android.permission.INTERNET" /> |
| 15 | <uses-permission android:name="android.permission.NFC" /> | 15 | <uses-permission android:name="android.permission.NFC" /> |
| 16 | <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> | 16 | <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> |
| 17 | <uses-permission android:name="android.permission.VIBRATE" /> | ||
| 17 | 18 | ||
| 18 | <application | 19 | <application |
| 19 | android:name="org.yuzu.yuzu_emu.YuzuApplication" | 20 | android:name="org.yuzu.yuzu_emu.YuzuApplication" |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt index 6ebb46af7..02a20dacf 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt | |||
| @@ -3,24 +3,21 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu | 4 | package org.yuzu.yuzu_emu |
| 5 | 5 | ||
| 6 | import android.app.Dialog | ||
| 7 | import android.content.DialogInterface | 6 | import android.content.DialogInterface |
| 8 | import android.net.Uri | 7 | import android.net.Uri |
| 9 | import android.os.Bundle | ||
| 10 | import android.text.Html | 8 | import android.text.Html |
| 11 | import android.text.method.LinkMovementMethod | 9 | import android.text.method.LinkMovementMethod |
| 12 | import android.view.Surface | 10 | import android.view.Surface |
| 13 | import android.view.View | 11 | import android.view.View |
| 14 | import android.widget.TextView | 12 | import android.widget.TextView |
| 15 | import androidx.annotation.Keep | 13 | import androidx.annotation.Keep |
| 16 | import androidx.fragment.app.DialogFragment | ||
| 17 | import com.google.android.material.dialog.MaterialAlertDialogBuilder | 14 | import com.google.android.material.dialog.MaterialAlertDialogBuilder |
| 18 | import java.lang.ref.WeakReference | 15 | import java.lang.ref.WeakReference |
| 19 | import org.yuzu.yuzu_emu.activities.EmulationActivity | 16 | import org.yuzu.yuzu_emu.activities.EmulationActivity |
| 17 | import org.yuzu.yuzu_emu.fragments.CoreErrorDialogFragment | ||
| 20 | import org.yuzu.yuzu_emu.utils.DocumentsTree | 18 | import org.yuzu.yuzu_emu.utils.DocumentsTree |
| 21 | import org.yuzu.yuzu_emu.utils.FileUtil | 19 | import org.yuzu.yuzu_emu.utils.FileUtil |
| 22 | import org.yuzu.yuzu_emu.utils.Log | 20 | import org.yuzu.yuzu_emu.utils.Log |
| 23 | import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable | ||
| 24 | import org.yuzu.yuzu_emu.model.InstallResult | 21 | import org.yuzu.yuzu_emu.model.InstallResult |
| 25 | import org.yuzu.yuzu_emu.model.Patch | 22 | import org.yuzu.yuzu_emu.model.Patch |
| 26 | import org.yuzu.yuzu_emu.model.GameVerificationResult | 23 | import org.yuzu.yuzu_emu.model.GameVerificationResult |
| @@ -30,34 +27,6 @@ import org.yuzu.yuzu_emu.model.GameVerificationResult | |||
| 30 | * with the native side of the Yuzu code. | 27 | * with the native side of the Yuzu code. |
| 31 | */ | 28 | */ |
| 32 | object NativeLibrary { | 29 | object NativeLibrary { |
| 33 | /** | ||
| 34 | * Default controller id for each device | ||
| 35 | */ | ||
| 36 | const val Player1Device = 0 | ||
| 37 | const val Player2Device = 1 | ||
| 38 | const val Player3Device = 2 | ||
| 39 | const val Player4Device = 3 | ||
| 40 | const val Player5Device = 4 | ||
| 41 | const val Player6Device = 5 | ||
| 42 | const val Player7Device = 6 | ||
| 43 | const val Player8Device = 7 | ||
| 44 | const val ConsoleDevice = 8 | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Controller type for each device | ||
| 48 | */ | ||
| 49 | const val ProController = 3 | ||
| 50 | const val Handheld = 4 | ||
| 51 | const val JoyconDual = 5 | ||
| 52 | const val JoyconLeft = 6 | ||
| 53 | const val JoyconRight = 7 | ||
| 54 | const val GameCube = 8 | ||
| 55 | const val Pokeball = 9 | ||
| 56 | const val NES = 10 | ||
| 57 | const val SNES = 11 | ||
| 58 | const val N64 = 12 | ||
| 59 | const val SegaGenesis = 13 | ||
| 60 | |||
| 61 | @JvmField | 30 | @JvmField |
| 62 | var sEmulationActivity = WeakReference<EmulationActivity?>(null) | 31 | var sEmulationActivity = WeakReference<EmulationActivity?>(null) |
| 63 | 32 | ||
| @@ -127,112 +96,6 @@ object NativeLibrary { | |||
| 127 | FileUtil.getFilename(Uri.parse(path)) | 96 | FileUtil.getFilename(Uri.parse(path)) |
| 128 | } | 97 | } |
| 129 | 98 | ||
| 130 | /** | ||
| 131 | * Returns true if pro controller isn't available and handheld is | ||
| 132 | */ | ||
| 133 | external fun isHandheldOnly(): Boolean | ||
| 134 | |||
| 135 | /** | ||
| 136 | * Changes controller type for a specific device. | ||
| 137 | * | ||
| 138 | * @param Device The input descriptor of the gamepad. | ||
| 139 | * @param Type The NpadStyleIndex of the gamepad. | ||
| 140 | */ | ||
| 141 | external fun setDeviceType(Device: Int, Type: Int): Boolean | ||
| 142 | |||
| 143 | /** | ||
| 144 | * Handles event when a gamepad is connected. | ||
| 145 | * | ||
| 146 | * @param Device The input descriptor of the gamepad. | ||
| 147 | */ | ||
| 148 | external fun onGamePadConnectEvent(Device: Int): Boolean | ||
| 149 | |||
| 150 | /** | ||
| 151 | * Handles event when a gamepad is disconnected. | ||
| 152 | * | ||
| 153 | * @param Device The input descriptor of the gamepad. | ||
| 154 | */ | ||
| 155 | external fun onGamePadDisconnectEvent(Device: Int): Boolean | ||
| 156 | |||
| 157 | /** | ||
| 158 | * Handles button press events for a gamepad. | ||
| 159 | * | ||
| 160 | * @param Device The input descriptor of the gamepad. | ||
| 161 | * @param Button Key code identifying which button was pressed. | ||
| 162 | * @param Action Mask identifying which action is happening (button pressed down, or button released). | ||
| 163 | * @return If we handled the button press. | ||
| 164 | */ | ||
| 165 | external fun onGamePadButtonEvent(Device: Int, Button: Int, Action: Int): Boolean | ||
| 166 | |||
| 167 | /** | ||
| 168 | * Handles joystick movement events. | ||
| 169 | * | ||
| 170 | * @param Device The device ID of the gamepad. | ||
| 171 | * @param Axis The axis ID | ||
| 172 | * @param x_axis The value of the x-axis represented by the given ID. | ||
| 173 | * @param y_axis The value of the y-axis represented by the given ID. | ||
| 174 | */ | ||
| 175 | external fun onGamePadJoystickEvent( | ||
| 176 | Device: Int, | ||
| 177 | Axis: Int, | ||
| 178 | x_axis: Float, | ||
| 179 | y_axis: Float | ||
| 180 | ): Boolean | ||
| 181 | |||
| 182 | /** | ||
| 183 | * Handles motion events. | ||
| 184 | * | ||
| 185 | * @param delta_timestamp The finger id corresponding to this event | ||
| 186 | * @param gyro_x,gyro_y,gyro_z The value of the accelerometer sensor. | ||
| 187 | * @param accel_x,accel_y,accel_z The value of the y-axis | ||
| 188 | */ | ||
| 189 | external fun onGamePadMotionEvent( | ||
| 190 | Device: Int, | ||
| 191 | delta_timestamp: Long, | ||
| 192 | gyro_x: Float, | ||
| 193 | gyro_y: Float, | ||
| 194 | gyro_z: Float, | ||
| 195 | accel_x: Float, | ||
| 196 | accel_y: Float, | ||
| 197 | accel_z: Float | ||
| 198 | ): Boolean | ||
| 199 | |||
| 200 | /** | ||
| 201 | * Signals and load a nfc tag | ||
| 202 | * | ||
| 203 | * @param data Byte array containing all the data from a nfc tag | ||
| 204 | */ | ||
| 205 | external fun onReadNfcTag(data: ByteArray?): Boolean | ||
| 206 | |||
| 207 | /** | ||
| 208 | * Removes current loaded nfc tag | ||
| 209 | */ | ||
| 210 | external fun onRemoveNfcTag(): Boolean | ||
| 211 | |||
| 212 | /** | ||
| 213 | * Handles touch press events. | ||
| 214 | * | ||
| 215 | * @param finger_id The finger id corresponding to this event | ||
| 216 | * @param x_axis The value of the x-axis. | ||
| 217 | * @param y_axis The value of the y-axis. | ||
| 218 | */ | ||
| 219 | external fun onTouchPressed(finger_id: Int, x_axis: Float, y_axis: Float) | ||
| 220 | |||
| 221 | /** | ||
| 222 | * Handles touch movement. | ||
| 223 | * | ||
| 224 | * @param x_axis The value of the instantaneous x-axis. | ||
| 225 | * @param y_axis The value of the instantaneous y-axis. | ||
| 226 | */ | ||
| 227 | external fun onTouchMoved(finger_id: Int, x_axis: Float, y_axis: Float) | ||
| 228 | |||
| 229 | /** | ||
| 230 | * Handles touch release events. | ||
| 231 | * | ||
| 232 | * @param finger_id The finger id corresponding to this event | ||
| 233 | */ | ||
| 234 | external fun onTouchReleased(finger_id: Int) | ||
| 235 | |||
| 236 | external fun setAppDirectory(directory: String) | 99 | external fun setAppDirectory(directory: String) |
| 237 | 100 | ||
| 238 | /** | 101 | /** |
| @@ -318,46 +181,13 @@ object NativeLibrary { | |||
| 318 | ErrorUnknown | 181 | ErrorUnknown |
| 319 | } | 182 | } |
| 320 | 183 | ||
| 321 | private var coreErrorAlertResult = false | 184 | var coreErrorAlertResult = false |
| 322 | private val coreErrorAlertLock = Object() | 185 | val coreErrorAlertLock = Object() |
| 323 | |||
| 324 | class CoreErrorDialogFragment : DialogFragment() { | ||
| 325 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { | ||
| 326 | val title = requireArguments().serializable<String>("title") | ||
| 327 | val message = requireArguments().serializable<String>("message") | ||
| 328 | |||
| 329 | return MaterialAlertDialogBuilder(requireActivity()) | ||
| 330 | .setTitle(title) | ||
| 331 | .setMessage(message) | ||
| 332 | .setPositiveButton(R.string.continue_button, null) | ||
| 333 | .setNegativeButton(R.string.abort_button) { _: DialogInterface?, _: Int -> | ||
| 334 | coreErrorAlertResult = false | ||
| 335 | synchronized(coreErrorAlertLock) { coreErrorAlertLock.notify() } | ||
| 336 | } | ||
| 337 | .create() | ||
| 338 | } | ||
| 339 | |||
| 340 | override fun onDismiss(dialog: DialogInterface) { | ||
| 341 | coreErrorAlertResult = true | ||
| 342 | synchronized(coreErrorAlertLock) { coreErrorAlertLock.notify() } | ||
| 343 | } | ||
| 344 | |||
| 345 | companion object { | ||
| 346 | fun newInstance(title: String?, message: String?): CoreErrorDialogFragment { | ||
| 347 | val frag = CoreErrorDialogFragment() | ||
| 348 | val args = Bundle() | ||
| 349 | args.putString("title", title) | ||
| 350 | args.putString("message", message) | ||
| 351 | frag.arguments = args | ||
| 352 | return frag | ||
| 353 | } | ||
| 354 | } | ||
| 355 | } | ||
| 356 | 186 | ||
| 357 | private fun onCoreErrorImpl(title: String, message: String) { | 187 | private fun onCoreErrorImpl(title: String, message: String) { |
| 358 | val emulationActivity = sEmulationActivity.get() | 188 | val emulationActivity = sEmulationActivity.get() |
| 359 | if (emulationActivity == null) { | 189 | if (emulationActivity == null) { |
| 360 | error("[NativeLibrary] EmulationActivity not present") | 190 | Log.error("[NativeLibrary] EmulationActivity not present") |
| 361 | return | 191 | return |
| 362 | } | 192 | } |
| 363 | 193 | ||
| @@ -373,7 +203,7 @@ object NativeLibrary { | |||
| 373 | fun onCoreError(error: CoreError?, details: String): Boolean { | 203 | fun onCoreError(error: CoreError?, details: String): Boolean { |
| 374 | val emulationActivity = sEmulationActivity.get() | 204 | val emulationActivity = sEmulationActivity.get() |
| 375 | if (emulationActivity == null) { | 205 | if (emulationActivity == null) { |
| 376 | error("[NativeLibrary] EmulationActivity not present") | 206 | Log.error("[NativeLibrary] EmulationActivity not present") |
| 377 | return false | 207 | return false |
| 378 | } | 208 | } |
| 379 | 209 | ||
| @@ -404,7 +234,7 @@ object NativeLibrary { | |||
| 404 | } | 234 | } |
| 405 | 235 | ||
| 406 | // Show the AlertDialog on the main thread. | 236 | // Show the AlertDialog on the main thread. |
| 407 | emulationActivity.runOnUiThread(Runnable { onCoreErrorImpl(title, message) }) | 237 | emulationActivity.runOnUiThread { onCoreErrorImpl(title, message) } |
| 408 | 238 | ||
| 409 | // Wait for the lock to notify that it is complete. | 239 | // Wait for the lock to notify that it is complete. |
| 410 | synchronized(coreErrorAlertLock) { coreErrorAlertLock.wait() } | 240 | synchronized(coreErrorAlertLock) { coreErrorAlertLock.wait() } |
| @@ -629,46 +459,4 @@ object NativeLibrary { | |||
| 629 | * Checks if all necessary keys are present for decryption | 459 | * Checks if all necessary keys are present for decryption |
| 630 | */ | 460 | */ |
| 631 | external fun areKeysPresent(): Boolean | 461 | external fun areKeysPresent(): Boolean |
| 632 | |||
| 633 | /** | ||
| 634 | * Button type for use in onTouchEvent | ||
| 635 | */ | ||
| 636 | object ButtonType { | ||
| 637 | const val BUTTON_A = 0 | ||
| 638 | const val BUTTON_B = 1 | ||
| 639 | const val BUTTON_X = 2 | ||
| 640 | const val BUTTON_Y = 3 | ||
| 641 | const val STICK_L = 4 | ||
| 642 | const val STICK_R = 5 | ||
| 643 | const val TRIGGER_L = 6 | ||
| 644 | const val TRIGGER_R = 7 | ||
| 645 | const val TRIGGER_ZL = 8 | ||
| 646 | const val TRIGGER_ZR = 9 | ||
| 647 | const val BUTTON_PLUS = 10 | ||
| 648 | const val BUTTON_MINUS = 11 | ||
| 649 | const val DPAD_LEFT = 12 | ||
| 650 | const val DPAD_UP = 13 | ||
| 651 | const val DPAD_RIGHT = 14 | ||
| 652 | const val DPAD_DOWN = 15 | ||
| 653 | const val BUTTON_SL = 16 | ||
| 654 | const val BUTTON_SR = 17 | ||
| 655 | const val BUTTON_HOME = 18 | ||
| 656 | const val BUTTON_CAPTURE = 19 | ||
| 657 | } | ||
| 658 | |||
| 659 | /** | ||
| 660 | * Stick type for use in onTouchEvent | ||
| 661 | */ | ||
| 662 | object StickType { | ||
| 663 | const val STICK_L = 0 | ||
| 664 | const val STICK_R = 1 | ||
| 665 | } | ||
| 666 | |||
| 667 | /** | ||
| 668 | * Button states | ||
| 669 | */ | ||
| 670 | object ButtonState { | ||
| 671 | const val RELEASED = 0 | ||
| 672 | const val PRESSED = 1 | ||
| 673 | } | ||
| 674 | } | 462 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt index 76778c10a..72943f33e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt | |||
| @@ -7,6 +7,7 @@ import android.app.Application | |||
| 7 | import android.app.NotificationChannel | 7 | import android.app.NotificationChannel |
| 8 | import android.app.NotificationManager | 8 | import android.app.NotificationManager |
| 9 | import android.content.Context | 9 | import android.content.Context |
| 10 | import org.yuzu.yuzu_emu.features.input.NativeInput | ||
| 10 | import java.io.File | 11 | import java.io.File |
| 11 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization | 12 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization |
| 12 | import org.yuzu.yuzu_emu.utils.DocumentsTree | 13 | import org.yuzu.yuzu_emu.utils.DocumentsTree |
| @@ -37,6 +38,7 @@ class YuzuApplication : Application() { | |||
| 37 | documentsTree = DocumentsTree() | 38 | documentsTree = DocumentsTree() |
| 38 | DirectoryInitialization.start() | 39 | DirectoryInitialization.start() |
| 39 | GpuDriverHelper.initializeDriverParameters() | 40 | GpuDriverHelper.initializeDriverParameters() |
| 41 | NativeInput.reloadInputDevices() | ||
| 40 | NativeLibrary.logDeviceInfo() | 42 | NativeLibrary.logDeviceInfo() |
| 41 | Log.logDeviceInfo() | 43 | Log.logDeviceInfo() |
| 42 | 44 | ||
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 7a8d03610..c962558a7 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 | |||
| @@ -39,6 +39,7 @@ import org.yuzu.yuzu_emu.NativeLibrary | |||
| 39 | import org.yuzu.yuzu_emu.R | 39 | import org.yuzu.yuzu_emu.R |
| 40 | import org.yuzu.yuzu_emu.YuzuApplication | 40 | import org.yuzu.yuzu_emu.YuzuApplication |
| 41 | import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding | 41 | import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding |
| 42 | import org.yuzu.yuzu_emu.features.input.NativeInput | ||
| 42 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting | 43 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting |
| 43 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting | 44 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting |
| 44 | import org.yuzu.yuzu_emu.features.settings.model.Settings | 45 | import org.yuzu.yuzu_emu.features.settings.model.Settings |
| @@ -47,7 +48,9 @@ import org.yuzu.yuzu_emu.model.Game | |||
| 47 | import org.yuzu.yuzu_emu.utils.InputHandler | 48 | import org.yuzu.yuzu_emu.utils.InputHandler |
| 48 | import org.yuzu.yuzu_emu.utils.Log | 49 | import org.yuzu.yuzu_emu.utils.Log |
| 49 | import org.yuzu.yuzu_emu.utils.MemoryUtil | 50 | import org.yuzu.yuzu_emu.utils.MemoryUtil |
| 51 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 50 | import org.yuzu.yuzu_emu.utils.NfcReader | 52 | import org.yuzu.yuzu_emu.utils.NfcReader |
| 53 | import org.yuzu.yuzu_emu.utils.ParamPackage | ||
| 51 | import org.yuzu.yuzu_emu.utils.ThemeHelper | 54 | import org.yuzu.yuzu_emu.utils.ThemeHelper |
| 52 | import java.text.NumberFormat | 55 | import java.text.NumberFormat |
| 53 | import kotlin.math.roundToInt | 56 | import kotlin.math.roundToInt |
| @@ -63,8 +66,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 63 | private var motionTimestamp: Long = 0 | 66 | private var motionTimestamp: Long = 0 |
| 64 | private var flipMotionOrientation: Boolean = false | 67 | private var flipMotionOrientation: Boolean = false |
| 65 | 68 | ||
| 66 | private var controllerIds = InputHandler.getGameControllerIds() | ||
| 67 | |||
| 68 | private val actionPause = "ACTION_EMULATOR_PAUSE" | 69 | private val actionPause = "ACTION_EMULATOR_PAUSE" |
| 69 | private val actionPlay = "ACTION_EMULATOR_PLAY" | 70 | private val actionPlay = "ACTION_EMULATOR_PLAY" |
| 70 | private val actionMute = "ACTION_EMULATOR_MUTE" | 71 | private val actionMute = "ACTION_EMULATOR_MUTE" |
| @@ -78,6 +79,33 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 78 | 79 | ||
| 79 | super.onCreate(savedInstanceState) | 80 | super.onCreate(savedInstanceState) |
| 80 | 81 | ||
| 82 | InputHandler.updateControllerData() | ||
| 83 | val players = NativeConfig.getInputSettings(true) | ||
| 84 | var hasConfiguredControllers = false | ||
| 85 | players.forEach { | ||
| 86 | if (it.hasMapping()) { | ||
| 87 | hasConfiguredControllers = true | ||
| 88 | } | ||
| 89 | } | ||
| 90 | if (!hasConfiguredControllers && InputHandler.androidControllers.isNotEmpty()) { | ||
| 91 | var params: ParamPackage? = null | ||
| 92 | for (controller in InputHandler.registeredControllers) { | ||
| 93 | if (controller.get("port", -1) == 0) { | ||
| 94 | params = controller | ||
| 95 | break | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | if (params != null) { | ||
| 100 | NativeInput.updateMappingsWithDefault( | ||
| 101 | 0, | ||
| 102 | params, | ||
| 103 | params.get("display", getString(R.string.unknown)) | ||
| 104 | ) | ||
| 105 | NativeConfig.saveGlobalConfig() | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 81 | binding = ActivityEmulationBinding.inflate(layoutInflater) | 109 | binding = ActivityEmulationBinding.inflate(layoutInflater) |
| 82 | setContentView(binding.root) | 110 | setContentView(binding.root) |
| 83 | 111 | ||
| @@ -95,8 +123,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 95 | nfcReader = NfcReader(this) | 123 | nfcReader = NfcReader(this) |
| 96 | nfcReader.initialize() | 124 | nfcReader.initialize() |
| 97 | 125 | ||
| 98 | InputHandler.initialize() | ||
| 99 | |||
| 100 | val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | 126 | val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) |
| 101 | if (!preferences.getBoolean(Settings.PREF_MEMORY_WARNING_SHOWN, false)) { | 127 | if (!preferences.getBoolean(Settings.PREF_MEMORY_WARNING_SHOWN, false)) { |
| 102 | if (MemoryUtil.isLessThan(MemoryUtil.REQUIRED_MEMORY, MemoryUtil.totalMemory)) { | 128 | if (MemoryUtil.isLessThan(MemoryUtil.REQUIRED_MEMORY, MemoryUtil.totalMemory)) { |
| @@ -147,7 +173,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 147 | super.onResume() | 173 | super.onResume() |
| 148 | nfcReader.startScanning() | 174 | nfcReader.startScanning() |
| 149 | startMotionSensorListener() | 175 | startMotionSensorListener() |
| 150 | InputHandler.updateControllerIds() | 176 | InputHandler.updateControllerData() |
| 151 | 177 | ||
| 152 | buildPictureInPictureParams() | 178 | buildPictureInPictureParams() |
| 153 | } | 179 | } |
| @@ -172,6 +198,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 172 | super.onNewIntent(intent) | 198 | super.onNewIntent(intent) |
| 173 | setIntent(intent) | 199 | setIntent(intent) |
| 174 | nfcReader.onNewIntent(intent) | 200 | nfcReader.onNewIntent(intent) |
| 201 | InputHandler.updateControllerData() | ||
| 175 | } | 202 | } |
| 176 | 203 | ||
| 177 | override fun dispatchKeyEvent(event: KeyEvent): Boolean { | 204 | override fun dispatchKeyEvent(event: KeyEvent): Boolean { |
| @@ -244,8 +271,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 244 | } | 271 | } |
| 245 | val deltaTimestamp = (event.timestamp - motionTimestamp) / 1000 | 272 | val deltaTimestamp = (event.timestamp - motionTimestamp) / 1000 |
| 246 | motionTimestamp = event.timestamp | 273 | motionTimestamp = event.timestamp |
| 247 | NativeLibrary.onGamePadMotionEvent( | 274 | NativeInput.onDeviceMotionEvent( |
| 248 | NativeLibrary.Player1Device, | 275 | NativeInput.Player1Device, |
| 249 | deltaTimestamp, | 276 | deltaTimestamp, |
| 250 | gyro[0], | 277 | gyro[0], |
| 251 | gyro[1], | 278 | gyro[1], |
| @@ -254,8 +281,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 254 | accel[1], | 281 | accel[1], |
| 255 | accel[2] | 282 | accel[2] |
| 256 | ) | 283 | ) |
| 257 | NativeLibrary.onGamePadMotionEvent( | 284 | NativeInput.onDeviceMotionEvent( |
| 258 | NativeLibrary.ConsoleDevice, | 285 | NativeInput.ConsoleDevice, |
| 259 | deltaTimestamp, | 286 | deltaTimestamp, |
| 260 | gyro[0], | 287 | gyro[0], |
| 261 | gyro[1], | 288 | gyro[1], |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt index f218c76ef..50663ad91 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt | |||
| @@ -3,15 +3,15 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.adapters | 4 | package org.yuzu.yuzu_emu.adapters |
| 5 | 5 | ||
| 6 | import android.text.TextUtils | ||
| 7 | import android.view.LayoutInflater | 6 | import android.view.LayoutInflater |
| 8 | import android.view.View | ||
| 9 | import android.view.ViewGroup | 7 | import android.view.ViewGroup |
| 10 | import org.yuzu.yuzu_emu.R | 8 | import org.yuzu.yuzu_emu.R |
| 11 | import org.yuzu.yuzu_emu.databinding.CardDriverOptionBinding | 9 | import org.yuzu.yuzu_emu.databinding.CardDriverOptionBinding |
| 12 | import org.yuzu.yuzu_emu.features.settings.model.StringSetting | 10 | import org.yuzu.yuzu_emu.features.settings.model.StringSetting |
| 13 | import org.yuzu.yuzu_emu.model.Driver | 11 | import org.yuzu.yuzu_emu.model.Driver |
| 14 | import org.yuzu.yuzu_emu.model.DriverViewModel | 12 | import org.yuzu.yuzu_emu.model.DriverViewModel |
| 13 | import org.yuzu.yuzu_emu.utils.ViewUtils.marquee | ||
| 14 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 15 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | 15 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder |
| 16 | 16 | ||
| 17 | class DriverAdapter(private val driverViewModel: DriverViewModel) : | 17 | class DriverAdapter(private val driverViewModel: DriverViewModel) : |
| @@ -44,25 +44,15 @@ class DriverAdapter(private val driverViewModel: DriverViewModel) : | |||
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | // Delay marquee by 3s | 46 | // Delay marquee by 3s |
| 47 | title.postDelayed( | 47 | title.marquee() |
| 48 | { | 48 | version.marquee() |
| 49 | title.isSelected = true | 49 | description.marquee() |
| 50 | title.ellipsize = TextUtils.TruncateAt.MARQUEE | ||
| 51 | version.isSelected = true | ||
| 52 | version.ellipsize = TextUtils.TruncateAt.MARQUEE | ||
| 53 | description.isSelected = true | ||
| 54 | description.ellipsize = TextUtils.TruncateAt.MARQUEE | ||
| 55 | }, | ||
| 56 | 3000 | ||
| 57 | ) | ||
| 58 | title.text = model.title | 50 | title.text = model.title |
| 59 | version.text = model.version | 51 | version.text = model.version |
| 60 | description.text = model.description | 52 | description.text = model.description |
| 61 | if (model.title != binding.root.context.getString(R.string.system_gpu_driver)) { | 53 | buttonDelete.setVisible( |
| 62 | buttonDelete.visibility = View.VISIBLE | 54 | model.title != binding.root.context.getString(R.string.system_gpu_driver) |
| 63 | } else { | 55 | ) |
| 64 | buttonDelete.visibility = View.GONE | ||
| 65 | } | ||
| 66 | } | 56 | } |
| 67 | } | 57 | } |
| 68 | } | 58 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt index 3d8f0bda8..5cbd15d2a 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | package org.yuzu.yuzu_emu.adapters | 4 | package org.yuzu.yuzu_emu.adapters |
| 5 | 5 | ||
| 6 | import android.net.Uri | 6 | import android.net.Uri |
| 7 | import android.text.TextUtils | ||
| 8 | import android.view.LayoutInflater | 7 | import android.view.LayoutInflater |
| 9 | import android.view.ViewGroup | 8 | import android.view.ViewGroup |
| 10 | import androidx.fragment.app.FragmentActivity | 9 | import androidx.fragment.app.FragmentActivity |
| @@ -12,6 +11,7 @@ import org.yuzu.yuzu_emu.databinding.CardFolderBinding | |||
| 12 | import org.yuzu.yuzu_emu.fragments.GameFolderPropertiesDialogFragment | 11 | import org.yuzu.yuzu_emu.fragments.GameFolderPropertiesDialogFragment |
| 13 | import org.yuzu.yuzu_emu.model.GameDir | 12 | import org.yuzu.yuzu_emu.model.GameDir |
| 14 | import org.yuzu.yuzu_emu.model.GamesViewModel | 13 | import org.yuzu.yuzu_emu.model.GamesViewModel |
| 14 | import org.yuzu.yuzu_emu.utils.ViewUtils.marquee | ||
| 15 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | 15 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder |
| 16 | 16 | ||
| 17 | class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesViewModel) : | 17 | class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesViewModel) : |
| @@ -29,13 +29,7 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie | |||
| 29 | override fun bind(model: GameDir) { | 29 | override fun bind(model: GameDir) { |
| 30 | binding.apply { | 30 | binding.apply { |
| 31 | path.text = Uri.parse(model.uriString).path | 31 | path.text = Uri.parse(model.uriString).path |
| 32 | path.postDelayed( | 32 | path.marquee() |
| 33 | { | ||
| 34 | path.isSelected = true | ||
| 35 | path.ellipsize = TextUtils.TruncateAt.MARQUEE | ||
| 36 | }, | ||
| 37 | 3000 | ||
| 38 | ) | ||
| 39 | 33 | ||
| 40 | buttonEdit.setOnClickListener { | 34 | buttonEdit.setOnClickListener { |
| 41 | GameFolderPropertiesDialogFragment.newInstance(model) | 35 | GameFolderPropertiesDialogFragment.newInstance(model) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt index 85c8249e6..b1f247ac3 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | package org.yuzu.yuzu_emu.adapters | 4 | package org.yuzu.yuzu_emu.adapters |
| 5 | 5 | ||
| 6 | import android.net.Uri | 6 | import android.net.Uri |
| 7 | import android.text.TextUtils | ||
| 8 | import android.view.LayoutInflater | 7 | import android.view.LayoutInflater |
| 9 | import android.view.ViewGroup | 8 | import android.view.ViewGroup |
| 10 | import android.widget.ImageView | 9 | import android.widget.ImageView |
| @@ -27,6 +26,7 @@ import org.yuzu.yuzu_emu.databinding.CardGameBinding | |||
| 27 | import org.yuzu.yuzu_emu.model.Game | 26 | import org.yuzu.yuzu_emu.model.Game |
| 28 | import org.yuzu.yuzu_emu.model.GamesViewModel | 27 | import org.yuzu.yuzu_emu.model.GamesViewModel |
| 29 | import org.yuzu.yuzu_emu.utils.GameIconUtils | 28 | import org.yuzu.yuzu_emu.utils.GameIconUtils |
| 29 | import org.yuzu.yuzu_emu.utils.ViewUtils.marquee | ||
| 30 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | 30 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder |
| 31 | 31 | ||
| 32 | class GameAdapter(private val activity: AppCompatActivity) : | 32 | class GameAdapter(private val activity: AppCompatActivity) : |
| @@ -44,14 +44,7 @@ class GameAdapter(private val activity: AppCompatActivity) : | |||
| 44 | 44 | ||
| 45 | binding.textGameTitle.text = model.title.replace("[\\t\\n\\r]+".toRegex(), " ") | 45 | binding.textGameTitle.text = model.title.replace("[\\t\\n\\r]+".toRegex(), " ") |
| 46 | 46 | ||
| 47 | binding.textGameTitle.postDelayed( | 47 | binding.textGameTitle.marquee() |
| 48 | { | ||
| 49 | binding.textGameTitle.ellipsize = TextUtils.TruncateAt.MARQUEE | ||
| 50 | binding.textGameTitle.isSelected = true | ||
| 51 | }, | ||
| 52 | 3000 | ||
| 53 | ) | ||
| 54 | |||
| 55 | binding.cardGame.setOnClickListener { onClick(model) } | 48 | binding.cardGame.setOnClickListener { onClick(model) } |
| 56 | binding.cardGame.setOnLongClickListener { onLongClick(model) } | 49 | binding.cardGame.setOnLongClickListener { onLongClick(model) } |
| 57 | } | 50 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt index 0046d5314..7366e2c77 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt | |||
| @@ -3,21 +3,18 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.adapters | 4 | package org.yuzu.yuzu_emu.adapters |
| 5 | 5 | ||
| 6 | import android.text.TextUtils | ||
| 7 | import android.view.LayoutInflater | 6 | import android.view.LayoutInflater |
| 8 | import android.view.View | ||
| 9 | import android.view.ViewGroup | 7 | import android.view.ViewGroup |
| 10 | import androidx.core.content.res.ResourcesCompat | 8 | import androidx.core.content.res.ResourcesCompat |
| 11 | import androidx.lifecycle.Lifecycle | ||
| 12 | import androidx.lifecycle.LifecycleOwner | 9 | import androidx.lifecycle.LifecycleOwner |
| 13 | import androidx.lifecycle.lifecycleScope | ||
| 14 | import androidx.lifecycle.repeatOnLifecycle | ||
| 15 | import kotlinx.coroutines.launch | ||
| 16 | import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding | 10 | import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding |
| 17 | import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding | 11 | import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding |
| 18 | import org.yuzu.yuzu_emu.model.GameProperty | 12 | import org.yuzu.yuzu_emu.model.GameProperty |
| 19 | import org.yuzu.yuzu_emu.model.InstallableProperty | 13 | import org.yuzu.yuzu_emu.model.InstallableProperty |
| 20 | import org.yuzu.yuzu_emu.model.SubmenuProperty | 14 | import org.yuzu.yuzu_emu.model.SubmenuProperty |
| 15 | import org.yuzu.yuzu_emu.utils.ViewUtils.marquee | ||
| 16 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 17 | import org.yuzu.yuzu_emu.utils.collect | ||
| 21 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | 18 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder |
| 22 | 19 | ||
| 23 | class GamePropertiesAdapter( | 20 | class GamePropertiesAdapter( |
| @@ -76,23 +73,15 @@ class GamePropertiesAdapter( | |||
| 76 | ) | 73 | ) |
| 77 | ) | 74 | ) |
| 78 | 75 | ||
| 79 | binding.details.postDelayed({ | 76 | binding.details.marquee() |
| 80 | binding.details.isSelected = true | ||
| 81 | binding.details.ellipsize = TextUtils.TruncateAt.MARQUEE | ||
| 82 | }, 3000) | ||
| 83 | |||
| 84 | if (submenuProperty.details != null) { | 77 | if (submenuProperty.details != null) { |
| 85 | binding.details.visibility = View.VISIBLE | 78 | binding.details.setVisible(true) |
| 86 | binding.details.text = submenuProperty.details.invoke() | 79 | binding.details.text = submenuProperty.details.invoke() |
| 87 | } else if (submenuProperty.detailsFlow != null) { | 80 | } else if (submenuProperty.detailsFlow != null) { |
| 88 | binding.details.visibility = View.VISIBLE | 81 | binding.details.setVisible(true) |
| 89 | viewLifecycle.lifecycleScope.launch { | 82 | submenuProperty.detailsFlow.collect(viewLifecycle) { binding.details.text = it } |
| 90 | viewLifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { | ||
| 91 | submenuProperty.detailsFlow.collect { binding.details.text = it } | ||
| 92 | } | ||
| 93 | } | ||
| 94 | } else { | 83 | } else { |
| 95 | binding.details.visibility = View.GONE | 84 | binding.details.setVisible(false) |
| 96 | } | 85 | } |
| 97 | } | 86 | } |
| 98 | } | 87 | } |
| @@ -112,14 +101,10 @@ class GamePropertiesAdapter( | |||
| 112 | ) | 101 | ) |
| 113 | ) | 102 | ) |
| 114 | 103 | ||
| 115 | if (installableProperty.install != null) { | 104 | binding.buttonInstall.setVisible(installableProperty.install != null) |
| 116 | binding.buttonInstall.visibility = View.VISIBLE | 105 | binding.buttonInstall.setOnClickListener { installableProperty.install?.invoke() } |
| 117 | binding.buttonInstall.setOnClickListener { installableProperty.install.invoke() } | 106 | binding.buttonExport.setVisible(installableProperty.export != null) |
| 118 | } | 107 | binding.buttonExport.setOnClickListener { installableProperty.export?.invoke() } |
| 119 | if (installableProperty.export != null) { | ||
| 120 | binding.buttonExport.visibility = View.VISIBLE | ||
| 121 | binding.buttonExport.setOnClickListener { installableProperty.export.invoke() } | ||
| 122 | } | ||
| 123 | } | 108 | } |
| 124 | } | 109 | } |
| 125 | 110 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt index b512845d5..0bd196673 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt | |||
| @@ -3,22 +3,19 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.adapters | 4 | package org.yuzu.yuzu_emu.adapters |
| 5 | 5 | ||
| 6 | import android.text.TextUtils | ||
| 7 | import android.view.LayoutInflater | 6 | import android.view.LayoutInflater |
| 8 | import android.view.View | ||
| 9 | import android.view.ViewGroup | 7 | import android.view.ViewGroup |
| 10 | import androidx.appcompat.app.AppCompatActivity | 8 | import androidx.appcompat.app.AppCompatActivity |
| 11 | import androidx.core.content.ContextCompat | 9 | import androidx.core.content.ContextCompat |
| 12 | import androidx.core.content.res.ResourcesCompat | 10 | import androidx.core.content.res.ResourcesCompat |
| 13 | import androidx.lifecycle.Lifecycle | ||
| 14 | import androidx.lifecycle.LifecycleOwner | 11 | import androidx.lifecycle.LifecycleOwner |
| 15 | import androidx.lifecycle.lifecycleScope | ||
| 16 | import androidx.lifecycle.repeatOnLifecycle | ||
| 17 | import kotlinx.coroutines.launch | ||
| 18 | import org.yuzu.yuzu_emu.R | 12 | import org.yuzu.yuzu_emu.R |
| 19 | import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding | 13 | import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding |
| 20 | import org.yuzu.yuzu_emu.fragments.MessageDialogFragment | 14 | import org.yuzu.yuzu_emu.fragments.MessageDialogFragment |
| 21 | import org.yuzu.yuzu_emu.model.HomeSetting | 15 | import org.yuzu.yuzu_emu.model.HomeSetting |
| 16 | import org.yuzu.yuzu_emu.utils.ViewUtils.marquee | ||
| 17 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 18 | import org.yuzu.yuzu_emu.utils.collect | ||
| 22 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | 19 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder |
| 23 | 20 | ||
| 24 | class HomeSettingAdapter( | 21 | class HomeSettingAdapter( |
| @@ -59,18 +56,8 @@ class HomeSettingAdapter( | |||
| 59 | binding.optionIcon.alpha = 0.5f | 56 | binding.optionIcon.alpha = 0.5f |
| 60 | } | 57 | } |
| 61 | 58 | ||
| 62 | viewLifecycle.lifecycleScope.launch { | 59 | model.details.collect(viewLifecycle) { updateOptionDetails(it) } |
| 63 | viewLifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) { | 60 | binding.optionDetail.marquee() |
| 64 | model.details.collect { updateOptionDetails(it) } | ||
| 65 | } | ||
| 66 | } | ||
| 67 | binding.optionDetail.postDelayed( | ||
| 68 | { | ||
| 69 | binding.optionDetail.ellipsize = TextUtils.TruncateAt.MARQUEE | ||
| 70 | binding.optionDetail.isSelected = true | ||
| 71 | }, | ||
| 72 | 3000 | ||
| 73 | ) | ||
| 74 | 61 | ||
| 75 | binding.root.setOnClickListener { onClick(model) } | 62 | binding.root.setOnClickListener { onClick(model) } |
| 76 | } | 63 | } |
| @@ -90,7 +77,7 @@ class HomeSettingAdapter( | |||
| 90 | private fun updateOptionDetails(detailString: String) { | 77 | private fun updateOptionDetails(detailString: String) { |
| 91 | if (detailString.isNotEmpty()) { | 78 | if (detailString.isNotEmpty()) { |
| 92 | binding.optionDetail.text = detailString | 79 | binding.optionDetail.text = detailString |
| 93 | binding.optionDetail.visibility = View.VISIBLE | 80 | binding.optionDetail.setVisible(true) |
| 94 | } | 81 | } |
| 95 | } | 82 | } |
| 96 | } | 83 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/InstallableAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/InstallableAdapter.kt index 4218c4e52..1ba75fa2f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/InstallableAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/InstallableAdapter.kt | |||
| @@ -4,10 +4,10 @@ | |||
| 4 | package org.yuzu.yuzu_emu.adapters | 4 | package org.yuzu.yuzu_emu.adapters |
| 5 | 5 | ||
| 6 | import android.view.LayoutInflater | 6 | import android.view.LayoutInflater |
| 7 | import android.view.View | ||
| 8 | import android.view.ViewGroup | 7 | import android.view.ViewGroup |
| 9 | import org.yuzu.yuzu_emu.databinding.CardInstallableBinding | 8 | import org.yuzu.yuzu_emu.databinding.CardInstallableBinding |
| 10 | import org.yuzu.yuzu_emu.model.Installable | 9 | import org.yuzu.yuzu_emu.model.Installable |
| 10 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 11 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | 11 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder |
| 12 | 12 | ||
| 13 | class InstallableAdapter(installables: List<Installable>) : | 13 | class InstallableAdapter(installables: List<Installable>) : |
| @@ -26,14 +26,10 @@ class InstallableAdapter(installables: List<Installable>) : | |||
| 26 | binding.title.setText(model.titleId) | 26 | binding.title.setText(model.titleId) |
| 27 | binding.description.setText(model.descriptionId) | 27 | binding.description.setText(model.descriptionId) |
| 28 | 28 | ||
| 29 | if (model.install != null) { | 29 | binding.buttonInstall.setVisible(model.install != null) |
| 30 | binding.buttonInstall.visibility = View.VISIBLE | 30 | binding.buttonInstall.setOnClickListener { model.install?.invoke() } |
| 31 | binding.buttonInstall.setOnClickListener { model.install.invoke() } | 31 | binding.buttonExport.setVisible(model.export != null) |
| 32 | } | 32 | binding.buttonExport.setOnClickListener { model.export?.invoke() } |
| 33 | if (model.export != null) { | ||
| 34 | binding.buttonExport.visibility = View.VISIBLE | ||
| 35 | binding.buttonExport.setOnClickListener { model.export.invoke() } | ||
| 36 | } | ||
| 37 | } | 33 | } |
| 38 | } | 34 | } |
| 39 | } | 35 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt index 38bb1f96f..1379968f9 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt | |||
| @@ -4,12 +4,12 @@ | |||
| 4 | package org.yuzu.yuzu_emu.adapters | 4 | package org.yuzu.yuzu_emu.adapters |
| 5 | 5 | ||
| 6 | import android.view.LayoutInflater | 6 | import android.view.LayoutInflater |
| 7 | import android.view.View | ||
| 8 | import android.view.ViewGroup | 7 | import android.view.ViewGroup |
| 9 | import androidx.appcompat.app.AppCompatActivity | 8 | import androidx.appcompat.app.AppCompatActivity |
| 10 | import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding | 9 | import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding |
| 11 | import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment | 10 | import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment |
| 12 | import org.yuzu.yuzu_emu.model.License | 11 | import org.yuzu.yuzu_emu.model.License |
| 12 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 13 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | 13 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder |
| 14 | 14 | ||
| 15 | class LicenseAdapter(private val activity: AppCompatActivity, licenses: List<License>) : | 15 | class LicenseAdapter(private val activity: AppCompatActivity, licenses: List<License>) : |
| @@ -25,7 +25,7 @@ class LicenseAdapter(private val activity: AppCompatActivity, licenses: List<Lic | |||
| 25 | binding.apply { | 25 | binding.apply { |
| 26 | textSettingName.text = root.context.getString(model.titleId) | 26 | textSettingName.text = root.context.getString(model.titleId) |
| 27 | textSettingDescription.text = root.context.getString(model.descriptionId) | 27 | textSettingDescription.text = root.context.getString(model.descriptionId) |
| 28 | textSettingValue.visibility = View.GONE | 28 | textSettingValue.setVisible(false) |
| 29 | 29 | ||
| 30 | root.setOnClickListener { onClick(model) } | 30 | root.setOnClickListener { onClick(model) } |
| 31 | } | 31 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt index 02118e1a8..a5f610b31 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt | |||
| @@ -5,7 +5,6 @@ package org.yuzu.yuzu_emu.adapters | |||
| 5 | 5 | ||
| 6 | import android.text.Html | 6 | import android.text.Html |
| 7 | import android.view.LayoutInflater | 7 | import android.view.LayoutInflater |
| 8 | import android.view.View | ||
| 9 | import android.view.ViewGroup | 8 | import android.view.ViewGroup |
| 10 | import androidx.appcompat.app.AppCompatActivity | 9 | import androidx.appcompat.app.AppCompatActivity |
| 11 | import androidx.core.content.res.ResourcesCompat | 10 | import androidx.core.content.res.ResourcesCompat |
| @@ -17,6 +16,7 @@ import org.yuzu.yuzu_emu.model.SetupCallback | |||
| 17 | import org.yuzu.yuzu_emu.model.SetupPage | 16 | import org.yuzu.yuzu_emu.model.SetupPage |
| 18 | import org.yuzu.yuzu_emu.model.StepState | 17 | import org.yuzu.yuzu_emu.model.StepState |
| 19 | import org.yuzu.yuzu_emu.utils.ViewUtils | 18 | import org.yuzu.yuzu_emu.utils.ViewUtils |
| 19 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 20 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | 20 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder |
| 21 | 21 | ||
| 22 | class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) : | 22 | class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) : |
| @@ -30,8 +30,8 @@ class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) : | |||
| 30 | AbstractViewHolder<SetupPage>(binding), SetupCallback { | 30 | AbstractViewHolder<SetupPage>(binding), SetupCallback { |
| 31 | override fun bind(model: SetupPage) { | 31 | override fun bind(model: SetupPage) { |
| 32 | if (model.stepCompleted.invoke() == StepState.COMPLETE) { | 32 | if (model.stepCompleted.invoke() == StepState.COMPLETE) { |
| 33 | binding.buttonAction.visibility = View.INVISIBLE | 33 | binding.buttonAction.setVisible(visible = false, gone = false) |
| 34 | binding.textConfirmation.visibility = View.VISIBLE | 34 | binding.textConfirmation.setVisible(true) |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | binding.icon.setImageDrawable( | 37 | binding.icon.setImageDrawable( |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/NativeInput.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/NativeInput.kt new file mode 100644 index 000000000..15d776311 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/NativeInput.kt | |||
| @@ -0,0 +1,416 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.input | ||
| 5 | |||
| 6 | import org.yuzu.yuzu_emu.features.input.model.NativeButton | ||
| 7 | import org.yuzu.yuzu_emu.features.input.model.NativeAnalog | ||
| 8 | import org.yuzu.yuzu_emu.features.input.model.InputType | ||
| 9 | import org.yuzu.yuzu_emu.features.input.model.ButtonName | ||
| 10 | import org.yuzu.yuzu_emu.features.input.model.NpadStyleIndex | ||
| 11 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 12 | import org.yuzu.yuzu_emu.utils.ParamPackage | ||
| 13 | import android.view.InputDevice | ||
| 14 | |||
| 15 | object NativeInput { | ||
| 16 | /** | ||
| 17 | * Default controller id for each device | ||
| 18 | */ | ||
| 19 | const val Player1Device = 0 | ||
| 20 | const val Player2Device = 1 | ||
| 21 | const val Player3Device = 2 | ||
| 22 | const val Player4Device = 3 | ||
| 23 | const val Player5Device = 4 | ||
| 24 | const val Player6Device = 5 | ||
| 25 | const val Player7Device = 6 | ||
| 26 | const val Player8Device = 7 | ||
| 27 | const val ConsoleDevice = 8 | ||
| 28 | |||
| 29 | /** | ||
| 30 | * Button states | ||
| 31 | */ | ||
| 32 | object ButtonState { | ||
| 33 | const val RELEASED = 0 | ||
| 34 | const val PRESSED = 1 | ||
| 35 | } | ||
| 36 | |||
| 37 | /** | ||
| 38 | * Returns true if pro controller isn't available and handheld is. | ||
| 39 | * Intended to check where the input overlay should direct its inputs. | ||
| 40 | */ | ||
| 41 | external fun isHandheldOnly(): Boolean | ||
| 42 | |||
| 43 | /** | ||
| 44 | * Handles button press events for a gamepad. | ||
| 45 | * @param guid 32 character hexadecimal string consisting of the controller's PID+VID. | ||
| 46 | * @param port Port determined by controller connection order. | ||
| 47 | * @param buttonId The Android Keycode corresponding to this event. | ||
| 48 | * @param action Mask identifying which action is happening (button pressed down, or button released). | ||
| 49 | */ | ||
| 50 | external fun onGamePadButtonEvent( | ||
| 51 | guid: String, | ||
| 52 | port: Int, | ||
| 53 | buttonId: Int, | ||
| 54 | action: Int | ||
| 55 | ) | ||
| 56 | |||
| 57 | /** | ||
| 58 | * Handles axis movement events. | ||
| 59 | * @param guid 32 character hexadecimal string consisting of the controller's PID+VID. | ||
| 60 | * @param port Port determined by controller connection order. | ||
| 61 | * @param axis The axis ID. | ||
| 62 | * @param value Value along the given axis. | ||
| 63 | */ | ||
| 64 | external fun onGamePadAxisEvent(guid: String, port: Int, axis: Int, value: Float) | ||
| 65 | |||
| 66 | /** | ||
| 67 | * Handles motion events. | ||
| 68 | * @param guid 32 character hexadecimal string consisting of the controller's PID+VID. | ||
| 69 | * @param port Port determined by controller connection order. | ||
| 70 | * @param deltaTimestamp The finger id corresponding to this event. | ||
| 71 | * @param xGyro The value of the x-axis for the gyroscope. | ||
| 72 | * @param yGyro The value of the y-axis for the gyroscope. | ||
| 73 | * @param zGyro The value of the z-axis for the gyroscope. | ||
| 74 | * @param xAccel The value of the x-axis for the accelerometer. | ||
| 75 | * @param yAccel The value of the y-axis for the accelerometer. | ||
| 76 | * @param zAccel The value of the z-axis for the accelerometer. | ||
| 77 | */ | ||
| 78 | external fun onGamePadMotionEvent( | ||
| 79 | guid: String, | ||
| 80 | port: Int, | ||
| 81 | deltaTimestamp: Long, | ||
| 82 | xGyro: Float, | ||
| 83 | yGyro: Float, | ||
| 84 | zGyro: Float, | ||
| 85 | xAccel: Float, | ||
| 86 | yAccel: Float, | ||
| 87 | zAccel: Float | ||
| 88 | ) | ||
| 89 | |||
| 90 | /** | ||
| 91 | * Signals and load a nfc tag | ||
| 92 | * @param data Byte array containing all the data from a nfc tag. | ||
| 93 | */ | ||
| 94 | external fun onReadNfcTag(data: ByteArray?) | ||
| 95 | |||
| 96 | /** | ||
| 97 | * Removes current loaded nfc tag. | ||
| 98 | */ | ||
| 99 | external fun onRemoveNfcTag() | ||
| 100 | |||
| 101 | /** | ||
| 102 | * Handles touch press events. | ||
| 103 | * @param fingerId The finger id corresponding to this event. | ||
| 104 | * @param xAxis The value of the x-axis on the touchscreen. | ||
| 105 | * @param yAxis The value of the y-axis on the touchscreen. | ||
| 106 | */ | ||
| 107 | external fun onTouchPressed(fingerId: Int, xAxis: Float, yAxis: Float) | ||
| 108 | |||
| 109 | /** | ||
| 110 | * Handles touch movement. | ||
| 111 | * @param fingerId The finger id corresponding to this event. | ||
| 112 | * @param xAxis The value of the x-axis on the touchscreen. | ||
| 113 | * @param yAxis The value of the y-axis on the touchscreen. | ||
| 114 | */ | ||
| 115 | external fun onTouchMoved(fingerId: Int, xAxis: Float, yAxis: Float) | ||
| 116 | |||
| 117 | /** | ||
| 118 | * Handles touch release events. | ||
| 119 | * @param fingerId The finger id corresponding to this event | ||
| 120 | */ | ||
| 121 | external fun onTouchReleased(fingerId: Int) | ||
| 122 | |||
| 123 | /** | ||
| 124 | * Sends a button input to the global virtual controllers. | ||
| 125 | * @param port Port determined by controller connection order. | ||
| 126 | * @param button The [NativeButton] corresponding to this event. | ||
| 127 | * @param action Mask identifying which action is happening (button pressed down, or button released). | ||
| 128 | */ | ||
| 129 | fun onOverlayButtonEvent(port: Int, button: NativeButton, action: Int) = | ||
| 130 | onOverlayButtonEventImpl(port, button.int, action) | ||
| 131 | |||
| 132 | private external fun onOverlayButtonEventImpl(port: Int, buttonId: Int, action: Int) | ||
| 133 | |||
| 134 | /** | ||
| 135 | * Sends a joystick input to the global virtual controllers. | ||
| 136 | * @param port Port determined by controller connection order. | ||
| 137 | * @param stick The [NativeAnalog] corresponding to this event. | ||
| 138 | * @param xAxis Value along the X axis. | ||
| 139 | * @param yAxis Value along the Y axis. | ||
| 140 | */ | ||
| 141 | fun onOverlayJoystickEvent(port: Int, stick: NativeAnalog, xAxis: Float, yAxis: Float) = | ||
| 142 | onOverlayJoystickEventImpl(port, stick.int, xAxis, yAxis) | ||
| 143 | |||
| 144 | private external fun onOverlayJoystickEventImpl( | ||
| 145 | port: Int, | ||
| 146 | stickId: Int, | ||
| 147 | xAxis: Float, | ||
| 148 | yAxis: Float | ||
| 149 | ) | ||
| 150 | |||
| 151 | /** | ||
| 152 | * Handles motion events for the global virtual controllers. | ||
| 153 | * @param port Port determined by controller connection order | ||
| 154 | * @param deltaTimestamp The finger id corresponding to this event. | ||
| 155 | * @param xGyro The value of the x-axis for the gyroscope. | ||
| 156 | * @param yGyro The value of the y-axis for the gyroscope. | ||
| 157 | * @param zGyro The value of the z-axis for the gyroscope. | ||
| 158 | * @param xAccel The value of the x-axis for the accelerometer. | ||
| 159 | * @param yAccel The value of the y-axis for the accelerometer. | ||
| 160 | * @param zAccel The value of the z-axis for the accelerometer. | ||
| 161 | */ | ||
| 162 | external fun onDeviceMotionEvent( | ||
| 163 | port: Int, | ||
| 164 | deltaTimestamp: Long, | ||
| 165 | xGyro: Float, | ||
| 166 | yGyro: Float, | ||
| 167 | zGyro: Float, | ||
| 168 | xAccel: Float, | ||
| 169 | yAccel: Float, | ||
| 170 | zAccel: Float | ||
| 171 | ) | ||
| 172 | |||
| 173 | /** | ||
| 174 | * Reloads all input devices from the currently loaded Settings::values.players into HID Core | ||
| 175 | */ | ||
| 176 | external fun reloadInputDevices() | ||
| 177 | |||
| 178 | /** | ||
| 179 | * Registers a controller to be used with mapping | ||
| 180 | * @param device An [InputDevice] or the input overlay wrapped with [YuzuInputDevice] | ||
| 181 | */ | ||
| 182 | external fun registerController(device: YuzuInputDevice) | ||
| 183 | |||
| 184 | /** | ||
| 185 | * Gets the names of input devices that have been registered with the input subsystem via [registerController] | ||
| 186 | */ | ||
| 187 | external fun getInputDevices(): Array<String> | ||
| 188 | |||
| 189 | /** | ||
| 190 | * Reads all input profiles from disk. Must be called before creating a profile picker. | ||
| 191 | */ | ||
| 192 | external fun loadInputProfiles() | ||
| 193 | |||
| 194 | /** | ||
| 195 | * Gets the names of each available input profile. | ||
| 196 | */ | ||
| 197 | external fun getInputProfileNames(): Array<String> | ||
| 198 | |||
| 199 | /** | ||
| 200 | * Checks if the user-provided name for an input profile is valid. | ||
| 201 | * @param name User-provided name for an input profile. | ||
| 202 | * @return Whether [name] is valid or not. | ||
| 203 | */ | ||
| 204 | external fun isProfileNameValid(name: String): Boolean | ||
| 205 | |||
| 206 | /** | ||
| 207 | * Creates a new input profile. | ||
| 208 | * @param name The new profile's name. | ||
| 209 | * @param playerIndex Index of the player that's currently being edited. Used to write the profile | ||
| 210 | * name to this player's config. | ||
| 211 | * @return Whether creating the profile was successful or not. | ||
| 212 | */ | ||
| 213 | external fun createProfile(name: String, playerIndex: Int): Boolean | ||
| 214 | |||
| 215 | /** | ||
| 216 | * Deletes an input profile. | ||
| 217 | * @param name Name of the profile to delete. | ||
| 218 | * @param playerIndex Index of the player that's currently being edited. Used to remove the profile | ||
| 219 | * name from this player's config if they have it loaded. | ||
| 220 | * @return Whether deleting this profile was successful or not. | ||
| 221 | */ | ||
| 222 | external fun deleteProfile(name: String, playerIndex: Int): Boolean | ||
| 223 | |||
| 224 | /** | ||
| 225 | * Loads an input profile. | ||
| 226 | * @param name Name of the input profile to load. | ||
| 227 | * @param playerIndex Index of the player that will have this profile loaded. | ||
| 228 | * @return Whether loading this profile was successful or not. | ||
| 229 | */ | ||
| 230 | external fun loadProfile(name: String, playerIndex: Int): Boolean | ||
| 231 | |||
| 232 | /** | ||
| 233 | * Saves an input profile. | ||
| 234 | * @param name Name of the profile to save. | ||
| 235 | * @param playerIndex Index of the player that's currently being edited. Used to write the profile | ||
| 236 | * name to this player's config. | ||
| 237 | * @return Whether saving the profile was successful or not. | ||
| 238 | */ | ||
| 239 | external fun saveProfile(name: String, playerIndex: Int): Boolean | ||
| 240 | |||
| 241 | /** | ||
| 242 | * Intended to be used immediately before a call to [NativeConfig.saveControlPlayerValues] | ||
| 243 | * Must be used while per-game config is loaded. | ||
| 244 | */ | ||
| 245 | external fun loadPerGameConfiguration( | ||
| 246 | playerIndex: Int, | ||
| 247 | selectedIndex: Int, | ||
| 248 | selectedProfileName: String | ||
| 249 | ) | ||
| 250 | |||
| 251 | /** | ||
| 252 | * Tells the input subsystem to start listening for inputs to map. | ||
| 253 | * @param type Type of input to map as shown by the int property in each [InputType]. | ||
| 254 | */ | ||
| 255 | external fun beginMapping(type: Int) | ||
| 256 | |||
| 257 | /** | ||
| 258 | * Gets an input's [ParamPackage] as a serialized string. Used for input verification before mapping. | ||
| 259 | * Must be run after [beginMapping] and before [stopMapping]. | ||
| 260 | */ | ||
| 261 | external fun getNextInput(): String | ||
| 262 | |||
| 263 | /** | ||
| 264 | * Tells the input subsystem to stop listening for inputs to map. | ||
| 265 | */ | ||
| 266 | external fun stopMapping() | ||
| 267 | |||
| 268 | /** | ||
| 269 | * Updates a controller's mappings with auto-mapping params. | ||
| 270 | * @param playerIndex Index of the player to auto-map. | ||
| 271 | * @param deviceParams [ParamPackage] representing the device to auto-map as received | ||
| 272 | * from [getInputDevices]. | ||
| 273 | * @param displayName Name of the device to auto-map as received from the "display" param in [deviceParams]. | ||
| 274 | * Intended to be a way to provide a default name for a controller if the "display" param is empty. | ||
| 275 | */ | ||
| 276 | fun updateMappingsWithDefault( | ||
| 277 | playerIndex: Int, | ||
| 278 | deviceParams: ParamPackage, | ||
| 279 | displayName: String | ||
| 280 | ) = updateMappingsWithDefaultImpl(playerIndex, deviceParams.serialize(), displayName) | ||
| 281 | |||
| 282 | private external fun updateMappingsWithDefaultImpl( | ||
| 283 | playerIndex: Int, | ||
| 284 | deviceParams: String, | ||
| 285 | displayName: String | ||
| 286 | ) | ||
| 287 | |||
| 288 | /** | ||
| 289 | * Gets the params for a specific button. | ||
| 290 | * @param playerIndex Index of the player to get params from. | ||
| 291 | * @param button The [NativeButton] to get params for. | ||
| 292 | * @return A [ParamPackage] representing a player's specific button. | ||
| 293 | */ | ||
| 294 | fun getButtonParam(playerIndex: Int, button: NativeButton): ParamPackage = | ||
| 295 | ParamPackage(getButtonParamImpl(playerIndex, button.int)) | ||
| 296 | |||
| 297 | private external fun getButtonParamImpl(playerIndex: Int, buttonId: Int): String | ||
| 298 | |||
| 299 | /** | ||
| 300 | * Sets the params for a specific button. | ||
| 301 | * @param playerIndex Index of the player to set params for. | ||
| 302 | * @param button The [NativeButton] to set params for. | ||
| 303 | * @param param A [ParamPackage] to set. | ||
| 304 | */ | ||
| 305 | fun setButtonParam(playerIndex: Int, button: NativeButton, param: ParamPackage) = | ||
| 306 | setButtonParamImpl(playerIndex, button.int, param.serialize()) | ||
| 307 | |||
| 308 | private external fun setButtonParamImpl(playerIndex: Int, buttonId: Int, param: String) | ||
| 309 | |||
| 310 | /** | ||
| 311 | * Gets the params for a specific stick. | ||
| 312 | * @param playerIndex Index of the player to get params from. | ||
| 313 | * @param stick The [NativeAnalog] to get params for. | ||
| 314 | * @return A [ParamPackage] representing a player's specific stick. | ||
| 315 | */ | ||
| 316 | fun getStickParam(playerIndex: Int, stick: NativeAnalog): ParamPackage = | ||
| 317 | ParamPackage(getStickParamImpl(playerIndex, stick.int)) | ||
| 318 | |||
| 319 | private external fun getStickParamImpl(playerIndex: Int, stickId: Int): String | ||
| 320 | |||
| 321 | /** | ||
| 322 | * Sets the params for a specific stick. | ||
| 323 | * @param playerIndex Index of the player to set params for. | ||
| 324 | * @param stick The [NativeAnalog] to set params for. | ||
| 325 | * @param param A [ParamPackage] to set. | ||
| 326 | */ | ||
| 327 | fun setStickParam(playerIndex: Int, stick: NativeAnalog, param: ParamPackage) = | ||
| 328 | setStickParamImpl(playerIndex, stick.int, param.serialize()) | ||
| 329 | |||
| 330 | private external fun setStickParamImpl(playerIndex: Int, stickId: Int, param: String) | ||
| 331 | |||
| 332 | /** | ||
| 333 | * Gets the int representation of a [ButtonName]. Tells you what to show as the mapped input for | ||
| 334 | * a button/analog/other. | ||
| 335 | * @param param A [ParamPackage] that represents a specific button's params. | ||
| 336 | * @return The [ButtonName] for [param]. | ||
| 337 | */ | ||
| 338 | fun getButtonName(param: ParamPackage): ButtonName = | ||
| 339 | ButtonName.from(getButtonNameImpl(param.serialize())) | ||
| 340 | |||
| 341 | private external fun getButtonNameImpl(param: String): Int | ||
| 342 | |||
| 343 | /** | ||
| 344 | * Gets each supported [NpadStyleIndex] for a given player. | ||
| 345 | * @param playerIndex Index of the player to get supported indexes for. | ||
| 346 | * @return List of each supported [NpadStyleIndex]. | ||
| 347 | */ | ||
| 348 | fun getSupportedStyleTags(playerIndex: Int): List<NpadStyleIndex> = | ||
| 349 | getSupportedStyleTagsImpl(playerIndex).map { NpadStyleIndex.from(it) } | ||
| 350 | |||
| 351 | private external fun getSupportedStyleTagsImpl(playerIndex: Int): IntArray | ||
| 352 | |||
| 353 | /** | ||
| 354 | * Gets the [NpadStyleIndex] for a given player. | ||
| 355 | * @param playerIndex Index of the player to get an [NpadStyleIndex] from. | ||
| 356 | * @return The [NpadStyleIndex] for a given player. | ||
| 357 | */ | ||
| 358 | fun getStyleIndex(playerIndex: Int): NpadStyleIndex = | ||
| 359 | NpadStyleIndex.from(getStyleIndexImpl(playerIndex)) | ||
| 360 | |||
| 361 | private external fun getStyleIndexImpl(playerIndex: Int): Int | ||
| 362 | |||
| 363 | /** | ||
| 364 | * Sets the [NpadStyleIndex] for a given player. | ||
| 365 | * @param playerIndex Index of the player to change. | ||
| 366 | * @param style The new style to set. | ||
| 367 | */ | ||
| 368 | fun setStyleIndex(playerIndex: Int, style: NpadStyleIndex) = | ||
| 369 | setStyleIndexImpl(playerIndex, style.int) | ||
| 370 | |||
| 371 | private external fun setStyleIndexImpl(playerIndex: Int, styleIndex: Int) | ||
| 372 | |||
| 373 | /** | ||
| 374 | * Checks if a device is a controller. | ||
| 375 | * @param params [ParamPackage] for an input device retrieved from [getInputDevices] | ||
| 376 | * @return Whether the device is a controller or not. | ||
| 377 | */ | ||
| 378 | fun isController(params: ParamPackage): Boolean = isControllerImpl(params.serialize()) | ||
| 379 | |||
| 380 | private external fun isControllerImpl(params: String): Boolean | ||
| 381 | |||
| 382 | /** | ||
| 383 | * Checks if a controller is connected | ||
| 384 | * @param playerIndex Index of the player to check. | ||
| 385 | * @return Whether the player is connected or not. | ||
| 386 | */ | ||
| 387 | external fun getIsConnected(playerIndex: Int): Boolean | ||
| 388 | |||
| 389 | /** | ||
| 390 | * Connects/disconnects a controller and ensures that connection order stays in-tact. | ||
| 391 | * @param playerIndex Index of the player to connect/disconnect. | ||
| 392 | * @param connected Whether to connect or disconnect this controller. | ||
| 393 | */ | ||
| 394 | fun connectControllers(playerIndex: Int, connected: Boolean = true) { | ||
| 395 | val connectedControllers = mutableListOf<Boolean>().apply { | ||
| 396 | if (connected) { | ||
| 397 | for (i in 0 until 8) { | ||
| 398 | add(i <= playerIndex) | ||
| 399 | } | ||
| 400 | } else { | ||
| 401 | for (i in 0 until 8) { | ||
| 402 | add(i < playerIndex) | ||
| 403 | } | ||
| 404 | } | ||
| 405 | } | ||
| 406 | connectControllersImpl(connectedControllers.toBooleanArray()) | ||
| 407 | } | ||
| 408 | |||
| 409 | private external fun connectControllersImpl(connected: BooleanArray) | ||
| 410 | |||
| 411 | /** | ||
| 412 | * Resets all of the button and analog mappings for a player. | ||
| 413 | * @param playerIndex Index of the player that will have its mappings reset. | ||
| 414 | */ | ||
| 415 | external fun resetControllerMappings(playerIndex: Int) | ||
| 416 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/YuzuInputDevice.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/YuzuInputDevice.kt new file mode 100644 index 000000000..15cc38c7f --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/YuzuInputDevice.kt | |||
| @@ -0,0 +1,93 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.input | ||
| 5 | |||
| 6 | import android.view.InputDevice | ||
| 7 | import androidx.annotation.Keep | ||
| 8 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 9 | import org.yuzu.yuzu_emu.R | ||
| 10 | import org.yuzu.yuzu_emu.utils.InputHandler.getGUID | ||
| 11 | |||
| 12 | @Keep | ||
| 13 | interface YuzuInputDevice { | ||
| 14 | fun getName(): String | ||
| 15 | |||
| 16 | fun getGUID(): String | ||
| 17 | |||
| 18 | fun getPort(): Int | ||
| 19 | |||
| 20 | fun getSupportsVibration(): Boolean | ||
| 21 | |||
| 22 | fun vibrate(intensity: Float) | ||
| 23 | |||
| 24 | fun getAxes(): Array<Int> = arrayOf() | ||
| 25 | fun hasKeys(keys: IntArray): BooleanArray = BooleanArray(0) | ||
| 26 | } | ||
| 27 | |||
| 28 | class YuzuPhysicalDevice( | ||
| 29 | private val device: InputDevice, | ||
| 30 | private val port: Int, | ||
| 31 | useSystemVibrator: Boolean | ||
| 32 | ) : YuzuInputDevice { | ||
| 33 | private val vibrator = if (useSystemVibrator) { | ||
| 34 | YuzuVibrator.getSystemVibrator() | ||
| 35 | } else { | ||
| 36 | YuzuVibrator.getControllerVibrator(device) | ||
| 37 | } | ||
| 38 | |||
| 39 | override fun getName(): String { | ||
| 40 | return device.name | ||
| 41 | } | ||
| 42 | |||
| 43 | override fun getGUID(): String { | ||
| 44 | return device.getGUID() | ||
| 45 | } | ||
| 46 | |||
| 47 | override fun getPort(): Int { | ||
| 48 | return port | ||
| 49 | } | ||
| 50 | |||
| 51 | override fun getSupportsVibration(): Boolean { | ||
| 52 | return vibrator.supportsVibration() | ||
| 53 | } | ||
| 54 | |||
| 55 | override fun vibrate(intensity: Float) { | ||
| 56 | vibrator.vibrate(intensity) | ||
| 57 | } | ||
| 58 | |||
| 59 | override fun getAxes(): Array<Int> = device.motionRanges.map { it.axis }.toTypedArray() | ||
| 60 | override fun hasKeys(keys: IntArray): BooleanArray = device.hasKeys(*keys) | ||
| 61 | } | ||
| 62 | |||
| 63 | class YuzuInputOverlayDevice( | ||
| 64 | private val vibration: Boolean, | ||
| 65 | private val port: Int | ||
| 66 | ) : YuzuInputDevice { | ||
| 67 | private val vibrator = YuzuVibrator.getSystemVibrator() | ||
| 68 | |||
| 69 | override fun getName(): String { | ||
| 70 | return YuzuApplication.appContext.getString(R.string.input_overlay) | ||
| 71 | } | ||
| 72 | |||
| 73 | override fun getGUID(): String { | ||
| 74 | return "00000000000000000000000000000000" | ||
| 75 | } | ||
| 76 | |||
| 77 | override fun getPort(): Int { | ||
| 78 | return port | ||
| 79 | } | ||
| 80 | |||
| 81 | override fun getSupportsVibration(): Boolean { | ||
| 82 | if (vibration) { | ||
| 83 | return vibrator.supportsVibration() | ||
| 84 | } | ||
| 85 | return false | ||
| 86 | } | ||
| 87 | |||
| 88 | override fun vibrate(intensity: Float) { | ||
| 89 | if (vibration) { | ||
| 90 | vibrator.vibrate(intensity) | ||
| 91 | } | ||
| 92 | } | ||
| 93 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/YuzuVibrator.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/YuzuVibrator.kt new file mode 100644 index 000000000..aac49ecae --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/YuzuVibrator.kt | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.input | ||
| 5 | |||
| 6 | import android.content.Context | ||
| 7 | import android.os.Build | ||
| 8 | import android.os.CombinedVibration | ||
| 9 | import android.os.VibrationEffect | ||
| 10 | import android.os.Vibrator | ||
| 11 | import android.os.VibratorManager | ||
| 12 | import android.view.InputDevice | ||
| 13 | import androidx.annotation.Keep | ||
| 14 | import androidx.annotation.RequiresApi | ||
| 15 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 16 | |||
| 17 | @Keep | ||
| 18 | @Suppress("DEPRECATION") | ||
| 19 | interface YuzuVibrator { | ||
| 20 | fun supportsVibration(): Boolean | ||
| 21 | |||
| 22 | fun vibrate(intensity: Float) | ||
| 23 | |||
| 24 | companion object { | ||
| 25 | fun getControllerVibrator(device: InputDevice): YuzuVibrator = | ||
| 26 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { | ||
| 27 | YuzuVibratorManager(device.vibratorManager) | ||
| 28 | } else { | ||
| 29 | YuzuVibratorManagerCompat(device.vibrator) | ||
| 30 | } | ||
| 31 | |||
| 32 | fun getSystemVibrator(): YuzuVibrator = | ||
| 33 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { | ||
| 34 | val vibratorManager = YuzuApplication.appContext | ||
| 35 | .getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager | ||
| 36 | YuzuVibratorManager(vibratorManager) | ||
| 37 | } else { | ||
| 38 | val vibrator = YuzuApplication.appContext | ||
| 39 | .getSystemService(Context.VIBRATOR_SERVICE) as Vibrator | ||
| 40 | YuzuVibratorManagerCompat(vibrator) | ||
| 41 | } | ||
| 42 | |||
| 43 | fun getVibrationEffect(intensity: Float): VibrationEffect? { | ||
| 44 | if (intensity > 0f) { | ||
| 45 | return VibrationEffect.createOneShot( | ||
| 46 | 50, | ||
| 47 | (255.0 * intensity).toInt().coerceIn(1, 255) | ||
| 48 | ) | ||
| 49 | } | ||
| 50 | return null | ||
| 51 | } | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | @RequiresApi(Build.VERSION_CODES.S) | ||
| 56 | class YuzuVibratorManager(private val vibratorManager: VibratorManager) : YuzuVibrator { | ||
| 57 | override fun supportsVibration(): Boolean { | ||
| 58 | return vibratorManager.vibratorIds.isNotEmpty() | ||
| 59 | } | ||
| 60 | |||
| 61 | override fun vibrate(intensity: Float) { | ||
| 62 | val vibration = YuzuVibrator.getVibrationEffect(intensity) ?: return | ||
| 63 | vibratorManager.vibrate(CombinedVibration.createParallel(vibration)) | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | class YuzuVibratorManagerCompat(private val vibrator: Vibrator) : YuzuVibrator { | ||
| 68 | override fun supportsVibration(): Boolean { | ||
| 69 | return vibrator.hasVibrator() | ||
| 70 | } | ||
| 71 | |||
| 72 | override fun vibrate(intensity: Float) { | ||
| 73 | val vibration = YuzuVibrator.getVibrationEffect(intensity) ?: return | ||
| 74 | vibrator.vibrate(vibration) | ||
| 75 | } | ||
| 76 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/AnalogDirection.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/AnalogDirection.kt new file mode 100644 index 000000000..0a5fab2ae --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/AnalogDirection.kt | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.input.model | ||
| 5 | |||
| 6 | enum class AnalogDirection(val int: Int, val param: String) { | ||
| 7 | Up(0, "up"), | ||
| 8 | Down(1, "down"), | ||
| 9 | Left(2, "left"), | ||
| 10 | Right(3, "right") | ||
| 11 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/ButtonName.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/ButtonName.kt new file mode 100644 index 000000000..b8846ecad --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/ButtonName.kt | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.input.model | ||
| 5 | |||
| 6 | // Loosely matches the enum in common/input.h | ||
| 7 | enum class ButtonName(val int: Int) { | ||
| 8 | Invalid(1), | ||
| 9 | |||
| 10 | // This will display the engine name instead of the button name | ||
| 11 | Engine(2), | ||
| 12 | |||
| 13 | // This will display the button by value instead of the button name | ||
| 14 | Value(3); | ||
| 15 | |||
| 16 | companion object { | ||
| 17 | fun from(int: Int): ButtonName = entries.firstOrNull { it.int == int } ?: Invalid | ||
| 18 | } | ||
| 19 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/InputType.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/InputType.kt new file mode 100644 index 000000000..f725231cb --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/InputType.kt | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.input.model | ||
| 5 | |||
| 6 | // Must match the corresponding enum in input_common/main.h | ||
| 7 | enum class InputType(val int: Int) { | ||
| 8 | None(0), | ||
| 9 | Button(1), | ||
| 10 | Stick(2), | ||
| 11 | Motion(3), | ||
| 12 | Touch(4) | ||
| 13 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/NativeAnalog.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/NativeAnalog.kt new file mode 100644 index 000000000..c3b7a785d --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/NativeAnalog.kt | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.input.model | ||
| 5 | |||
| 6 | // Must match enum in src/common/settings_input.h | ||
| 7 | enum class NativeAnalog(val int: Int) { | ||
| 8 | LStick(0), | ||
| 9 | RStick(1); | ||
| 10 | |||
| 11 | companion object { | ||
| 12 | fun from(int: Int): NativeAnalog = entries.firstOrNull { it.int == int } ?: LStick | ||
| 13 | } | ||
| 14 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/NativeButton.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/NativeButton.kt new file mode 100644 index 000000000..c5ccd7115 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/NativeButton.kt | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.input.model | ||
| 5 | |||
| 6 | // Must match enum in src/common/settings_input.h | ||
| 7 | enum class NativeButton(val int: Int) { | ||
| 8 | A(0), | ||
| 9 | B(1), | ||
| 10 | X(2), | ||
| 11 | Y(3), | ||
| 12 | LStick(4), | ||
| 13 | RStick(5), | ||
| 14 | L(6), | ||
| 15 | R(7), | ||
| 16 | ZL(8), | ||
| 17 | ZR(9), | ||
| 18 | Plus(10), | ||
| 19 | Minus(11), | ||
| 20 | |||
| 21 | DLeft(12), | ||
| 22 | DUp(13), | ||
| 23 | DRight(14), | ||
| 24 | DDown(15), | ||
| 25 | |||
| 26 | SLLeft(16), | ||
| 27 | SRLeft(17), | ||
| 28 | |||
| 29 | Home(18), | ||
| 30 | Capture(19), | ||
| 31 | |||
| 32 | SLRight(20), | ||
| 33 | SRRight(21); | ||
| 34 | |||
| 35 | companion object { | ||
| 36 | fun from(int: Int): NativeButton = entries.firstOrNull { it.int == int } ?: A | ||
| 37 | } | ||
| 38 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/NativeTrigger.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/NativeTrigger.kt new file mode 100644 index 000000000..625f352b4 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/NativeTrigger.kt | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.input.model | ||
| 5 | |||
| 6 | // Must match enum in src/common/settings_input.h | ||
| 7 | enum class NativeTrigger(val int: Int) { | ||
| 8 | LTrigger(0), | ||
| 9 | RTrigger(1) | ||
| 10 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/NpadStyleIndex.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/NpadStyleIndex.kt new file mode 100644 index 000000000..e2a3d7aff --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/NpadStyleIndex.kt | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.input.model | ||
| 5 | |||
| 6 | import androidx.annotation.StringRes | ||
| 7 | import org.yuzu.yuzu_emu.R | ||
| 8 | |||
| 9 | // Must match enum in src/core/hid/hid_types.h | ||
| 10 | enum class NpadStyleIndex(val int: Int, @StringRes val nameId: Int = 0) { | ||
| 11 | None(0), | ||
| 12 | Fullkey(3, R.string.pro_controller), | ||
| 13 | Handheld(4, R.string.handheld), | ||
| 14 | HandheldNES(4), | ||
| 15 | JoyconDual(5, R.string.dual_joycons), | ||
| 16 | JoyconLeft(6, R.string.left_joycon), | ||
| 17 | JoyconRight(7, R.string.right_joycon), | ||
| 18 | GameCube(8, R.string.gamecube_controller), | ||
| 19 | Pokeball(9), | ||
| 20 | NES(10), | ||
| 21 | SNES(12), | ||
| 22 | N64(13), | ||
| 23 | SegaGenesis(14), | ||
| 24 | SystemExt(32), | ||
| 25 | System(33); | ||
| 26 | |||
| 27 | companion object { | ||
| 28 | fun from(int: Int): NpadStyleIndex = entries.firstOrNull { it.int == int } ?: None | ||
| 29 | } | ||
| 30 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt new file mode 100644 index 000000000..d35de80c4 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.input.model | ||
| 5 | |||
| 6 | import androidx.annotation.Keep | ||
| 7 | |||
| 8 | @Keep | ||
| 9 | data class PlayerInput( | ||
| 10 | var connected: Boolean, | ||
| 11 | var buttons: Array<String>, | ||
| 12 | var analogs: Array<String>, | ||
| 13 | var motions: Array<String>, | ||
| 14 | |||
| 15 | var vibrationEnabled: Boolean, | ||
| 16 | var vibrationStrength: Int, | ||
| 17 | |||
| 18 | var bodyColorLeft: Long, | ||
| 19 | var bodyColorRight: Long, | ||
| 20 | var buttonColorLeft: Long, | ||
| 21 | var buttonColorRight: Long, | ||
| 22 | var profileName: String, | ||
| 23 | |||
| 24 | var useSystemVibrator: Boolean | ||
| 25 | ) { | ||
| 26 | // It's recommended to use the generated equals() and hashCode() methods | ||
| 27 | // when using arrays in a data class | ||
| 28 | override fun equals(other: Any?): Boolean { | ||
| 29 | if (this === other) return true | ||
| 30 | if (javaClass != other?.javaClass) return false | ||
| 31 | |||
| 32 | other as PlayerInput | ||
| 33 | |||
| 34 | if (connected != other.connected) return false | ||
| 35 | if (!buttons.contentEquals(other.buttons)) return false | ||
| 36 | if (!analogs.contentEquals(other.analogs)) return false | ||
| 37 | if (!motions.contentEquals(other.motions)) return false | ||
| 38 | if (vibrationEnabled != other.vibrationEnabled) return false | ||
| 39 | if (vibrationStrength != other.vibrationStrength) return false | ||
| 40 | if (bodyColorLeft != other.bodyColorLeft) return false | ||
| 41 | if (bodyColorRight != other.bodyColorRight) return false | ||
| 42 | if (buttonColorLeft != other.buttonColorLeft) return false | ||
| 43 | if (buttonColorRight != other.buttonColorRight) return false | ||
| 44 | if (profileName != other.profileName) return false | ||
| 45 | return useSystemVibrator == other.useSystemVibrator | ||
| 46 | } | ||
| 47 | |||
| 48 | override fun hashCode(): Int { | ||
| 49 | var result = connected.hashCode() | ||
| 50 | result = 31 * result + buttons.contentHashCode() | ||
| 51 | result = 31 * result + analogs.contentHashCode() | ||
| 52 | result = 31 * result + motions.contentHashCode() | ||
| 53 | result = 31 * result + vibrationEnabled.hashCode() | ||
| 54 | result = 31 * result + vibrationStrength | ||
| 55 | result = 31 * result + bodyColorLeft.hashCode() | ||
| 56 | result = 31 * result + bodyColorRight.hashCode() | ||
| 57 | result = 31 * result + buttonColorLeft.hashCode() | ||
| 58 | result = 31 * result + buttonColorRight.hashCode() | ||
| 59 | result = 31 * result + profileName.hashCode() | ||
| 60 | result = 31 * result + useSystemVibrator.hashCode() | ||
| 61 | return result | ||
| 62 | } | ||
| 63 | |||
| 64 | fun hasMapping(): Boolean { | ||
| 65 | var hasMapping = false | ||
| 66 | buttons.forEach { | ||
| 67 | if (it != "[empty]") { | ||
| 68 | hasMapping = true | ||
| 69 | } | ||
| 70 | } | ||
| 71 | analogs.forEach { | ||
| 72 | if (it != "[empty]") { | ||
| 73 | hasMapping = true | ||
| 74 | } | ||
| 75 | } | ||
| 76 | motions.forEach { | ||
| 77 | if (it != "[empty]") { | ||
| 78 | hasMapping = true | ||
| 79 | } | ||
| 80 | } | ||
| 81 | return hasMapping | ||
| 82 | } | ||
| 83 | } | ||
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 862c6c483..4f6b93bd2 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 | |||
| @@ -4,17 +4,30 @@ | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | 4 | package org.yuzu.yuzu_emu.features.settings.model |
| 5 | 5 | ||
| 6 | import org.yuzu.yuzu_emu.R | 6 | import org.yuzu.yuzu_emu.R |
| 7 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 7 | 8 | ||
| 8 | object Settings { | 9 | object Settings { |
| 9 | enum class MenuTag(val titleId: Int) { | 10 | enum class MenuTag(val titleId: Int = 0) { |
| 10 | SECTION_ROOT(R.string.advanced_settings), | 11 | SECTION_ROOT(R.string.advanced_settings), |
| 11 | SECTION_SYSTEM(R.string.preferences_system), | 12 | SECTION_SYSTEM(R.string.preferences_system), |
| 12 | SECTION_RENDERER(R.string.preferences_graphics), | 13 | SECTION_RENDERER(R.string.preferences_graphics), |
| 13 | SECTION_AUDIO(R.string.preferences_audio), | 14 | SECTION_AUDIO(R.string.preferences_audio), |
| 15 | SECTION_INPUT(R.string.preferences_controls), | ||
| 16 | SECTION_INPUT_PLAYER_ONE, | ||
| 17 | SECTION_INPUT_PLAYER_TWO, | ||
| 18 | SECTION_INPUT_PLAYER_THREE, | ||
| 19 | SECTION_INPUT_PLAYER_FOUR, | ||
| 20 | SECTION_INPUT_PLAYER_FIVE, | ||
| 21 | SECTION_INPUT_PLAYER_SIX, | ||
| 22 | SECTION_INPUT_PLAYER_SEVEN, | ||
| 23 | SECTION_INPUT_PLAYER_EIGHT, | ||
| 14 | SECTION_THEME(R.string.preferences_theme), | 24 | SECTION_THEME(R.string.preferences_theme), |
| 15 | SECTION_DEBUG(R.string.preferences_debug); | 25 | SECTION_DEBUG(R.string.preferences_debug); |
| 16 | } | 26 | } |
| 17 | 27 | ||
| 28 | fun getPlayerString(player: Int): String = | ||
| 29 | YuzuApplication.appContext.getString(R.string.preferences_player, player) | ||
| 30 | |||
| 18 | const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch" | 31 | const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch" |
| 19 | const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown" | 32 | const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown" |
| 20 | 33 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/AnalogInputSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/AnalogInputSetting.kt new file mode 100644 index 000000000..a2996725e --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/AnalogInputSetting.kt | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model.view | ||
| 5 | |||
| 6 | import androidx.annotation.StringRes | ||
| 7 | import org.yuzu.yuzu_emu.features.input.NativeInput | ||
| 8 | import org.yuzu.yuzu_emu.features.input.model.AnalogDirection | ||
| 9 | import org.yuzu.yuzu_emu.features.input.model.InputType | ||
| 10 | import org.yuzu.yuzu_emu.features.input.model.NativeAnalog | ||
| 11 | import org.yuzu.yuzu_emu.utils.ParamPackage | ||
| 12 | |||
| 13 | class AnalogInputSetting( | ||
| 14 | override val playerIndex: Int, | ||
| 15 | val nativeAnalog: NativeAnalog, | ||
| 16 | val analogDirection: AnalogDirection, | ||
| 17 | @StringRes titleId: Int = 0, | ||
| 18 | titleString: String = "" | ||
| 19 | ) : InputSetting(titleId, titleString) { | ||
| 20 | override val type = TYPE_INPUT | ||
| 21 | override val inputType = InputType.Stick | ||
| 22 | |||
| 23 | override fun getSelectedValue(): String { | ||
| 24 | val params = NativeInput.getStickParam(playerIndex, nativeAnalog) | ||
| 25 | val analog = analogToText(params, analogDirection.param) | ||
| 26 | return getDisplayString(params, analog) | ||
| 27 | } | ||
| 28 | |||
| 29 | override fun setSelectedValue(param: ParamPackage) = | ||
| 30 | NativeInput.setStickParam(playerIndex, nativeAnalog, param) | ||
| 31 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/ButtonInputSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/ButtonInputSetting.kt new file mode 100644 index 000000000..786d09a7a --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/ButtonInputSetting.kt | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model.view | ||
| 5 | |||
| 6 | import androidx.annotation.StringRes | ||
| 7 | import org.yuzu.yuzu_emu.utils.ParamPackage | ||
| 8 | import org.yuzu.yuzu_emu.features.input.NativeInput | ||
| 9 | import org.yuzu.yuzu_emu.features.input.model.InputType | ||
| 10 | import org.yuzu.yuzu_emu.features.input.model.NativeButton | ||
| 11 | |||
| 12 | class ButtonInputSetting( | ||
| 13 | override val playerIndex: Int, | ||
| 14 | val nativeButton: NativeButton, | ||
| 15 | @StringRes titleId: Int = 0, | ||
| 16 | titleString: String = "" | ||
| 17 | ) : InputSetting(titleId, titleString) { | ||
| 18 | override val type = TYPE_INPUT | ||
| 19 | override val inputType = InputType.Button | ||
| 20 | |||
| 21 | override fun getSelectedValue(): String { | ||
| 22 | val params = NativeInput.getButtonParam(playerIndex, nativeButton) | ||
| 23 | val button = buttonToText(params) | ||
| 24 | return getDisplayString(params, button) | ||
| 25 | } | ||
| 26 | |||
| 27 | override fun setSelectedValue(param: ParamPackage) = | ||
| 28 | NativeInput.setButtonParam(playerIndex, nativeButton, param) | ||
| 29 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/DateTimeSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/DateTimeSetting.kt index 1d81f5f2b..58febff1d 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/DateTimeSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/DateTimeSetting.kt | |||
| @@ -3,13 +3,16 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.model.view | 4 | package org.yuzu.yuzu_emu.features.settings.model.view |
| 5 | 5 | ||
| 6 | import androidx.annotation.StringRes | ||
| 6 | import org.yuzu.yuzu_emu.features.settings.model.AbstractLongSetting | 7 | import org.yuzu.yuzu_emu.features.settings.model.AbstractLongSetting |
| 7 | 8 | ||
| 8 | class DateTimeSetting( | 9 | class DateTimeSetting( |
| 9 | private val longSetting: AbstractLongSetting, | 10 | private val longSetting: AbstractLongSetting, |
| 10 | titleId: Int, | 11 | @StringRes titleId: Int = 0, |
| 11 | descriptionId: Int | 12 | titleString: String = "", |
| 12 | ) : SettingsItem(longSetting, titleId, descriptionId) { | 13 | @StringRes descriptionId: Int = 0, |
| 14 | descriptionString: String = "" | ||
| 15 | ) : SettingsItem(longSetting, titleId, titleString, descriptionId, descriptionString) { | ||
| 13 | override val type = TYPE_DATETIME_SETTING | 16 | override val type = TYPE_DATETIME_SETTING |
| 14 | 17 | ||
| 15 | fun getValue(needsGlobal: Boolean = false): Long = longSetting.getLong(needsGlobal) | 18 | fun getValue(needsGlobal: Boolean = false): Long = longSetting.getLong(needsGlobal) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/HeaderSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/HeaderSetting.kt index d31ce1c31..8a6a51d5c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/HeaderSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/HeaderSetting.kt | |||
| @@ -3,8 +3,11 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.model.view | 4 | package org.yuzu.yuzu_emu.features.settings.model.view |
| 5 | 5 | ||
| 6 | import androidx.annotation.StringRes | ||
| 7 | |||
| 6 | class HeaderSetting( | 8 | class HeaderSetting( |
| 7 | titleId: Int | 9 | @StringRes titleId: Int = 0, |
| 8 | ) : SettingsItem(emptySetting, titleId, 0) { | 10 | titleString: String = "" |
| 11 | ) : SettingsItem(emptySetting, titleId, titleString, 0, "") { | ||
| 9 | override val type = TYPE_HEADER | 12 | override val type = TYPE_HEADER |
| 10 | } | 13 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/InputProfileSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/InputProfileSetting.kt new file mode 100644 index 000000000..c46de08c5 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/InputProfileSetting.kt | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model.view | ||
| 5 | |||
| 6 | import org.yuzu.yuzu_emu.R | ||
| 7 | import org.yuzu.yuzu_emu.features.input.NativeInput | ||
| 8 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 9 | |||
| 10 | class InputProfileSetting(private val playerIndex: Int) : | ||
| 11 | SettingsItem(emptySetting, R.string.profile, "", 0, "") { | ||
| 12 | override val type = TYPE_INPUT_PROFILE | ||
| 13 | |||
| 14 | fun getCurrentProfile(): String = | ||
| 15 | NativeConfig.getInputSettings(true)[playerIndex].profileName | ||
| 16 | |||
| 17 | fun getProfileNames(): Array<String> = NativeInput.getInputProfileNames() | ||
| 18 | |||
| 19 | fun isProfileNameValid(name: String): Boolean = NativeInput.isProfileNameValid(name) | ||
| 20 | |||
| 21 | fun createProfile(name: String): Boolean = NativeInput.createProfile(name, playerIndex) | ||
| 22 | |||
| 23 | fun deleteProfile(name: String): Boolean = NativeInput.deleteProfile(name, playerIndex) | ||
| 24 | |||
| 25 | fun loadProfile(name: String): Boolean { | ||
| 26 | val result = NativeInput.loadProfile(name, playerIndex) | ||
| 27 | NativeInput.reloadInputDevices() | ||
| 28 | return result | ||
| 29 | } | ||
| 30 | |||
| 31 | fun saveProfile(name: String): Boolean = NativeInput.saveProfile(name, playerIndex) | ||
| 32 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/InputSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/InputSetting.kt new file mode 100644 index 000000000..2d118bff3 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/InputSetting.kt | |||
| @@ -0,0 +1,134 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model.view | ||
| 5 | |||
| 6 | import androidx.annotation.StringRes | ||
| 7 | import org.yuzu.yuzu_emu.R | ||
| 8 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 9 | import org.yuzu.yuzu_emu.features.input.NativeInput | ||
| 10 | import org.yuzu.yuzu_emu.features.input.model.ButtonName | ||
| 11 | import org.yuzu.yuzu_emu.features.input.model.InputType | ||
| 12 | import org.yuzu.yuzu_emu.utils.ParamPackage | ||
| 13 | |||
| 14 | sealed class InputSetting( | ||
| 15 | @StringRes titleId: Int, | ||
| 16 | titleString: String | ||
| 17 | ) : SettingsItem(emptySetting, titleId, titleString, 0, "") { | ||
| 18 | override val type = TYPE_INPUT | ||
| 19 | abstract val inputType: InputType | ||
| 20 | abstract val playerIndex: Int | ||
| 21 | |||
| 22 | protected val context get() = YuzuApplication.appContext | ||
| 23 | |||
| 24 | abstract fun getSelectedValue(): String | ||
| 25 | |||
| 26 | abstract fun setSelectedValue(param: ParamPackage) | ||
| 27 | |||
| 28 | protected fun getDisplayString(params: ParamPackage, control: String): String { | ||
| 29 | val deviceName = params.get("display", "") | ||
| 30 | deviceName.ifEmpty { | ||
| 31 | return context.getString(R.string.not_set) | ||
| 32 | } | ||
| 33 | return "$deviceName: $control" | ||
| 34 | } | ||
| 35 | |||
| 36 | private fun getDirectionName(direction: String): String = | ||
| 37 | when (direction) { | ||
| 38 | "up" -> context.getString(R.string.up) | ||
| 39 | "down" -> context.getString(R.string.down) | ||
| 40 | "left" -> context.getString(R.string.left) | ||
| 41 | "right" -> context.getString(R.string.right) | ||
| 42 | else -> direction | ||
| 43 | } | ||
| 44 | |||
| 45 | protected fun buttonToText(param: ParamPackage): String { | ||
| 46 | if (!param.has("engine")) { | ||
| 47 | return context.getString(R.string.not_set) | ||
| 48 | } | ||
| 49 | |||
| 50 | val toggle = if (param.get("toggle", false)) "~" else "" | ||
| 51 | val inverted = if (param.get("inverted", false)) "!" else "" | ||
| 52 | val invert = if (param.get("invert", "+") == "-") "-" else "" | ||
| 53 | val turbo = if (param.get("turbo", false)) "$" else "" | ||
| 54 | val commonButtonName = NativeInput.getButtonName(param) | ||
| 55 | |||
| 56 | if (commonButtonName == ButtonName.Invalid) { | ||
| 57 | return context.getString(R.string.invalid) | ||
| 58 | } | ||
| 59 | |||
| 60 | if (commonButtonName == ButtonName.Engine) { | ||
| 61 | return param.get("engine", "") | ||
| 62 | } | ||
| 63 | |||
| 64 | if (commonButtonName == ButtonName.Value) { | ||
| 65 | if (param.has("hat")) { | ||
| 66 | val hat = getDirectionName(param.get("direction", "")) | ||
| 67 | return context.getString(R.string.qualified_hat, turbo, toggle, inverted, hat) | ||
| 68 | } | ||
| 69 | if (param.has("axis")) { | ||
| 70 | val axis = param.get("axis", "") | ||
| 71 | return context.getString( | ||
| 72 | R.string.qualified_button_stick_axis, | ||
| 73 | toggle, | ||
| 74 | inverted, | ||
| 75 | invert, | ||
| 76 | axis | ||
| 77 | ) | ||
| 78 | } | ||
| 79 | if (param.has("button")) { | ||
| 80 | val button = param.get("button", "") | ||
| 81 | return context.getString(R.string.qualified_button, turbo, toggle, inverted, button) | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | return context.getString(R.string.unknown) | ||
| 86 | } | ||
| 87 | |||
| 88 | protected fun analogToText(param: ParamPackage, direction: String): String { | ||
| 89 | if (!param.has("engine")) { | ||
| 90 | return context.getString(R.string.not_set) | ||
| 91 | } | ||
| 92 | |||
| 93 | if (param.get("engine", "") == "analog_from_button") { | ||
| 94 | return buttonToText(ParamPackage(param.get(direction, ""))) | ||
| 95 | } | ||
| 96 | |||
| 97 | if (!param.has("axis_x") || !param.has("axis_y")) { | ||
| 98 | return context.getString(R.string.unknown) | ||
| 99 | } | ||
| 100 | |||
| 101 | val xAxis = param.get("axis_x", "") | ||
| 102 | val yAxis = param.get("axis_y", "") | ||
| 103 | val xInvert = param.get("invert_x", "+") == "-" | ||
| 104 | val yInvert = param.get("invert_y", "+") == "-" | ||
| 105 | |||
| 106 | if (direction == "modifier") { | ||
| 107 | return context.getString(R.string.unused) | ||
| 108 | } | ||
| 109 | |||
| 110 | when (direction) { | ||
| 111 | "up" -> { | ||
| 112 | val yInvertString = if (yInvert) "+" else "-" | ||
| 113 | return context.getString(R.string.qualified_axis, yAxis, yInvertString) | ||
| 114 | } | ||
| 115 | |||
| 116 | "down" -> { | ||
| 117 | val yInvertString = if (yInvert) "-" else "+" | ||
| 118 | return context.getString(R.string.qualified_axis, yAxis, yInvertString) | ||
| 119 | } | ||
| 120 | |||
| 121 | "left" -> { | ||
| 122 | val xInvertString = if (xInvert) "+" else "-" | ||
| 123 | return context.getString(R.string.qualified_axis, xAxis, xInvertString) | ||
| 124 | } | ||
| 125 | |||
| 126 | "right" -> { | ||
| 127 | val xInvertString = if (xInvert) "-" else "+" | ||
| 128 | return context.getString(R.string.qualified_axis, xAxis, xInvertString) | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | return context.getString(R.string.unknown) | ||
| 133 | } | ||
| 134 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/IntSingleChoiceSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/IntSingleChoiceSetting.kt new file mode 100644 index 000000000..e024c793a --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/IntSingleChoiceSetting.kt | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model.view | ||
| 5 | |||
| 6 | import androidx.annotation.StringRes | ||
| 7 | import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting | ||
| 8 | |||
| 9 | class IntSingleChoiceSetting( | ||
| 10 | private val intSetting: AbstractIntSetting, | ||
| 11 | @StringRes titleId: Int = 0, | ||
| 12 | titleString: String = "", | ||
| 13 | @StringRes descriptionId: Int = 0, | ||
| 14 | descriptionString: String = "", | ||
| 15 | val choices: Array<String>, | ||
| 16 | val values: Array<Int> | ||
| 17 | ) : SettingsItem(intSetting, titleId, titleString, descriptionId, descriptionString) { | ||
| 18 | override val type = TYPE_INT_SINGLE_CHOICE | ||
| 19 | |||
| 20 | fun getValueAt(index: Int): Int = | ||
| 21 | if (values.indices.contains(index)) values[index] else -1 | ||
| 22 | |||
| 23 | fun getChoiceAt(index: Int): String = | ||
| 24 | if (choices.indices.contains(index)) choices[index] else "" | ||
| 25 | |||
| 26 | fun getSelectedValue(needsGlobal: Boolean = false) = intSetting.getInt(needsGlobal) | ||
| 27 | fun setSelectedValue(value: Int) = intSetting.setInt(value) | ||
| 28 | |||
| 29 | val selectedValueIndex: Int | ||
| 30 | get() { | ||
| 31 | for (i in values.indices) { | ||
| 32 | if (values[i] == getSelectedValue()) { | ||
| 33 | return i | ||
| 34 | } | ||
| 35 | } | ||
| 36 | return -1 | ||
| 37 | } | ||
| 38 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/ModifierInputSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/ModifierInputSetting.kt new file mode 100644 index 000000000..a1db3cc87 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/ModifierInputSetting.kt | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model.view | ||
| 5 | |||
| 6 | import androidx.annotation.StringRes | ||
| 7 | import org.yuzu.yuzu_emu.features.input.NativeInput | ||
| 8 | import org.yuzu.yuzu_emu.features.input.model.InputType | ||
| 9 | import org.yuzu.yuzu_emu.features.input.model.NativeAnalog | ||
| 10 | import org.yuzu.yuzu_emu.utils.ParamPackage | ||
| 11 | |||
| 12 | class ModifierInputSetting( | ||
| 13 | override val playerIndex: Int, | ||
| 14 | val nativeAnalog: NativeAnalog, | ||
| 15 | @StringRes titleId: Int = 0, | ||
| 16 | titleString: String = "" | ||
| 17 | ) : InputSetting(titleId, titleString) { | ||
| 18 | override val inputType = InputType.Button | ||
| 19 | |||
| 20 | override fun getSelectedValue(): String { | ||
| 21 | val analogParam = NativeInput.getStickParam(playerIndex, nativeAnalog) | ||
| 22 | val modifierParam = ParamPackage(analogParam.get("modifier", "")) | ||
| 23 | return buttonToText(modifierParam) | ||
| 24 | } | ||
| 25 | |||
| 26 | override fun setSelectedValue(param: ParamPackage) { | ||
| 27 | val newParam = NativeInput.getStickParam(playerIndex, nativeAnalog) | ||
| 28 | newParam.set("modifier", param.serialize()) | ||
| 29 | NativeInput.setStickParam(playerIndex, nativeAnalog, newParam) | ||
| 30 | } | ||
| 31 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/RunnableSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/RunnableSetting.kt index 425160024..06f607424 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/RunnableSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/RunnableSetting.kt | |||
| @@ -4,13 +4,16 @@ | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model.view | 4 | package org.yuzu.yuzu_emu.features.settings.model.view |
| 5 | 5 | ||
| 6 | import androidx.annotation.DrawableRes | 6 | import androidx.annotation.DrawableRes |
| 7 | import androidx.annotation.StringRes | ||
| 7 | 8 | ||
| 8 | class RunnableSetting( | 9 | class RunnableSetting( |
| 9 | titleId: Int, | 10 | @StringRes titleId: Int = 0, |
| 10 | descriptionId: Int, | 11 | titleString: String = "", |
| 11 | val isRuntimeRunnable: Boolean, | 12 | @StringRes descriptionId: Int = 0, |
| 13 | descriptionString: String = "", | ||
| 14 | val isRunnable: Boolean, | ||
| 12 | @DrawableRes val iconId: Int = 0, | 15 | @DrawableRes val iconId: Int = 0, |
| 13 | val runnable: () -> Unit | 16 | val runnable: () -> Unit |
| 14 | ) : SettingsItem(emptySetting, titleId, descriptionId) { | 17 | ) : SettingsItem(emptySetting, titleId, titleString, descriptionId, descriptionString) { |
| 15 | override val type = TYPE_RUNNABLE | 18 | override val type = TYPE_RUNNABLE |
| 16 | } | 19 | } |
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 21ca97bc1..8f724835e 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 | |||
| @@ -3,8 +3,12 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.model.view | 4 | package org.yuzu.yuzu_emu.features.settings.model.view |
| 5 | 5 | ||
| 6 | import androidx.annotation.StringRes | ||
| 6 | import org.yuzu.yuzu_emu.NativeLibrary | 7 | import org.yuzu.yuzu_emu.NativeLibrary |
| 7 | import org.yuzu.yuzu_emu.R | 8 | import org.yuzu.yuzu_emu.R |
| 9 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 10 | import org.yuzu.yuzu_emu.features.input.NativeInput | ||
| 11 | import org.yuzu.yuzu_emu.features.input.model.NpadStyleIndex | ||
| 8 | import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting | 12 | import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting |
| 9 | import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting | 13 | import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting |
| 10 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting | 14 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting |
| @@ -23,13 +27,34 @@ import org.yuzu.yuzu_emu.utils.NativeConfig | |||
| 23 | */ | 27 | */ |
| 24 | abstract class SettingsItem( | 28 | abstract class SettingsItem( |
| 25 | val setting: AbstractSetting, | 29 | val setting: AbstractSetting, |
| 26 | val nameId: Int, | 30 | @StringRes val titleId: Int, |
| 27 | val descriptionId: Int | 31 | val titleString: String, |
| 32 | @StringRes val descriptionId: Int, | ||
| 33 | val descriptionString: String | ||
| 28 | ) { | 34 | ) { |
| 29 | abstract val type: Int | 35 | abstract val type: Int |
| 30 | 36 | ||
| 37 | val title: String by lazy { | ||
| 38 | if (titleId != 0) { | ||
| 39 | return@lazy YuzuApplication.appContext.getString(titleId) | ||
| 40 | } | ||
| 41 | return@lazy titleString | ||
| 42 | } | ||
| 43 | |||
| 44 | val description: String by lazy { | ||
| 45 | if (descriptionId != 0) { | ||
| 46 | return@lazy YuzuApplication.appContext.getString(descriptionId) | ||
| 47 | } | ||
| 48 | return@lazy descriptionString | ||
| 49 | } | ||
| 50 | |||
| 31 | val isEditable: Boolean | 51 | val isEditable: Boolean |
| 32 | get() { | 52 | get() { |
| 53 | // Can't change docked mode toggle when using handheld mode | ||
| 54 | if (setting.key == BooleanSetting.USE_DOCKED_MODE.key) { | ||
| 55 | return NativeInput.getStyleIndex(0) != NpadStyleIndex.Handheld | ||
| 56 | } | ||
| 57 | |||
| 33 | // Can't edit settings that aren't saveable in per-game config even if they are switchable | 58 | // Can't edit settings that aren't saveable in per-game config even if they are switchable |
| 34 | if (NativeConfig.isPerGameConfigLoaded() && !setting.isSaveable) { | 59 | if (NativeConfig.isPerGameConfigLoaded() && !setting.isSaveable) { |
| 35 | return false | 60 | return false |
| @@ -59,6 +84,9 @@ abstract class SettingsItem( | |||
| 59 | const val TYPE_STRING_SINGLE_CHOICE = 5 | 84 | const val TYPE_STRING_SINGLE_CHOICE = 5 |
| 60 | const val TYPE_DATETIME_SETTING = 6 | 85 | const val TYPE_DATETIME_SETTING = 6 |
| 61 | const val TYPE_RUNNABLE = 7 | 86 | const val TYPE_RUNNABLE = 7 |
| 87 | const val TYPE_INPUT = 8 | ||
| 88 | const val TYPE_INT_SINGLE_CHOICE = 9 | ||
| 89 | const val TYPE_INPUT_PROFILE = 10 | ||
| 62 | 90 | ||
| 63 | const val FASTMEM_COMBINED = "fastmem_combined" | 91 | const val FASTMEM_COMBINED = "fastmem_combined" |
| 64 | 92 | ||
| @@ -80,237 +108,242 @@ abstract class SettingsItem( | |||
| 80 | put( | 108 | put( |
| 81 | SwitchSetting( | 109 | SwitchSetting( |
| 82 | BooleanSetting.RENDERER_USE_SPEED_LIMIT, | 110 | BooleanSetting.RENDERER_USE_SPEED_LIMIT, |
| 83 | R.string.frame_limit_enable, | 111 | titleId = R.string.frame_limit_enable, |
| 84 | R.string.frame_limit_enable_description | 112 | descriptionId = R.string.frame_limit_enable_description |
| 85 | ) | 113 | ) |
| 86 | ) | 114 | ) |
| 87 | put( | 115 | put( |
| 88 | SliderSetting( | 116 | SliderSetting( |
| 89 | ShortSetting.RENDERER_SPEED_LIMIT, | 117 | ShortSetting.RENDERER_SPEED_LIMIT, |
| 90 | R.string.frame_limit_slider, | 118 | titleId = R.string.frame_limit_slider, |
| 91 | R.string.frame_limit_slider_description, | 119 | descriptionId = R.string.frame_limit_slider_description, |
| 92 | 1, | 120 | min = 1, |
| 93 | 400, | 121 | max = 400, |
| 94 | "%" | 122 | units = "%" |
| 95 | ) | 123 | ) |
| 96 | ) | 124 | ) |
| 97 | put( | 125 | put( |
| 98 | SingleChoiceSetting( | 126 | SingleChoiceSetting( |
| 99 | IntSetting.CPU_BACKEND, | 127 | IntSetting.CPU_BACKEND, |
| 100 | R.string.cpu_backend, | 128 | titleId = R.string.cpu_backend, |
| 101 | 0, | 129 | choicesId = R.array.cpuBackendArm64Names, |
| 102 | R.array.cpuBackendArm64Names, | 130 | valuesId = R.array.cpuBackendArm64Values |
| 103 | R.array.cpuBackendArm64Values | ||
| 104 | ) | 131 | ) |
| 105 | ) | 132 | ) |
| 106 | put( | 133 | put( |
| 107 | SingleChoiceSetting( | 134 | SingleChoiceSetting( |
| 108 | IntSetting.CPU_ACCURACY, | 135 | IntSetting.CPU_ACCURACY, |
| 109 | R.string.cpu_accuracy, | 136 | titleId = R.string.cpu_accuracy, |
| 110 | 0, | 137 | choicesId = R.array.cpuAccuracyNames, |
| 111 | R.array.cpuAccuracyNames, | 138 | valuesId = R.array.cpuAccuracyValues |
| 112 | R.array.cpuAccuracyValues | ||
| 113 | ) | 139 | ) |
| 114 | ) | 140 | ) |
| 115 | put( | 141 | put( |
| 116 | SwitchSetting( | 142 | SwitchSetting( |
| 117 | BooleanSetting.PICTURE_IN_PICTURE, | 143 | BooleanSetting.PICTURE_IN_PICTURE, |
| 118 | R.string.picture_in_picture, | 144 | titleId = R.string.picture_in_picture, |
| 119 | R.string.picture_in_picture_description | 145 | descriptionId = R.string.picture_in_picture_description |
| 120 | ) | 146 | ) |
| 121 | ) | 147 | ) |
| 148 | |||
| 149 | val dockedModeSetting = object : AbstractBooleanSetting { | ||
| 150 | override val key = BooleanSetting.USE_DOCKED_MODE.key | ||
| 151 | |||
| 152 | override fun getBoolean(needsGlobal: Boolean): Boolean { | ||
| 153 | if (NativeInput.getStyleIndex(0) == NpadStyleIndex.Handheld) { | ||
| 154 | return false | ||
| 155 | } | ||
| 156 | return BooleanSetting.USE_DOCKED_MODE.getBoolean(needsGlobal) | ||
| 157 | } | ||
| 158 | |||
| 159 | override fun setBoolean(value: Boolean) = | ||
| 160 | BooleanSetting.USE_DOCKED_MODE.setBoolean(value) | ||
| 161 | |||
| 162 | override val defaultValue = BooleanSetting.USE_DOCKED_MODE.defaultValue | ||
| 163 | |||
| 164 | override fun getValueAsString(needsGlobal: Boolean): String = | ||
| 165 | BooleanSetting.USE_DOCKED_MODE.getValueAsString(needsGlobal) | ||
| 166 | |||
| 167 | override fun reset() = BooleanSetting.USE_DOCKED_MODE.reset() | ||
| 168 | } | ||
| 122 | put( | 169 | put( |
| 123 | SwitchSetting( | 170 | SwitchSetting( |
| 124 | BooleanSetting.USE_DOCKED_MODE, | 171 | dockedModeSetting, |
| 125 | R.string.use_docked_mode, | 172 | titleId = R.string.use_docked_mode, |
| 126 | R.string.use_docked_mode_description | 173 | descriptionId = R.string.use_docked_mode_description |
| 127 | ) | 174 | ) |
| 128 | ) | 175 | ) |
| 176 | |||
| 129 | put( | 177 | put( |
| 130 | SingleChoiceSetting( | 178 | SingleChoiceSetting( |
| 131 | IntSetting.REGION_INDEX, | 179 | IntSetting.REGION_INDEX, |
| 132 | R.string.emulated_region, | 180 | titleId = R.string.emulated_region, |
| 133 | 0, | 181 | choicesId = R.array.regionNames, |
| 134 | R.array.regionNames, | 182 | valuesId = R.array.regionValues |
| 135 | R.array.regionValues | ||
| 136 | ) | 183 | ) |
| 137 | ) | 184 | ) |
| 138 | put( | 185 | put( |
| 139 | SingleChoiceSetting( | 186 | SingleChoiceSetting( |
| 140 | IntSetting.LANGUAGE_INDEX, | 187 | IntSetting.LANGUAGE_INDEX, |
| 141 | R.string.emulated_language, | 188 | titleId = R.string.emulated_language, |
| 142 | 0, | 189 | choicesId = R.array.languageNames, |
| 143 | R.array.languageNames, | 190 | valuesId = R.array.languageValues |
| 144 | R.array.languageValues | ||
| 145 | ) | 191 | ) |
| 146 | ) | 192 | ) |
| 147 | put( | 193 | put( |
| 148 | SwitchSetting( | 194 | SwitchSetting( |
| 149 | BooleanSetting.USE_CUSTOM_RTC, | 195 | BooleanSetting.USE_CUSTOM_RTC, |
| 150 | R.string.use_custom_rtc, | 196 | titleId = R.string.use_custom_rtc, |
| 151 | R.string.use_custom_rtc_description | 197 | descriptionId = R.string.use_custom_rtc_description |
| 152 | ) | 198 | ) |
| 153 | ) | 199 | ) |
| 154 | put(DateTimeSetting(LongSetting.CUSTOM_RTC, R.string.set_custom_rtc, 0)) | 200 | put(DateTimeSetting(LongSetting.CUSTOM_RTC, titleId = R.string.set_custom_rtc)) |
| 155 | put( | 201 | put( |
| 156 | SingleChoiceSetting( | 202 | SingleChoiceSetting( |
| 157 | IntSetting.RENDERER_ACCURACY, | 203 | IntSetting.RENDERER_ACCURACY, |
| 158 | R.string.renderer_accuracy, | 204 | titleId = R.string.renderer_accuracy, |
| 159 | 0, | 205 | choicesId = R.array.rendererAccuracyNames, |
| 160 | R.array.rendererAccuracyNames, | 206 | valuesId = R.array.rendererAccuracyValues |
| 161 | R.array.rendererAccuracyValues | ||
| 162 | ) | 207 | ) |
| 163 | ) | 208 | ) |
| 164 | put( | 209 | put( |
| 165 | SingleChoiceSetting( | 210 | SingleChoiceSetting( |
| 166 | IntSetting.RENDERER_RESOLUTION, | 211 | IntSetting.RENDERER_RESOLUTION, |
| 167 | R.string.renderer_resolution, | 212 | titleId = R.string.renderer_resolution, |
| 168 | 0, | 213 | choicesId = R.array.rendererResolutionNames, |
| 169 | R.array.rendererResolutionNames, | 214 | valuesId = R.array.rendererResolutionValues |
| 170 | R.array.rendererResolutionValues | ||
| 171 | ) | 215 | ) |
| 172 | ) | 216 | ) |
| 173 | put( | 217 | put( |
| 174 | SingleChoiceSetting( | 218 | SingleChoiceSetting( |
| 175 | IntSetting.RENDERER_VSYNC, | 219 | IntSetting.RENDERER_VSYNC, |
| 176 | R.string.renderer_vsync, | 220 | titleId = R.string.renderer_vsync, |
| 177 | 0, | 221 | choicesId = R.array.rendererVSyncNames, |
| 178 | R.array.rendererVSyncNames, | 222 | valuesId = R.array.rendererVSyncValues |
| 179 | R.array.rendererVSyncValues | ||
| 180 | ) | 223 | ) |
| 181 | ) | 224 | ) |
| 182 | put( | 225 | put( |
| 183 | SingleChoiceSetting( | 226 | SingleChoiceSetting( |
| 184 | IntSetting.RENDERER_SCALING_FILTER, | 227 | IntSetting.RENDERER_SCALING_FILTER, |
| 185 | R.string.renderer_scaling_filter, | 228 | titleId = R.string.renderer_scaling_filter, |
| 186 | 0, | 229 | choicesId = R.array.rendererScalingFilterNames, |
| 187 | R.array.rendererScalingFilterNames, | 230 | valuesId = R.array.rendererScalingFilterValues |
| 188 | R.array.rendererScalingFilterValues | ||
| 189 | ) | 231 | ) |
| 190 | ) | 232 | ) |
| 191 | put( | 233 | put( |
| 192 | SliderSetting( | 234 | SliderSetting( |
| 193 | IntSetting.FSR_SHARPENING_SLIDER, | 235 | IntSetting.FSR_SHARPENING_SLIDER, |
| 194 | R.string.fsr_sharpness, | 236 | titleId = R.string.fsr_sharpness, |
| 195 | R.string.fsr_sharpness_description, | 237 | descriptionId = R.string.fsr_sharpness_description, |
| 196 | 0, | 238 | units = "%" |
| 197 | 100, | ||
| 198 | "%" | ||
| 199 | ) | 239 | ) |
| 200 | ) | 240 | ) |
| 201 | put( | 241 | put( |
| 202 | SingleChoiceSetting( | 242 | SingleChoiceSetting( |
| 203 | IntSetting.RENDERER_ANTI_ALIASING, | 243 | IntSetting.RENDERER_ANTI_ALIASING, |
| 204 | R.string.renderer_anti_aliasing, | 244 | titleId = R.string.renderer_anti_aliasing, |
| 205 | 0, | 245 | choicesId = R.array.rendererAntiAliasingNames, |
| 206 | R.array.rendererAntiAliasingNames, | 246 | valuesId = R.array.rendererAntiAliasingValues |
| 207 | R.array.rendererAntiAliasingValues | ||
| 208 | ) | 247 | ) |
| 209 | ) | 248 | ) |
| 210 | put( | 249 | put( |
| 211 | SingleChoiceSetting( | 250 | SingleChoiceSetting( |
| 212 | IntSetting.RENDERER_SCREEN_LAYOUT, | 251 | IntSetting.RENDERER_SCREEN_LAYOUT, |
| 213 | R.string.renderer_screen_layout, | 252 | titleId = R.string.renderer_screen_layout, |
| 214 | 0, | 253 | choicesId = R.array.rendererScreenLayoutNames, |
| 215 | R.array.rendererScreenLayoutNames, | 254 | valuesId = R.array.rendererScreenLayoutValues |
| 216 | R.array.rendererScreenLayoutValues | ||
| 217 | ) | 255 | ) |
| 218 | ) | 256 | ) |
| 219 | put( | 257 | put( |
| 220 | SingleChoiceSetting( | 258 | SingleChoiceSetting( |
| 221 | IntSetting.RENDERER_ASPECT_RATIO, | 259 | IntSetting.RENDERER_ASPECT_RATIO, |
| 222 | R.string.renderer_aspect_ratio, | 260 | titleId = R.string.renderer_aspect_ratio, |
| 223 | 0, | 261 | choicesId = R.array.rendererAspectRatioNames, |
| 224 | R.array.rendererAspectRatioNames, | 262 | valuesId = R.array.rendererAspectRatioValues |
| 225 | R.array.rendererAspectRatioValues | ||
| 226 | ) | 263 | ) |
| 227 | ) | 264 | ) |
| 228 | put( | 265 | put( |
| 229 | SingleChoiceSetting( | 266 | SingleChoiceSetting( |
| 230 | IntSetting.VERTICAL_ALIGNMENT, | 267 | IntSetting.VERTICAL_ALIGNMENT, |
| 231 | R.string.vertical_alignment, | 268 | titleId = R.string.vertical_alignment, |
| 232 | 0, | 269 | descriptionId = 0, |
| 233 | R.array.verticalAlignmentEntries, | 270 | choicesId = R.array.verticalAlignmentEntries, |
| 234 | R.array.verticalAlignmentValues | 271 | valuesId = R.array.verticalAlignmentValues |
| 235 | ) | 272 | ) |
| 236 | ) | 273 | ) |
| 237 | put( | 274 | put( |
| 238 | SwitchSetting( | 275 | SwitchSetting( |
| 239 | BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE, | 276 | BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE, |
| 240 | R.string.use_disk_shader_cache, | 277 | titleId = R.string.use_disk_shader_cache, |
| 241 | R.string.use_disk_shader_cache_description | 278 | descriptionId = R.string.use_disk_shader_cache_description |
| 242 | ) | 279 | ) |
| 243 | ) | 280 | ) |
| 244 | put( | 281 | put( |
| 245 | SwitchSetting( | 282 | SwitchSetting( |
| 246 | BooleanSetting.RENDERER_FORCE_MAX_CLOCK, | 283 | BooleanSetting.RENDERER_FORCE_MAX_CLOCK, |
| 247 | R.string.renderer_force_max_clock, | 284 | titleId = R.string.renderer_force_max_clock, |
| 248 | R.string.renderer_force_max_clock_description | 285 | descriptionId = R.string.renderer_force_max_clock_description |
| 249 | ) | 286 | ) |
| 250 | ) | 287 | ) |
| 251 | put( | 288 | put( |
| 252 | SwitchSetting( | 289 | SwitchSetting( |
| 253 | BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS, | 290 | BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS, |
| 254 | R.string.renderer_asynchronous_shaders, | 291 | titleId = R.string.renderer_asynchronous_shaders, |
| 255 | R.string.renderer_asynchronous_shaders_description | 292 | descriptionId = R.string.renderer_asynchronous_shaders_description |
| 256 | ) | 293 | ) |
| 257 | ) | 294 | ) |
| 258 | put( | 295 | put( |
| 259 | SwitchSetting( | 296 | SwitchSetting( |
| 260 | BooleanSetting.RENDERER_REACTIVE_FLUSHING, | 297 | BooleanSetting.RENDERER_REACTIVE_FLUSHING, |
| 261 | R.string.renderer_reactive_flushing, | 298 | titleId = R.string.renderer_reactive_flushing, |
| 262 | R.string.renderer_reactive_flushing_description | 299 | descriptionId = R.string.renderer_reactive_flushing_description |
| 263 | ) | 300 | ) |
| 264 | ) | 301 | ) |
| 265 | put( | 302 | put( |
| 266 | SingleChoiceSetting( | 303 | SingleChoiceSetting( |
| 267 | IntSetting.MAX_ANISOTROPY, | 304 | IntSetting.MAX_ANISOTROPY, |
| 268 | R.string.anisotropic_filtering, | 305 | titleId = R.string.anisotropic_filtering, |
| 269 | R.string.anisotropic_filtering_description, | 306 | descriptionId = R.string.anisotropic_filtering_description, |
| 270 | R.array.anisoEntries, | 307 | choicesId = R.array.anisoEntries, |
| 271 | R.array.anisoValues | 308 | valuesId = R.array.anisoValues |
| 272 | ) | 309 | ) |
| 273 | ) | 310 | ) |
| 274 | put( | 311 | put( |
| 275 | SingleChoiceSetting( | 312 | SingleChoiceSetting( |
| 276 | IntSetting.AUDIO_OUTPUT_ENGINE, | 313 | IntSetting.AUDIO_OUTPUT_ENGINE, |
| 277 | R.string.audio_output_engine, | 314 | titleId = R.string.audio_output_engine, |
| 278 | 0, | 315 | choicesId = R.array.outputEngineEntries, |
| 279 | R.array.outputEngineEntries, | 316 | valuesId = R.array.outputEngineValues |
| 280 | R.array.outputEngineValues | ||
| 281 | ) | 317 | ) |
| 282 | ) | 318 | ) |
| 283 | put( | 319 | put( |
| 284 | SliderSetting( | 320 | SliderSetting( |
| 285 | ByteSetting.AUDIO_VOLUME, | 321 | ByteSetting.AUDIO_VOLUME, |
| 286 | R.string.audio_volume, | 322 | titleId = R.string.audio_volume, |
| 287 | R.string.audio_volume_description, | 323 | descriptionId = R.string.audio_volume_description, |
| 288 | 0, | 324 | units = "%" |
| 289 | 100, | ||
| 290 | "%" | ||
| 291 | ) | 325 | ) |
| 292 | ) | 326 | ) |
| 293 | put( | 327 | put( |
| 294 | SingleChoiceSetting( | 328 | SingleChoiceSetting( |
| 295 | IntSetting.RENDERER_BACKEND, | 329 | IntSetting.RENDERER_BACKEND, |
| 296 | R.string.renderer_api, | 330 | titleId = R.string.renderer_api, |
| 297 | 0, | 331 | choicesId = R.array.rendererApiNames, |
| 298 | R.array.rendererApiNames, | 332 | valuesId = R.array.rendererApiValues |
| 299 | R.array.rendererApiValues | ||
| 300 | ) | 333 | ) |
| 301 | ) | 334 | ) |
| 302 | put( | 335 | put( |
| 303 | SwitchSetting( | 336 | SwitchSetting( |
| 304 | BooleanSetting.RENDERER_DEBUG, | 337 | BooleanSetting.RENDERER_DEBUG, |
| 305 | R.string.renderer_debug, | 338 | titleId = R.string.renderer_debug, |
| 306 | R.string.renderer_debug_description | 339 | descriptionId = R.string.renderer_debug_description |
| 307 | ) | 340 | ) |
| 308 | ) | 341 | ) |
| 309 | put( | 342 | put( |
| 310 | SwitchSetting( | 343 | SwitchSetting( |
| 311 | BooleanSetting.CPU_DEBUG_MODE, | 344 | BooleanSetting.CPU_DEBUG_MODE, |
| 312 | R.string.cpu_debug_mode, | 345 | titleId = R.string.cpu_debug_mode, |
| 313 | R.string.cpu_debug_mode_description | 346 | descriptionId = R.string.cpu_debug_mode_description |
| 314 | ) | 347 | ) |
| 315 | ) | 348 | ) |
| 316 | 349 | ||
| @@ -346,7 +379,7 @@ abstract class SettingsItem( | |||
| 346 | 379 | ||
| 347 | override fun reset() = setBoolean(defaultValue) | 380 | override fun reset() = setBoolean(defaultValue) |
| 348 | } | 381 | } |
| 349 | put(SwitchSetting(fastmem, R.string.fastmem, 0)) | 382 | put(SwitchSetting(fastmem, R.string.fastmem)) |
| 350 | } | 383 | } |
| 351 | } | 384 | } |
| 352 | } | 385 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt index 97a5a9e59..ea5e099ed 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt | |||
| @@ -3,16 +3,20 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.model.view | 4 | package org.yuzu.yuzu_emu.features.settings.model.view |
| 5 | 5 | ||
| 6 | import androidx.annotation.ArrayRes | ||
| 7 | import androidx.annotation.StringRes | ||
| 6 | import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting | 8 | import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting |
| 7 | import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting | 9 | import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting |
| 8 | 10 | ||
| 9 | class SingleChoiceSetting( | 11 | class SingleChoiceSetting( |
| 10 | setting: AbstractSetting, | 12 | setting: AbstractSetting, |
| 11 | titleId: Int, | 13 | @StringRes titleId: Int = 0, |
| 12 | descriptionId: Int, | 14 | titleString: String = "", |
| 13 | val choicesId: Int, | 15 | @StringRes descriptionId: Int = 0, |
| 14 | val valuesId: Int | 16 | descriptionString: String = "", |
| 15 | ) : SettingsItem(setting, titleId, descriptionId) { | 17 | @ArrayRes val choicesId: Int, |
| 18 | @ArrayRes val valuesId: Int | ||
| 19 | ) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) { | ||
| 16 | override val type = TYPE_SINGLE_CHOICE | 20 | override val type = TYPE_SINGLE_CHOICE |
| 17 | 21 | ||
| 18 | fun getSelectedValue(needsGlobal: Boolean = false) = | 22 | fun getSelectedValue(needsGlobal: Boolean = false) = |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt index b9b709bf7..6a5cdf48b 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.model.view | 4 | package org.yuzu.yuzu_emu.features.settings.model.view |
| 5 | 5 | ||
| 6 | import androidx.annotation.StringRes | ||
| 6 | import org.yuzu.yuzu_emu.features.settings.model.AbstractByteSetting | 7 | import org.yuzu.yuzu_emu.features.settings.model.AbstractByteSetting |
| 7 | import org.yuzu.yuzu_emu.features.settings.model.AbstractFloatSetting | 8 | import org.yuzu.yuzu_emu.features.settings.model.AbstractFloatSetting |
| 8 | import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting | 9 | import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting |
| @@ -12,12 +13,14 @@ import kotlin.math.roundToInt | |||
| 12 | 13 | ||
| 13 | class SliderSetting( | 14 | class SliderSetting( |
| 14 | setting: AbstractSetting, | 15 | setting: AbstractSetting, |
| 15 | titleId: Int, | 16 | @StringRes titleId: Int = 0, |
| 16 | descriptionId: Int, | 17 | titleString: String = "", |
| 17 | val min: Int, | 18 | @StringRes descriptionId: Int = 0, |
| 18 | val max: Int, | 19 | descriptionString: String = "", |
| 19 | val units: String | 20 | val min: Int = 0, |
| 20 | ) : SettingsItem(setting, titleId, descriptionId) { | 21 | val max: Int = 100, |
| 22 | val units: String = "" | ||
| 23 | ) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) { | ||
| 21 | override val type = TYPE_SLIDER | 24 | override val type = TYPE_SLIDER |
| 22 | 25 | ||
| 23 | fun getSelectedValue(needsGlobal: Boolean = false) = | 26 | fun getSelectedValue(needsGlobal: Boolean = false) = |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt index ba7920f50..5260ff4dc 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt | |||
| @@ -3,15 +3,18 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.model.view | 4 | package org.yuzu.yuzu_emu.features.settings.model.view |
| 5 | 5 | ||
| 6 | import androidx.annotation.StringRes | ||
| 6 | import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting | 7 | import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting |
| 7 | 8 | ||
| 8 | class StringSingleChoiceSetting( | 9 | class StringSingleChoiceSetting( |
| 9 | private val stringSetting: AbstractStringSetting, | 10 | private val stringSetting: AbstractStringSetting, |
| 10 | titleId: Int, | 11 | @StringRes titleId: Int = 0, |
| 11 | descriptionId: Int, | 12 | titleString: String = "", |
| 13 | @StringRes descriptionId: Int = 0, | ||
| 14 | descriptionString: String = "", | ||
| 12 | val choices: Array<String>, | 15 | val choices: Array<String>, |
| 13 | val values: Array<String> | 16 | val values: Array<String> |
| 14 | ) : SettingsItem(stringSetting, titleId, descriptionId) { | 17 | ) : SettingsItem(stringSetting, titleId, titleString, descriptionId, descriptionString) { |
| 15 | override val type = TYPE_STRING_SINGLE_CHOICE | 18 | override val type = TYPE_STRING_SINGLE_CHOICE |
| 16 | 19 | ||
| 17 | fun getValueAt(index: Int): String = | 20 | fun getValueAt(index: Int): String = |
| @@ -20,7 +23,7 @@ class StringSingleChoiceSetting( | |||
| 20 | fun getSelectedValue(needsGlobal: Boolean = false) = stringSetting.getString(needsGlobal) | 23 | fun getSelectedValue(needsGlobal: Boolean = false) = stringSetting.getString(needsGlobal) |
| 21 | fun setSelectedValue(value: String) = stringSetting.setString(value) | 24 | fun setSelectedValue(value: String) = stringSetting.setString(value) |
| 22 | 25 | ||
| 23 | val selectValueIndex: Int | 26 | val selectedValueIndex: Int |
| 24 | get() { | 27 | get() { |
| 25 | for (i in values.indices) { | 28 | for (i in values.indices) { |
| 26 | if (values[i] == getSelectedValue()) { | 29 | if (values[i] == getSelectedValue()) { |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt index 94953b18a..c722393dd 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt | |||
| @@ -8,10 +8,12 @@ import androidx.annotation.StringRes | |||
| 8 | import org.yuzu.yuzu_emu.features.settings.model.Settings | 8 | import org.yuzu.yuzu_emu.features.settings.model.Settings |
| 9 | 9 | ||
| 10 | class SubmenuSetting( | 10 | class SubmenuSetting( |
| 11 | @StringRes titleId: Int, | 11 | @StringRes titleId: Int = 0, |
| 12 | @StringRes descriptionId: Int, | 12 | titleString: String = "", |
| 13 | @DrawableRes val iconId: Int, | 13 | @StringRes descriptionId: Int = 0, |
| 14 | descriptionString: String = "", | ||
| 15 | @DrawableRes val iconId: Int = 0, | ||
| 14 | val menuKey: Settings.MenuTag | 16 | val menuKey: Settings.MenuTag |
| 15 | ) : SettingsItem(emptySetting, titleId, descriptionId) { | 17 | ) : SettingsItem(emptySetting, titleId, titleString, descriptionId, descriptionString) { |
| 16 | override val type = TYPE_SUBMENU | 18 | override val type = TYPE_SUBMENU |
| 17 | } | 19 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SwitchSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SwitchSetting.kt index 44d47dd69..4984bf52e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SwitchSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SwitchSetting.kt | |||
| @@ -3,15 +3,18 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.model.view | 4 | package org.yuzu.yuzu_emu.features.settings.model.view |
| 5 | 5 | ||
| 6 | import androidx.annotation.StringRes | ||
| 6 | import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting | 7 | import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting |
| 7 | import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting | 8 | import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting |
| 8 | import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting | 9 | import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting |
| 9 | 10 | ||
| 10 | class SwitchSetting( | 11 | class SwitchSetting( |
| 11 | setting: AbstractSetting, | 12 | setting: AbstractSetting, |
| 12 | titleId: Int, | 13 | @StringRes titleId: Int = 0, |
| 13 | descriptionId: Int | 14 | titleString: String = "", |
| 14 | ) : SettingsItem(setting, titleId, descriptionId) { | 15 | @StringRes descriptionId: Int = 0, |
| 16 | descriptionString: String = "" | ||
| 17 | ) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) { | ||
| 15 | override val type = TYPE_SWITCH | 18 | override val type = TYPE_SWITCH |
| 16 | 19 | ||
| 17 | fun getIsChecked(needsGlobal: Boolean = false): Boolean { | 20 | fun getIsChecked(needsGlobal: Boolean = false): Boolean { |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/InputDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/InputDialogFragment.kt new file mode 100644 index 000000000..16a1d0504 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/InputDialogFragment.kt | |||
| @@ -0,0 +1,300 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.ui | ||
| 5 | |||
| 6 | import android.app.Dialog | ||
| 7 | import android.graphics.drawable.Animatable2 | ||
| 8 | import android.graphics.drawable.AnimatedVectorDrawable | ||
| 9 | import android.graphics.drawable.Drawable | ||
| 10 | import android.os.Bundle | ||
| 11 | import android.view.InputDevice | ||
| 12 | import android.view.KeyEvent | ||
| 13 | import android.view.LayoutInflater | ||
| 14 | import android.view.MotionEvent | ||
| 15 | import android.view.View | ||
| 16 | import android.view.ViewGroup | ||
| 17 | import androidx.fragment.app.DialogFragment | ||
| 18 | import androidx.fragment.app.activityViewModels | ||
| 19 | import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||
| 20 | import org.yuzu.yuzu_emu.R | ||
| 21 | import org.yuzu.yuzu_emu.databinding.DialogMappingBinding | ||
| 22 | import org.yuzu.yuzu_emu.features.input.NativeInput | ||
| 23 | import org.yuzu.yuzu_emu.features.input.model.NativeAnalog | ||
| 24 | import org.yuzu.yuzu_emu.features.input.model.NativeButton | ||
| 25 | import org.yuzu.yuzu_emu.features.settings.model.view.AnalogInputSetting | ||
| 26 | import org.yuzu.yuzu_emu.features.settings.model.view.ButtonInputSetting | ||
| 27 | import org.yuzu.yuzu_emu.features.settings.model.view.InputSetting | ||
| 28 | import org.yuzu.yuzu_emu.features.settings.model.view.ModifierInputSetting | ||
| 29 | import org.yuzu.yuzu_emu.utils.InputHandler | ||
| 30 | import org.yuzu.yuzu_emu.utils.ParamPackage | ||
| 31 | |||
| 32 | class InputDialogFragment : DialogFragment() { | ||
| 33 | private var inputAccepted = false | ||
| 34 | |||
| 35 | private var position: Int = 0 | ||
| 36 | |||
| 37 | private lateinit var inputSetting: InputSetting | ||
| 38 | |||
| 39 | private lateinit var binding: DialogMappingBinding | ||
| 40 | |||
| 41 | private val settingsViewModel: SettingsViewModel by activityViewModels() | ||
| 42 | |||
| 43 | override fun onCreate(savedInstanceState: Bundle?) { | ||
| 44 | super.onCreate(savedInstanceState) | ||
| 45 | if (settingsViewModel.clickedItem == null) dismiss() | ||
| 46 | |||
| 47 | position = requireArguments().getInt(POSITION) | ||
| 48 | |||
| 49 | InputHandler.updateControllerData() | ||
| 50 | } | ||
| 51 | |||
| 52 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { | ||
| 53 | inputSetting = settingsViewModel.clickedItem as InputSetting | ||
| 54 | binding = DialogMappingBinding.inflate(layoutInflater) | ||
| 55 | |||
| 56 | val builder = MaterialAlertDialogBuilder(requireContext()) | ||
| 57 | .setPositiveButton(android.R.string.cancel) { _, _ -> | ||
| 58 | NativeInput.stopMapping() | ||
| 59 | dismiss() | ||
| 60 | } | ||
| 61 | .setView(binding.root) | ||
| 62 | |||
| 63 | val playButtonMapAnimation = { twoDirections: Boolean -> | ||
| 64 | val stickAnimation: AnimatedVectorDrawable | ||
| 65 | val buttonAnimation: AnimatedVectorDrawable | ||
| 66 | binding.imageStickAnimation.apply { | ||
| 67 | val anim = if (twoDirections) { | ||
| 68 | R.drawable.stick_two_direction_anim | ||
| 69 | } else { | ||
| 70 | R.drawable.stick_one_direction_anim | ||
| 71 | } | ||
| 72 | setBackgroundResource(anim) | ||
| 73 | stickAnimation = background as AnimatedVectorDrawable | ||
| 74 | } | ||
| 75 | binding.imageButtonAnimation.apply { | ||
| 76 | setBackgroundResource(R.drawable.button_anim) | ||
| 77 | buttonAnimation = background as AnimatedVectorDrawable | ||
| 78 | } | ||
| 79 | stickAnimation.registerAnimationCallback(object : Animatable2.AnimationCallback() { | ||
| 80 | override fun onAnimationEnd(drawable: Drawable?) { | ||
| 81 | buttonAnimation.start() | ||
| 82 | } | ||
| 83 | }) | ||
| 84 | buttonAnimation.registerAnimationCallback(object : Animatable2.AnimationCallback() { | ||
| 85 | override fun onAnimationEnd(drawable: Drawable?) { | ||
| 86 | stickAnimation.start() | ||
| 87 | } | ||
| 88 | }) | ||
| 89 | stickAnimation.start() | ||
| 90 | } | ||
| 91 | |||
| 92 | when (val setting = inputSetting) { | ||
| 93 | is AnalogInputSetting -> { | ||
| 94 | when (setting.nativeAnalog) { | ||
| 95 | NativeAnalog.LStick -> builder.setTitle( | ||
| 96 | getString(R.string.map_control, getString(R.string.left_stick)) | ||
| 97 | ) | ||
| 98 | |||
| 99 | NativeAnalog.RStick -> builder.setTitle( | ||
| 100 | getString(R.string.map_control, getString(R.string.right_stick)) | ||
| 101 | ) | ||
| 102 | } | ||
| 103 | |||
| 104 | builder.setMessage(R.string.stick_map_description) | ||
| 105 | |||
| 106 | playButtonMapAnimation.invoke(true) | ||
| 107 | } | ||
| 108 | |||
| 109 | is ModifierInputSetting -> { | ||
| 110 | builder.setTitle(getString(R.string.map_control, setting.title)) | ||
| 111 | .setMessage(R.string.button_map_description) | ||
| 112 | playButtonMapAnimation.invoke(false) | ||
| 113 | } | ||
| 114 | |||
| 115 | is ButtonInputSetting -> { | ||
| 116 | if (setting.nativeButton == NativeButton.DUp || | ||
| 117 | setting.nativeButton == NativeButton.DDown || | ||
| 118 | setting.nativeButton == NativeButton.DLeft || | ||
| 119 | setting.nativeButton == NativeButton.DRight | ||
| 120 | ) { | ||
| 121 | builder.setTitle(getString(R.string.map_dpad_direction, setting.title)) | ||
| 122 | } else { | ||
| 123 | builder.setTitle(getString(R.string.map_control, setting.title)) | ||
| 124 | } | ||
| 125 | builder.setMessage(R.string.button_map_description) | ||
| 126 | playButtonMapAnimation.invoke(false) | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | return builder.create() | ||
| 131 | } | ||
| 132 | |||
| 133 | override fun onCreateView( | ||
| 134 | inflater: LayoutInflater, | ||
| 135 | container: ViewGroup?, | ||
| 136 | savedInstanceState: Bundle? | ||
| 137 | ): View { | ||
| 138 | return binding.root | ||
| 139 | } | ||
| 140 | |||
| 141 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | ||
| 142 | super.onViewCreated(view, savedInstanceState) | ||
| 143 | view.requestFocus() | ||
| 144 | view.setOnFocusChangeListener { v, hasFocus -> if (!hasFocus) v.requestFocus() } | ||
| 145 | dialog?.setOnKeyListener { _, _, keyEvent -> onKeyEvent(keyEvent) } | ||
| 146 | binding.root.setOnGenericMotionListener { _, motionEvent -> onMotionEvent(motionEvent) } | ||
| 147 | NativeInput.beginMapping(inputSetting.inputType.int) | ||
| 148 | } | ||
| 149 | |||
| 150 | private fun onKeyEvent(event: KeyEvent): Boolean { | ||
| 151 | if (event.source and InputDevice.SOURCE_JOYSTICK != InputDevice.SOURCE_JOYSTICK && | ||
| 152 | event.source and InputDevice.SOURCE_GAMEPAD != InputDevice.SOURCE_GAMEPAD | ||
| 153 | ) { | ||
| 154 | return false | ||
| 155 | } | ||
| 156 | |||
| 157 | val action = when (event.action) { | ||
| 158 | KeyEvent.ACTION_DOWN -> NativeInput.ButtonState.PRESSED | ||
| 159 | KeyEvent.ACTION_UP -> NativeInput.ButtonState.RELEASED | ||
| 160 | else -> return false | ||
| 161 | } | ||
| 162 | val controllerData = | ||
| 163 | InputHandler.androidControllers[event.device.controllerNumber] ?: return false | ||
| 164 | NativeInput.onGamePadButtonEvent( | ||
| 165 | controllerData.getGUID(), | ||
| 166 | controllerData.getPort(), | ||
| 167 | event.keyCode, | ||
| 168 | action | ||
| 169 | ) | ||
| 170 | onInputReceived(event.device) | ||
| 171 | return true | ||
| 172 | } | ||
| 173 | |||
| 174 | private fun onMotionEvent(event: MotionEvent): Boolean { | ||
| 175 | if (event.source and InputDevice.SOURCE_JOYSTICK != InputDevice.SOURCE_JOYSTICK && | ||
| 176 | event.source and InputDevice.SOURCE_GAMEPAD != InputDevice.SOURCE_GAMEPAD | ||
| 177 | ) { | ||
| 178 | return false | ||
| 179 | } | ||
| 180 | |||
| 181 | // Temp workaround for DPads that give both axis and button input. The input system can't | ||
| 182 | // take in a specific axis direction for a binding so you lose half of the directions for a DPad. | ||
| 183 | |||
| 184 | val controllerData = | ||
| 185 | InputHandler.androidControllers[event.device.controllerNumber] ?: return false | ||
| 186 | event.device.motionRanges.forEach { | ||
| 187 | NativeInput.onGamePadAxisEvent( | ||
| 188 | controllerData.getGUID(), | ||
| 189 | controllerData.getPort(), | ||
| 190 | it.axis, | ||
| 191 | event.getAxisValue(it.axis) | ||
| 192 | ) | ||
| 193 | onInputReceived(event.device) | ||
| 194 | } | ||
| 195 | return true | ||
| 196 | } | ||
| 197 | |||
| 198 | private fun onInputReceived(device: InputDevice) { | ||
| 199 | val params = ParamPackage(NativeInput.getNextInput()) | ||
| 200 | if (params.has("engine") && isInputAcceptable(params) && !inputAccepted) { | ||
| 201 | inputAccepted = true | ||
| 202 | setResult(params, device) | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | private fun setResult(params: ParamPackage, device: InputDevice) { | ||
| 207 | NativeInput.stopMapping() | ||
| 208 | params.set("display", "${device.name} ${params.get("port", 0)}") | ||
| 209 | when (val item = settingsViewModel.clickedItem as InputSetting) { | ||
| 210 | is ModifierInputSetting, | ||
| 211 | is ButtonInputSetting -> { | ||
| 212 | // Invert DPad up and left bindings by default | ||
| 213 | val tempSetting = inputSetting as? ButtonInputSetting | ||
| 214 | if (tempSetting != null) { | ||
| 215 | if (tempSetting.nativeButton == NativeButton.DUp || | ||
| 216 | tempSetting.nativeButton == NativeButton.DLeft && | ||
| 217 | params.has("axis") | ||
| 218 | ) { | ||
| 219 | params.set("invert", "-") | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | item.setSelectedValue(params) | ||
| 224 | settingsViewModel.setAdapterItemChanged(position) | ||
| 225 | } | ||
| 226 | |||
| 227 | is AnalogInputSetting -> { | ||
| 228 | var analogParam = NativeInput.getStickParam(item.playerIndex, item.nativeAnalog) | ||
| 229 | analogParam = adjustAnalogParam(params, analogParam, item.analogDirection.param) | ||
| 230 | |||
| 231 | // Invert Y-Axis by default | ||
| 232 | analogParam.set("invert_y", "-") | ||
| 233 | |||
| 234 | item.setSelectedValue(analogParam) | ||
| 235 | settingsViewModel.setReloadListAndNotifyDataset(true) | ||
| 236 | } | ||
| 237 | } | ||
| 238 | dismiss() | ||
| 239 | } | ||
| 240 | |||
| 241 | private fun adjustAnalogParam( | ||
| 242 | inputParam: ParamPackage, | ||
| 243 | analogParam: ParamPackage, | ||
| 244 | buttonName: String | ||
| 245 | ): ParamPackage { | ||
| 246 | // The poller returned a complete axis, so set all the buttons | ||
| 247 | if (inputParam.has("axis_x") && inputParam.has("axis_y")) { | ||
| 248 | return inputParam | ||
| 249 | } | ||
| 250 | |||
| 251 | // Check if the current configuration has either no engine or an axis binding. | ||
| 252 | // Clears out the old binding and adds one with analog_from_button. | ||
| 253 | if (!analogParam.has("engine") || analogParam.has("axis_x") || analogParam.has("axis_y")) { | ||
| 254 | analogParam.clear() | ||
| 255 | analogParam.set("engine", "analog_from_button") | ||
| 256 | } | ||
| 257 | analogParam.set(buttonName, inputParam.serialize()) | ||
| 258 | return analogParam | ||
| 259 | } | ||
| 260 | |||
| 261 | private fun isInputAcceptable(params: ParamPackage): Boolean { | ||
| 262 | if (InputHandler.registeredControllers.size == 1) { | ||
| 263 | return true | ||
| 264 | } | ||
| 265 | |||
| 266 | if (params.has("motion")) { | ||
| 267 | return true | ||
| 268 | } | ||
| 269 | |||
| 270 | val currentDevice = settingsViewModel.getCurrentDeviceParams(params) | ||
| 271 | if (currentDevice.get("engine", "any") == "any") { | ||
| 272 | return true | ||
| 273 | } | ||
| 274 | |||
| 275 | val guidMatch = params.get("guid", "") == currentDevice.get("guid", "") || | ||
| 276 | params.get("guid", "") == currentDevice.get("guid2", "") | ||
| 277 | return params.get("engine", "") == currentDevice.get("engine", "") && | ||
| 278 | guidMatch && | ||
| 279 | params.get("port", 0) == currentDevice.get("port", 0) | ||
| 280 | } | ||
| 281 | |||
| 282 | companion object { | ||
| 283 | const val TAG = "InputDialogFragment" | ||
| 284 | |||
| 285 | const val POSITION = "Position" | ||
| 286 | |||
| 287 | fun newInstance( | ||
| 288 | inputMappingViewModel: SettingsViewModel, | ||
| 289 | setting: InputSetting, | ||
| 290 | position: Int | ||
| 291 | ): InputDialogFragment { | ||
| 292 | inputMappingViewModel.clickedItem = setting | ||
| 293 | val args = Bundle() | ||
| 294 | args.putInt(POSITION, position) | ||
| 295 | val fragment = InputDialogFragment() | ||
| 296 | fragment.arguments = args | ||
| 297 | return fragment | ||
| 298 | } | ||
| 299 | } | ||
| 300 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/InputProfileAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/InputProfileAdapter.kt new file mode 100644 index 000000000..5656e9d8d --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/InputProfileAdapter.kt | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.ui | ||
| 5 | |||
| 6 | import android.view.LayoutInflater | ||
| 7 | import android.view.View | ||
| 8 | import android.view.ViewGroup | ||
| 9 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 10 | import org.yuzu.yuzu_emu.adapters.AbstractListAdapter | ||
| 11 | import org.yuzu.yuzu_emu.databinding.ListItemInputProfileBinding | ||
| 12 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | ||
| 13 | import org.yuzu.yuzu_emu.R | ||
| 14 | |||
| 15 | class InputProfileAdapter(options: List<ProfileItem>) : | ||
| 16 | AbstractListAdapter<ProfileItem, AbstractViewHolder<ProfileItem>>(options) { | ||
| 17 | override fun onCreateViewHolder( | ||
| 18 | parent: ViewGroup, | ||
| 19 | viewType: Int | ||
| 20 | ): AbstractViewHolder<ProfileItem> { | ||
| 21 | ListItemInputProfileBinding.inflate(LayoutInflater.from(parent.context), parent, false) | ||
| 22 | .also { return InputProfileViewHolder(it) } | ||
| 23 | } | ||
| 24 | |||
| 25 | inner class InputProfileViewHolder(val binding: ListItemInputProfileBinding) : | ||
| 26 | AbstractViewHolder<ProfileItem>(binding) { | ||
| 27 | override fun bind(model: ProfileItem) { | ||
| 28 | when (model) { | ||
| 29 | is ExistingProfileItem -> { | ||
| 30 | binding.title.text = model.name | ||
| 31 | binding.buttonNew.visibility = View.GONE | ||
| 32 | binding.buttonDelete.visibility = View.VISIBLE | ||
| 33 | binding.buttonDelete.setOnClickListener { model.deleteProfile.invoke() } | ||
| 34 | binding.buttonSave.visibility = View.VISIBLE | ||
| 35 | binding.buttonSave.setOnClickListener { model.saveProfile.invoke() } | ||
| 36 | binding.buttonLoad.visibility = View.VISIBLE | ||
| 37 | binding.buttonLoad.setOnClickListener { model.loadProfile.invoke() } | ||
| 38 | } | ||
| 39 | |||
| 40 | is NewProfileItem -> { | ||
| 41 | binding.title.text = model.name | ||
| 42 | binding.buttonNew.visibility = View.VISIBLE | ||
| 43 | binding.buttonNew.setOnClickListener { model.createNewProfile.invoke() } | ||
| 44 | binding.buttonSave.visibility = View.GONE | ||
| 45 | binding.buttonDelete.visibility = View.GONE | ||
| 46 | binding.buttonLoad.visibility = View.GONE | ||
| 47 | } | ||
| 48 | } | ||
| 49 | } | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | sealed interface ProfileItem { | ||
| 54 | val name: String | ||
| 55 | } | ||
| 56 | |||
| 57 | data class NewProfileItem( | ||
| 58 | val createNewProfile: () -> Unit | ||
| 59 | ) : ProfileItem { | ||
| 60 | override val name: String = YuzuApplication.appContext.getString(R.string.create_new_profile) | ||
| 61 | } | ||
| 62 | |||
| 63 | data class ExistingProfileItem( | ||
| 64 | override val name: String, | ||
| 65 | val deleteProfile: () -> Unit, | ||
| 66 | val saveProfile: () -> Unit, | ||
| 67 | val loadProfile: () -> Unit | ||
| 68 | ) : ProfileItem | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/InputProfileDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/InputProfileDialogFragment.kt new file mode 100644 index 000000000..1bae593ae --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/InputProfileDialogFragment.kt | |||
| @@ -0,0 +1,148 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.ui | ||
| 5 | |||
| 6 | import android.app.Dialog | ||
| 7 | import android.os.Bundle | ||
| 8 | import android.view.LayoutInflater | ||
| 9 | import android.view.View | ||
| 10 | import android.view.ViewGroup | ||
| 11 | import android.widget.Toast | ||
| 12 | import androidx.fragment.app.DialogFragment | ||
| 13 | import androidx.fragment.app.activityViewModels | ||
| 14 | import androidx.recyclerview.widget.LinearLayoutManager | ||
| 15 | import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||
| 16 | import org.yuzu.yuzu_emu.R | ||
| 17 | import org.yuzu.yuzu_emu.databinding.DialogInputProfilesBinding | ||
| 18 | import org.yuzu.yuzu_emu.features.settings.model.view.InputProfileSetting | ||
| 19 | import org.yuzu.yuzu_emu.fragments.MessageDialogFragment | ||
| 20 | import org.yuzu.yuzu_emu.utils.collect | ||
| 21 | |||
| 22 | class InputProfileDialogFragment : DialogFragment() { | ||
| 23 | private var position = 0 | ||
| 24 | |||
| 25 | private val settingsViewModel: SettingsViewModel by activityViewModels() | ||
| 26 | |||
| 27 | private lateinit var binding: DialogInputProfilesBinding | ||
| 28 | |||
| 29 | private lateinit var setting: InputProfileSetting | ||
| 30 | |||
| 31 | override fun onCreate(savedInstanceState: Bundle?) { | ||
| 32 | super.onCreate(savedInstanceState) | ||
| 33 | position = requireArguments().getInt(POSITION) | ||
| 34 | } | ||
| 35 | |||
| 36 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { | ||
| 37 | binding = DialogInputProfilesBinding.inflate(layoutInflater) | ||
| 38 | |||
| 39 | setting = settingsViewModel.clickedItem as InputProfileSetting | ||
| 40 | val options = mutableListOf<ProfileItem>().apply { | ||
| 41 | add( | ||
| 42 | NewProfileItem( | ||
| 43 | createNewProfile = { | ||
| 44 | NewInputProfileDialogFragment.newInstance( | ||
| 45 | settingsViewModel, | ||
| 46 | setting, | ||
| 47 | position | ||
| 48 | ).show(parentFragmentManager, NewInputProfileDialogFragment.TAG) | ||
| 49 | dismiss() | ||
| 50 | } | ||
| 51 | ) | ||
| 52 | ) | ||
| 53 | |||
| 54 | val onActionDismiss = { | ||
| 55 | settingsViewModel.setReloadListAndNotifyDataset(true) | ||
| 56 | dismiss() | ||
| 57 | } | ||
| 58 | setting.getProfileNames().forEach { | ||
| 59 | add( | ||
| 60 | ExistingProfileItem( | ||
| 61 | it, | ||
| 62 | deleteProfile = { | ||
| 63 | settingsViewModel.setShouldShowDeleteProfileDialog(it) | ||
| 64 | }, | ||
| 65 | saveProfile = { | ||
| 66 | if (!setting.saveProfile(it)) { | ||
| 67 | Toast.makeText( | ||
| 68 | requireContext(), | ||
| 69 | R.string.failed_to_save_profile, | ||
| 70 | Toast.LENGTH_SHORT | ||
| 71 | ).show() | ||
| 72 | } | ||
| 73 | onActionDismiss.invoke() | ||
| 74 | }, | ||
| 75 | loadProfile = { | ||
| 76 | if (!setting.loadProfile(it)) { | ||
| 77 | Toast.makeText( | ||
| 78 | requireContext(), | ||
| 79 | R.string.failed_to_load_profile, | ||
| 80 | Toast.LENGTH_SHORT | ||
| 81 | ).show() | ||
| 82 | } | ||
| 83 | onActionDismiss.invoke() | ||
| 84 | } | ||
| 85 | ) | ||
| 86 | ) | ||
| 87 | } | ||
| 88 | } | ||
| 89 | binding.listProfiles.apply { | ||
| 90 | layoutManager = LinearLayoutManager(requireContext()) | ||
| 91 | adapter = InputProfileAdapter(options) | ||
| 92 | } | ||
| 93 | |||
| 94 | return MaterialAlertDialogBuilder(requireContext()) | ||
| 95 | .setView(binding.root) | ||
| 96 | .create() | ||
| 97 | } | ||
| 98 | |||
| 99 | override fun onCreateView( | ||
| 100 | inflater: LayoutInflater, | ||
| 101 | container: ViewGroup?, | ||
| 102 | savedInstanceState: Bundle? | ||
| 103 | ): View { | ||
| 104 | return binding.root | ||
| 105 | } | ||
| 106 | |||
| 107 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | ||
| 108 | super.onViewCreated(view, savedInstanceState) | ||
| 109 | |||
| 110 | settingsViewModel.shouldShowDeleteProfileDialog.collect(viewLifecycleOwner) { | ||
| 111 | if (it.isNotEmpty()) { | ||
| 112 | MessageDialogFragment.newInstance( | ||
| 113 | activity = requireActivity(), | ||
| 114 | titleId = R.string.delete_input_profile, | ||
| 115 | descriptionId = R.string.delete_input_profile_description, | ||
| 116 | positiveAction = { | ||
| 117 | setting.deleteProfile(it) | ||
| 118 | settingsViewModel.setReloadListAndNotifyDataset(true) | ||
| 119 | }, | ||
| 120 | negativeAction = {}, | ||
| 121 | negativeButtonTitleId = android.R.string.cancel | ||
| 122 | ).show(parentFragmentManager, MessageDialogFragment.TAG) | ||
| 123 | settingsViewModel.setShouldShowDeleteProfileDialog("") | ||
| 124 | dismiss() | ||
| 125 | } | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | companion object { | ||
| 130 | const val TAG = "InputProfileDialogFragment" | ||
| 131 | |||
| 132 | const val POSITION = "Position" | ||
| 133 | |||
| 134 | fun newInstance( | ||
| 135 | settingsViewModel: SettingsViewModel, | ||
| 136 | profileSetting: InputProfileSetting, | ||
| 137 | position: Int | ||
| 138 | ): InputProfileDialogFragment { | ||
| 139 | settingsViewModel.clickedItem = profileSetting | ||
| 140 | |||
| 141 | val args = Bundle() | ||
| 142 | args.putInt(POSITION, position) | ||
| 143 | val fragment = InputProfileDialogFragment() | ||
| 144 | fragment.arguments = args | ||
| 145 | return fragment | ||
| 146 | } | ||
| 147 | } | ||
| 148 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/NewInputProfileDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/NewInputProfileDialogFragment.kt new file mode 100644 index 000000000..6e52bea80 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/NewInputProfileDialogFragment.kt | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.ui | ||
| 5 | |||
| 6 | import android.app.Dialog | ||
| 7 | import android.os.Bundle | ||
| 8 | import android.widget.Toast | ||
| 9 | import androidx.fragment.app.DialogFragment | ||
| 10 | import androidx.fragment.app.activityViewModels | ||
| 11 | import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||
| 12 | import org.yuzu.yuzu_emu.databinding.DialogEditTextBinding | ||
| 13 | import org.yuzu.yuzu_emu.features.settings.model.view.InputProfileSetting | ||
| 14 | import org.yuzu.yuzu_emu.R | ||
| 15 | |||
| 16 | class NewInputProfileDialogFragment : DialogFragment() { | ||
| 17 | private var position = 0 | ||
| 18 | |||
| 19 | private val settingsViewModel: SettingsViewModel by activityViewModels() | ||
| 20 | |||
| 21 | private lateinit var binding: DialogEditTextBinding | ||
| 22 | |||
| 23 | override fun onCreate(savedInstanceState: Bundle?) { | ||
| 24 | super.onCreate(savedInstanceState) | ||
| 25 | position = requireArguments().getInt(POSITION) | ||
| 26 | } | ||
| 27 | |||
| 28 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { | ||
| 29 | binding = DialogEditTextBinding.inflate(layoutInflater) | ||
| 30 | |||
| 31 | val setting = settingsViewModel.clickedItem as InputProfileSetting | ||
| 32 | return MaterialAlertDialogBuilder(requireContext()) | ||
| 33 | .setTitle(R.string.enter_profile_name) | ||
| 34 | .setPositiveButton(android.R.string.ok) { _, _ -> | ||
| 35 | val profileName = binding.editText.text.toString() | ||
| 36 | if (!setting.isProfileNameValid(profileName)) { | ||
| 37 | Toast.makeText( | ||
| 38 | requireContext(), | ||
| 39 | R.string.invalid_profile_name, | ||
| 40 | Toast.LENGTH_SHORT | ||
| 41 | ).show() | ||
| 42 | return@setPositiveButton | ||
| 43 | } | ||
| 44 | |||
| 45 | if (!setting.createProfile(profileName)) { | ||
| 46 | Toast.makeText( | ||
| 47 | requireContext(), | ||
| 48 | R.string.profile_name_already_exists, | ||
| 49 | Toast.LENGTH_SHORT | ||
| 50 | ).show() | ||
| 51 | } else { | ||
| 52 | settingsViewModel.setAdapterItemChanged(position) | ||
| 53 | } | ||
| 54 | } | ||
| 55 | .setNegativeButton(android.R.string.cancel, null) | ||
| 56 | .setView(binding.root) | ||
| 57 | .show() | ||
| 58 | } | ||
| 59 | |||
| 60 | companion object { | ||
| 61 | const val TAG = "NewInputProfileDialogFragment" | ||
| 62 | |||
| 63 | const val POSITION = "Position" | ||
| 64 | |||
| 65 | fun newInstance( | ||
| 66 | settingsViewModel: SettingsViewModel, | ||
| 67 | profileSetting: InputProfileSetting, | ||
| 68 | position: Int | ||
| 69 | ): NewInputProfileDialogFragment { | ||
| 70 | settingsViewModel.clickedItem = profileSetting | ||
| 71 | |||
| 72 | val args = Bundle() | ||
| 73 | args.putInt(POSITION, position) | ||
| 74 | val fragment = NewInputProfileDialogFragment() | ||
| 75 | fragment.arguments = args | ||
| 76 | return fragment | ||
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt index 6f072241a..455b3b5ff 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt | |||
| @@ -13,21 +13,16 @@ import androidx.appcompat.app.AppCompatActivity | |||
| 13 | import androidx.core.view.ViewCompat | 13 | import androidx.core.view.ViewCompat |
| 14 | import androidx.core.view.WindowCompat | 14 | import androidx.core.view.WindowCompat |
| 15 | import androidx.core.view.WindowInsetsCompat | 15 | import androidx.core.view.WindowInsetsCompat |
| 16 | import androidx.lifecycle.Lifecycle | ||
| 17 | import androidx.lifecycle.lifecycleScope | ||
| 18 | import androidx.lifecycle.repeatOnLifecycle | ||
| 19 | import androidx.navigation.fragment.NavHostFragment | 16 | import androidx.navigation.fragment.NavHostFragment |
| 20 | import androidx.navigation.navArgs | 17 | import androidx.navigation.navArgs |
| 21 | import com.google.android.material.color.MaterialColors | 18 | import com.google.android.material.color.MaterialColors |
| 22 | import kotlinx.coroutines.flow.collectLatest | ||
| 23 | import kotlinx.coroutines.launch | ||
| 24 | import org.yuzu.yuzu_emu.NativeLibrary | 19 | import org.yuzu.yuzu_emu.NativeLibrary |
| 25 | import java.io.IOException | 20 | import java.io.IOException |
| 26 | import org.yuzu.yuzu_emu.R | 21 | import org.yuzu.yuzu_emu.R |
| 27 | import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding | 22 | import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding |
| 23 | import org.yuzu.yuzu_emu.features.input.NativeInput | ||
| 28 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile | 24 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile |
| 29 | import org.yuzu.yuzu_emu.fragments.ResetSettingsDialogFragment | 25 | import org.yuzu.yuzu_emu.fragments.ResetSettingsDialogFragment |
| 30 | import org.yuzu.yuzu_emu.model.SettingsViewModel | ||
| 31 | import org.yuzu.yuzu_emu.utils.* | 26 | import org.yuzu.yuzu_emu.utils.* |
| 32 | 27 | ||
| 33 | class SettingsActivity : AppCompatActivity() { | 28 | class SettingsActivity : AppCompatActivity() { |
| @@ -70,39 +65,23 @@ class SettingsActivity : AppCompatActivity() { | |||
| 70 | ) | 65 | ) |
| 71 | } | 66 | } |
| 72 | 67 | ||
| 73 | lifecycleScope.apply { | 68 | settingsViewModel.shouldRecreate.collect( |
| 74 | launch { | 69 | this, |
| 75 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 70 | resetState = { settingsViewModel.setShouldRecreate(false) } |
| 76 | settingsViewModel.shouldRecreate.collectLatest { | 71 | ) { if (it) recreate() } |
| 77 | if (it) { | 72 | settingsViewModel.shouldNavigateBack.collect( |
| 78 | settingsViewModel.setShouldRecreate(false) | 73 | this, |
| 79 | recreate() | 74 | resetState = { settingsViewModel.setShouldNavigateBack(false) } |
| 80 | } | 75 | ) { if (it) navigateBack() } |
| 81 | } | 76 | settingsViewModel.shouldShowResetSettingsDialog.collect( |
| 82 | } | 77 | this, |
| 83 | } | 78 | resetState = { settingsViewModel.setShouldShowResetSettingsDialog(false) } |
| 84 | launch { | 79 | ) { |
| 85 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 80 | if (it) { |
| 86 | settingsViewModel.shouldNavigateBack.collectLatest { | 81 | ResetSettingsDialogFragment().show( |
| 87 | if (it) { | 82 | supportFragmentManager, |
| 88 | settingsViewModel.setShouldNavigateBack(false) | 83 | ResetSettingsDialogFragment.TAG |
| 89 | navigateBack() | 84 | ) |
| 90 | } | ||
| 91 | } | ||
| 92 | } | ||
| 93 | } | ||
| 94 | launch { | ||
| 95 | repeatOnLifecycle(Lifecycle.State.CREATED) { | ||
| 96 | settingsViewModel.shouldShowResetSettingsDialog.collectLatest { | ||
| 97 | if (it) { | ||
| 98 | settingsViewModel.setShouldShowResetSettingsDialog(false) | ||
| 99 | ResetSettingsDialogFragment().show( | ||
| 100 | supportFragmentManager, | ||
| 101 | ResetSettingsDialogFragment.TAG | ||
| 102 | ) | ||
| 103 | } | ||
| 104 | } | ||
| 105 | } | ||
| 106 | } | 85 | } |
| 107 | } | 86 | } |
| 108 | 87 | ||
| @@ -137,6 +116,7 @@ class SettingsActivity : AppCompatActivity() { | |||
| 137 | super.onStop() | 116 | super.onStop() |
| 138 | Log.info("[SettingsActivity] Settings activity stopping. Saving settings to INI...") | 117 | Log.info("[SettingsActivity] Settings activity stopping. Saving settings to INI...") |
| 139 | if (isFinishing) { | 118 | if (isFinishing) { |
| 119 | NativeInput.reloadInputDevices() | ||
| 140 | NativeLibrary.applySettings() | 120 | NativeLibrary.applySettings() |
| 141 | if (args.game == null) { | 121 | if (args.game == null) { |
| 142 | NativeConfig.saveGlobalConfig() | 122 | NativeConfig.saveGlobalConfig() |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt index be9b3031b..45c8faa10 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt | |||
| @@ -8,12 +8,11 @@ import android.icu.util.Calendar | |||
| 8 | import android.icu.util.TimeZone | 8 | import android.icu.util.TimeZone |
| 9 | import android.text.format.DateFormat | 9 | import android.text.format.DateFormat |
| 10 | import android.view.LayoutInflater | 10 | import android.view.LayoutInflater |
| 11 | import android.view.View | ||
| 11 | import android.view.ViewGroup | 12 | import android.view.ViewGroup |
| 13 | import android.widget.PopupMenu | ||
| 12 | import androidx.fragment.app.Fragment | 14 | import androidx.fragment.app.Fragment |
| 13 | import androidx.lifecycle.Lifecycle | ||
| 14 | import androidx.lifecycle.ViewModelProvider | 15 | import androidx.lifecycle.ViewModelProvider |
| 15 | import androidx.lifecycle.lifecycleScope | ||
| 16 | import androidx.lifecycle.repeatOnLifecycle | ||
| 17 | import androidx.navigation.findNavController | 16 | import androidx.navigation.findNavController |
| 18 | import androidx.recyclerview.widget.AsyncDifferConfig | 17 | import androidx.recyclerview.widget.AsyncDifferConfig |
| 19 | import androidx.recyclerview.widget.DiffUtil | 18 | import androidx.recyclerview.widget.DiffUtil |
| @@ -21,16 +20,18 @@ import androidx.recyclerview.widget.ListAdapter | |||
| 21 | import com.google.android.material.datepicker.MaterialDatePicker | 20 | import com.google.android.material.datepicker.MaterialDatePicker |
| 22 | import com.google.android.material.timepicker.MaterialTimePicker | 21 | import com.google.android.material.timepicker.MaterialTimePicker |
| 23 | import com.google.android.material.timepicker.TimeFormat | 22 | import com.google.android.material.timepicker.TimeFormat |
| 24 | import kotlinx.coroutines.launch | ||
| 25 | import org.yuzu.yuzu_emu.R | 23 | import org.yuzu.yuzu_emu.R |
| 26 | import org.yuzu.yuzu_emu.SettingsNavigationDirections | 24 | import org.yuzu.yuzu_emu.SettingsNavigationDirections |
| 27 | import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding | 25 | import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding |
| 26 | import org.yuzu.yuzu_emu.databinding.ListItemSettingInputBinding | ||
| 28 | import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding | 27 | import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding |
| 29 | import org.yuzu.yuzu_emu.databinding.ListItemSettingsHeaderBinding | 28 | import org.yuzu.yuzu_emu.databinding.ListItemSettingsHeaderBinding |
| 29 | import org.yuzu.yuzu_emu.features.input.NativeInput | ||
| 30 | import org.yuzu.yuzu_emu.features.input.model.AnalogDirection | ||
| 31 | import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting | ||
| 30 | import org.yuzu.yuzu_emu.features.settings.model.view.* | 32 | import org.yuzu.yuzu_emu.features.settings.model.view.* |
| 31 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.* | 33 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.* |
| 32 | import org.yuzu.yuzu_emu.fragments.SettingsDialogFragment | 34 | import org.yuzu.yuzu_emu.utils.ParamPackage |
| 33 | import org.yuzu.yuzu_emu.model.SettingsViewModel | ||
| 34 | 35 | ||
| 35 | class SettingsAdapter( | 36 | class SettingsAdapter( |
| 36 | private val fragment: Fragment, | 37 | private val fragment: Fragment, |
| @@ -41,19 +42,6 @@ class SettingsAdapter( | |||
| 41 | private val settingsViewModel: SettingsViewModel | 42 | private val settingsViewModel: SettingsViewModel |
| 42 | get() = ViewModelProvider(fragment.requireActivity())[SettingsViewModel::class.java] | 43 | get() = ViewModelProvider(fragment.requireActivity())[SettingsViewModel::class.java] |
| 43 | 44 | ||
| 44 | init { | ||
| 45 | fragment.viewLifecycleOwner.lifecycleScope.launch { | ||
| 46 | fragment.repeatOnLifecycle(Lifecycle.State.STARTED) { | ||
| 47 | settingsViewModel.adapterItemChanged.collect { | ||
| 48 | if (it != -1) { | ||
| 49 | notifyItemChanged(it) | ||
| 50 | settingsViewModel.setAdapterItemChanged(-1) | ||
| 51 | } | ||
| 52 | } | ||
| 53 | } | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SettingViewHolder { | 45 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SettingViewHolder { |
| 58 | val inflater = LayoutInflater.from(parent.context) | 46 | val inflater = LayoutInflater.from(parent.context) |
| 59 | return when (viewType) { | 47 | return when (viewType) { |
| @@ -85,8 +73,19 @@ class SettingsAdapter( | |||
| 85 | RunnableViewHolder(ListItemSettingBinding.inflate(inflater), this) | 73 | RunnableViewHolder(ListItemSettingBinding.inflate(inflater), this) |
| 86 | } | 74 | } |
| 87 | 75 | ||
| 76 | SettingsItem.TYPE_INPUT -> { | ||
| 77 | InputViewHolder(ListItemSettingInputBinding.inflate(inflater), this) | ||
| 78 | } | ||
| 79 | |||
| 80 | SettingsItem.TYPE_INT_SINGLE_CHOICE -> { | ||
| 81 | SingleChoiceViewHolder(ListItemSettingBinding.inflate(inflater), this) | ||
| 82 | } | ||
| 83 | |||
| 84 | SettingsItem.TYPE_INPUT_PROFILE -> { | ||
| 85 | InputProfileViewHolder(ListItemSettingBinding.inflate(inflater), this) | ||
| 86 | } | ||
| 87 | |||
| 88 | else -> { | 88 | else -> { |
| 89 | // TODO: Create an error view since we can't return null now | ||
| 90 | HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this) | 89 | HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this) |
| 91 | } | 90 | } |
| 92 | } | 91 | } |
| @@ -126,6 +125,15 @@ class SettingsAdapter( | |||
| 126 | ).show(fragment.childFragmentManager, SettingsDialogFragment.TAG) | 125 | ).show(fragment.childFragmentManager, SettingsDialogFragment.TAG) |
| 127 | } | 126 | } |
| 128 | 127 | ||
| 128 | fun onIntSingleChoiceClick(item: IntSingleChoiceSetting, position: Int) { | ||
| 129 | SettingsDialogFragment.newInstance( | ||
| 130 | settingsViewModel, | ||
| 131 | item, | ||
| 132 | SettingsItem.TYPE_INT_SINGLE_CHOICE, | ||
| 133 | position | ||
| 134 | ).show(fragment.childFragmentManager, SettingsDialogFragment.TAG) | ||
| 135 | } | ||
| 136 | |||
| 129 | fun onDateTimeClick(item: DateTimeSetting, position: Int) { | 137 | fun onDateTimeClick(item: DateTimeSetting, position: Int) { |
| 130 | val storedTime = item.getValue() * 1000 | 138 | val storedTime = item.getValue() * 1000 |
| 131 | 139 | ||
| @@ -185,6 +193,205 @@ class SettingsAdapter( | |||
| 185 | fragment.view?.findNavController()?.navigate(action) | 193 | fragment.view?.findNavController()?.navigate(action) |
| 186 | } | 194 | } |
| 187 | 195 | ||
| 196 | fun onInputProfileClick(item: InputProfileSetting, position: Int) { | ||
| 197 | InputProfileDialogFragment.newInstance( | ||
| 198 | settingsViewModel, | ||
| 199 | item, | ||
| 200 | position | ||
| 201 | ).show(fragment.childFragmentManager, InputProfileDialogFragment.TAG) | ||
| 202 | } | ||
| 203 | |||
| 204 | fun onInputClick(item: InputSetting, position: Int) { | ||
| 205 | InputDialogFragment.newInstance( | ||
| 206 | settingsViewModel, | ||
| 207 | item, | ||
| 208 | position | ||
| 209 | ).show(fragment.childFragmentManager, InputDialogFragment.TAG) | ||
| 210 | } | ||
| 211 | |||
| 212 | fun onInputOptionsClick(anchor: View, item: InputSetting, position: Int) { | ||
| 213 | val popup = PopupMenu(context, anchor) | ||
| 214 | popup.menuInflater.inflate(R.menu.menu_input_options, popup.menu) | ||
| 215 | |||
| 216 | popup.menu.apply { | ||
| 217 | val invertAxis = findItem(R.id.invert_axis) | ||
| 218 | val invertButton = findItem(R.id.invert_button) | ||
| 219 | val toggleButton = findItem(R.id.toggle_button) | ||
| 220 | val turboButton = findItem(R.id.turbo_button) | ||
| 221 | val setThreshold = findItem(R.id.set_threshold) | ||
| 222 | val toggleAxis = findItem(R.id.toggle_axis) | ||
| 223 | when (item) { | ||
| 224 | is AnalogInputSetting -> { | ||
| 225 | val params = NativeInput.getStickParam(item.playerIndex, item.nativeAnalog) | ||
| 226 | |||
| 227 | invertAxis.isVisible = true | ||
| 228 | invertAxis.isCheckable = true | ||
| 229 | invertAxis.isChecked = when (item.analogDirection) { | ||
| 230 | AnalogDirection.Left, AnalogDirection.Right -> { | ||
| 231 | params.get("invert_x", "+") == "-" | ||
| 232 | } | ||
| 233 | |||
| 234 | AnalogDirection.Up, AnalogDirection.Down -> { | ||
| 235 | params.get("invert_y", "+") == "-" | ||
| 236 | } | ||
| 237 | } | ||
| 238 | invertAxis.setOnMenuItemClickListener { | ||
| 239 | if (item.analogDirection == AnalogDirection.Left || | ||
| 240 | item.analogDirection == AnalogDirection.Right | ||
| 241 | ) { | ||
| 242 | val invertValue = params.get("invert_x", "+") == "-" | ||
| 243 | val invertString = if (invertValue) "+" else "-" | ||
| 244 | params.set("invert_x", invertString) | ||
| 245 | } else if ( | ||
| 246 | item.analogDirection == AnalogDirection.Up || | ||
| 247 | item.analogDirection == AnalogDirection.Down | ||
| 248 | ) { | ||
| 249 | val invertValue = params.get("invert_y", "+") == "-" | ||
| 250 | val invertString = if (invertValue) "+" else "-" | ||
| 251 | params.set("invert_y", invertString) | ||
| 252 | } | ||
| 253 | true | ||
| 254 | } | ||
| 255 | |||
| 256 | popup.setOnDismissListener { | ||
| 257 | NativeInput.setStickParam(item.playerIndex, item.nativeAnalog, params) | ||
| 258 | settingsViewModel.setDatasetChanged(true) | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | is ButtonInputSetting -> { | ||
| 263 | val params = NativeInput.getButtonParam(item.playerIndex, item.nativeButton) | ||
| 264 | if (params.has("code") || params.has("button") || params.has("hat")) { | ||
| 265 | val buttonInvert = params.get("inverted", false) | ||
| 266 | invertButton.isVisible = true | ||
| 267 | invertButton.isCheckable = true | ||
| 268 | invertButton.isChecked = buttonInvert | ||
| 269 | invertButton.setOnMenuItemClickListener { | ||
| 270 | params.set("inverted", !buttonInvert) | ||
| 271 | true | ||
| 272 | } | ||
| 273 | |||
| 274 | val toggle = params.get("toggle", false) | ||
| 275 | toggleButton.isVisible = true | ||
| 276 | toggleButton.isCheckable = true | ||
| 277 | toggleButton.isChecked = toggle | ||
| 278 | toggleButton.setOnMenuItemClickListener { | ||
| 279 | params.set("toggle", !toggle) | ||
| 280 | true | ||
| 281 | } | ||
| 282 | |||
| 283 | val turbo = params.get("turbo", false) | ||
| 284 | turboButton.isVisible = true | ||
| 285 | turboButton.isCheckable = true | ||
| 286 | turboButton.isChecked = turbo | ||
| 287 | turboButton.setOnMenuItemClickListener { | ||
| 288 | params.set("turbo", !turbo) | ||
| 289 | true | ||
| 290 | } | ||
| 291 | } else if (params.has("axis")) { | ||
| 292 | val axisInvert = params.get("invert", "+") == "-" | ||
| 293 | invertAxis.isVisible = true | ||
| 294 | invertAxis.isCheckable = true | ||
| 295 | invertAxis.isChecked = axisInvert | ||
| 296 | invertAxis.setOnMenuItemClickListener { | ||
| 297 | params.set("invert", if (!axisInvert) "-" else "+") | ||
| 298 | true | ||
| 299 | } | ||
| 300 | |||
| 301 | val buttonInvert = params.get("inverted", false) | ||
| 302 | invertButton.isVisible = true | ||
| 303 | invertButton.isCheckable = true | ||
| 304 | invertButton.isChecked = buttonInvert | ||
| 305 | invertButton.setOnMenuItemClickListener { | ||
| 306 | params.set("inverted", !buttonInvert) | ||
| 307 | true | ||
| 308 | } | ||
| 309 | |||
| 310 | setThreshold.isVisible = true | ||
| 311 | val thresholdSetting = object : AbstractIntSetting { | ||
| 312 | override val key = "" | ||
| 313 | |||
| 314 | override fun getInt(needsGlobal: Boolean): Int = | ||
| 315 | (params.get("threshold", 0.5f) * 100).toInt() | ||
| 316 | |||
| 317 | override fun setInt(value: Int) { | ||
| 318 | params.set("threshold", value.toFloat() / 100) | ||
| 319 | NativeInput.setButtonParam( | ||
| 320 | item.playerIndex, | ||
| 321 | item.nativeButton, | ||
| 322 | params | ||
| 323 | ) | ||
| 324 | } | ||
| 325 | |||
| 326 | override val defaultValue = 50 | ||
| 327 | |||
| 328 | override fun getValueAsString(needsGlobal: Boolean): String = | ||
| 329 | getInt(needsGlobal).toString() | ||
| 330 | |||
| 331 | override fun reset() = setInt(defaultValue) | ||
| 332 | } | ||
| 333 | setThreshold.setOnMenuItemClickListener { | ||
| 334 | onSliderClick( | ||
| 335 | SliderSetting(thresholdSetting, R.string.set_threshold), | ||
| 336 | position | ||
| 337 | ) | ||
| 338 | true | ||
| 339 | } | ||
| 340 | |||
| 341 | val axisToggle = params.get("toggle", false) | ||
| 342 | toggleAxis.isVisible = true | ||
| 343 | toggleAxis.isCheckable = true | ||
| 344 | toggleAxis.isChecked = axisToggle | ||
| 345 | toggleAxis.setOnMenuItemClickListener { | ||
| 346 | params.set("toggle", !axisToggle) | ||
| 347 | true | ||
| 348 | } | ||
| 349 | } | ||
| 350 | |||
| 351 | popup.setOnDismissListener { | ||
| 352 | NativeInput.setButtonParam(item.playerIndex, item.nativeButton, params) | ||
| 353 | settingsViewModel.setAdapterItemChanged(position) | ||
| 354 | } | ||
| 355 | } | ||
| 356 | |||
| 357 | is ModifierInputSetting -> { | ||
| 358 | val stickParams = NativeInput.getStickParam(item.playerIndex, item.nativeAnalog) | ||
| 359 | val modifierParams = ParamPackage(stickParams.get("modifier", "")) | ||
| 360 | |||
| 361 | val invert = modifierParams.get("inverted", false) | ||
| 362 | invertButton.isVisible = true | ||
| 363 | invertButton.isCheckable = true | ||
| 364 | invertButton.isChecked = invert | ||
| 365 | invertButton.setOnMenuItemClickListener { | ||
| 366 | modifierParams.set("inverted", !invert) | ||
| 367 | stickParams.set("modifier", modifierParams.serialize()) | ||
| 368 | true | ||
| 369 | } | ||
| 370 | |||
| 371 | val toggle = modifierParams.get("toggle", false) | ||
| 372 | toggleButton.isVisible = true | ||
| 373 | toggleButton.isCheckable = true | ||
| 374 | toggleButton.isChecked = toggle | ||
| 375 | toggleButton.setOnMenuItemClickListener { | ||
| 376 | modifierParams.set("toggle", !toggle) | ||
| 377 | stickParams.set("modifier", modifierParams.serialize()) | ||
| 378 | true | ||
| 379 | } | ||
| 380 | |||
| 381 | popup.setOnDismissListener { | ||
| 382 | NativeInput.setStickParam( | ||
| 383 | item.playerIndex, | ||
| 384 | item.nativeAnalog, | ||
| 385 | stickParams | ||
| 386 | ) | ||
| 387 | settingsViewModel.setAdapterItemChanged(position) | ||
| 388 | } | ||
| 389 | } | ||
| 390 | } | ||
| 391 | } | ||
| 392 | popup.show() | ||
| 393 | } | ||
| 394 | |||
| 188 | fun onLongClick(item: SettingsItem, position: Int): Boolean { | 395 | fun onLongClick(item: SettingsItem, position: Int): Boolean { |
| 189 | SettingsDialogFragment.newInstance( | 396 | SettingsDialogFragment.newInstance( |
| 190 | settingsViewModel, | 397 | settingsViewModel, |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt index 60e029f34..a81ff6b1a 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsDialogFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.fragments | 4 | package org.yuzu.yuzu_emu.features.settings.ui |
| 5 | 5 | ||
| 6 | import android.app.Dialog | 6 | import android.app.Dialog |
| 7 | import android.content.DialogInterface | 7 | import android.content.DialogInterface |
| @@ -11,19 +11,21 @@ import android.view.View | |||
| 11 | import android.view.ViewGroup | 11 | import android.view.ViewGroup |
| 12 | import androidx.fragment.app.DialogFragment | 12 | import androidx.fragment.app.DialogFragment |
| 13 | import androidx.fragment.app.activityViewModels | 13 | import androidx.fragment.app.activityViewModels |
| 14 | import androidx.lifecycle.Lifecycle | ||
| 15 | import androidx.lifecycle.lifecycleScope | ||
| 16 | import androidx.lifecycle.repeatOnLifecycle | ||
| 17 | import com.google.android.material.dialog.MaterialAlertDialogBuilder | 14 | import com.google.android.material.dialog.MaterialAlertDialogBuilder |
| 18 | import com.google.android.material.slider.Slider | 15 | import com.google.android.material.slider.Slider |
| 19 | import kotlinx.coroutines.launch | ||
| 20 | import org.yuzu.yuzu_emu.R | 16 | import org.yuzu.yuzu_emu.R |
| 21 | import org.yuzu.yuzu_emu.databinding.DialogSliderBinding | 17 | import org.yuzu.yuzu_emu.databinding.DialogSliderBinding |
| 18 | import org.yuzu.yuzu_emu.features.input.NativeInput | ||
| 19 | import org.yuzu.yuzu_emu.features.input.model.AnalogDirection | ||
| 20 | import org.yuzu.yuzu_emu.features.settings.model.view.AnalogInputSetting | ||
| 21 | import org.yuzu.yuzu_emu.features.settings.model.view.ButtonInputSetting | ||
| 22 | import org.yuzu.yuzu_emu.features.settings.model.view.IntSingleChoiceSetting | ||
| 22 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem | 23 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem |
| 23 | import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting | 24 | import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting |
| 24 | import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting | 25 | import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting |
| 25 | import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting | 26 | import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting |
| 26 | import org.yuzu.yuzu_emu.model.SettingsViewModel | 27 | import org.yuzu.yuzu_emu.utils.ParamPackage |
| 28 | import org.yuzu.yuzu_emu.utils.collect | ||
| 27 | 29 | ||
| 28 | class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener { | 30 | class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener { |
| 29 | private var type = 0 | 31 | private var type = 0 |
| @@ -50,8 +52,49 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener | |||
| 50 | MaterialAlertDialogBuilder(requireContext()) | 52 | MaterialAlertDialogBuilder(requireContext()) |
| 51 | .setMessage(R.string.reset_setting_confirmation) | 53 | .setMessage(R.string.reset_setting_confirmation) |
| 52 | .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> | 54 | .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> |
| 53 | settingsViewModel.clickedItem!!.setting.reset() | 55 | when (val item = settingsViewModel.clickedItem) { |
| 54 | settingsViewModel.setAdapterItemChanged(position) | 56 | is AnalogInputSetting -> { |
| 57 | val stickParam = NativeInput.getStickParam( | ||
| 58 | item.playerIndex, | ||
| 59 | item.nativeAnalog | ||
| 60 | ) | ||
| 61 | if (stickParam.get("engine", "") == "analog_from_button") { | ||
| 62 | when (item.analogDirection) { | ||
| 63 | AnalogDirection.Up -> stickParam.erase("up") | ||
| 64 | AnalogDirection.Down -> stickParam.erase("down") | ||
| 65 | AnalogDirection.Left -> stickParam.erase("left") | ||
| 66 | AnalogDirection.Right -> stickParam.erase("right") | ||
| 67 | } | ||
| 68 | NativeInput.setStickParam( | ||
| 69 | item.playerIndex, | ||
| 70 | item.nativeAnalog, | ||
| 71 | stickParam | ||
| 72 | ) | ||
| 73 | settingsViewModel.setAdapterItemChanged(position) | ||
| 74 | } else { | ||
| 75 | NativeInput.setStickParam( | ||
| 76 | item.playerIndex, | ||
| 77 | item.nativeAnalog, | ||
| 78 | ParamPackage() | ||
| 79 | ) | ||
| 80 | settingsViewModel.setDatasetChanged(true) | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | is ButtonInputSetting -> { | ||
| 85 | NativeInput.setButtonParam( | ||
| 86 | item.playerIndex, | ||
| 87 | item.nativeButton, | ||
| 88 | ParamPackage() | ||
| 89 | ) | ||
| 90 | settingsViewModel.setAdapterItemChanged(position) | ||
| 91 | } | ||
| 92 | |||
| 93 | else -> { | ||
| 94 | settingsViewModel.clickedItem!!.setting.reset() | ||
| 95 | settingsViewModel.setAdapterItemChanged(position) | ||
| 96 | } | ||
| 97 | } | ||
| 55 | } | 98 | } |
| 56 | .setNegativeButton(android.R.string.cancel, null) | 99 | .setNegativeButton(android.R.string.cancel, null) |
| 57 | .create() | 100 | .create() |
| @@ -61,7 +104,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener | |||
| 61 | val item = settingsViewModel.clickedItem as SingleChoiceSetting | 104 | val item = settingsViewModel.clickedItem as SingleChoiceSetting |
| 62 | val value = getSelectionForSingleChoiceValue(item) | 105 | val value = getSelectionForSingleChoiceValue(item) |
| 63 | MaterialAlertDialogBuilder(requireContext()) | 106 | MaterialAlertDialogBuilder(requireContext()) |
| 64 | .setTitle(item.nameId) | 107 | .setTitle(item.title) |
| 65 | .setSingleChoiceItems(item.choicesId, value, this) | 108 | .setSingleChoiceItems(item.choicesId, value, this) |
| 66 | .create() | 109 | .create() |
| 67 | } | 110 | } |
| @@ -81,7 +124,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener | |||
| 81 | } | 124 | } |
| 82 | 125 | ||
| 83 | MaterialAlertDialogBuilder(requireContext()) | 126 | MaterialAlertDialogBuilder(requireContext()) |
| 84 | .setTitle(item.nameId) | 127 | .setTitle(item.title) |
| 85 | .setView(sliderBinding.root) | 128 | .setView(sliderBinding.root) |
| 86 | .setPositiveButton(android.R.string.ok, this) | 129 | .setPositiveButton(android.R.string.ok, this) |
| 87 | .setNegativeButton(android.R.string.cancel, defaultCancelListener) | 130 | .setNegativeButton(android.R.string.cancel, defaultCancelListener) |
| @@ -91,8 +134,16 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener | |||
| 91 | SettingsItem.TYPE_STRING_SINGLE_CHOICE -> { | 134 | SettingsItem.TYPE_STRING_SINGLE_CHOICE -> { |
| 92 | val item = settingsViewModel.clickedItem as StringSingleChoiceSetting | 135 | val item = settingsViewModel.clickedItem as StringSingleChoiceSetting |
| 93 | MaterialAlertDialogBuilder(requireContext()) | 136 | MaterialAlertDialogBuilder(requireContext()) |
| 94 | .setTitle(item.nameId) | 137 | .setTitle(item.title) |
| 95 | .setSingleChoiceItems(item.choices, item.selectValueIndex, this) | 138 | .setSingleChoiceItems(item.choices, item.selectedValueIndex, this) |
| 139 | .create() | ||
| 140 | } | ||
| 141 | |||
| 142 | SettingsItem.TYPE_INT_SINGLE_CHOICE -> { | ||
| 143 | val item = settingsViewModel.clickedItem as IntSingleChoiceSetting | ||
| 144 | MaterialAlertDialogBuilder(requireContext()) | ||
| 145 | .setTitle(item.title) | ||
| 146 | .setSingleChoiceItems(item.choices, item.selectedValueIndex, this) | ||
| 96 | .create() | 147 | .create() |
| 97 | } | 148 | } |
| 98 | 149 | ||
| @@ -115,17 +166,11 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener | |||
| 115 | super.onViewCreated(view, savedInstanceState) | 166 | super.onViewCreated(view, savedInstanceState) |
| 116 | when (type) { | 167 | when (type) { |
| 117 | SettingsItem.TYPE_SLIDER -> { | 168 | SettingsItem.TYPE_SLIDER -> { |
| 118 | viewLifecycleOwner.lifecycleScope.launch { | 169 | settingsViewModel.sliderTextValue.collect(viewLifecycleOwner) { |
| 119 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 170 | sliderBinding.textValue.text = it |
| 120 | settingsViewModel.sliderTextValue.collect { | 171 | } |
| 121 | sliderBinding.textValue.text = it | 172 | settingsViewModel.sliderProgress.collect(viewLifecycleOwner) { |
| 122 | } | 173 | sliderBinding.slider.value = it.toFloat() |
| 123 | } | ||
| 124 | repeatOnLifecycle(Lifecycle.State.CREATED) { | ||
| 125 | settingsViewModel.sliderProgress.collect { | ||
| 126 | sliderBinding.slider.value = it.toFloat() | ||
| 127 | } | ||
| 128 | } | ||
| 129 | } | 174 | } |
| 130 | } | 175 | } |
| 131 | } | 176 | } |
| @@ -145,6 +190,12 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener | |||
| 145 | scSetting.setSelectedValue(value) | 190 | scSetting.setSelectedValue(value) |
| 146 | } | 191 | } |
| 147 | 192 | ||
| 193 | is IntSingleChoiceSetting -> { | ||
| 194 | val scSetting = settingsViewModel.clickedItem as IntSingleChoiceSetting | ||
| 195 | val value = scSetting.getValueAt(which) | ||
| 196 | scSetting.setSelectedValue(value) | ||
| 197 | } | ||
| 198 | |||
| 148 | is SliderSetting -> { | 199 | is SliderSetting -> { |
| 149 | val sliderSetting = settingsViewModel.clickedItem as SliderSetting | 200 | val sliderSetting = settingsViewModel.clickedItem as SliderSetting |
| 150 | sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value) | 201 | sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt index 6f6e7be10..ec16f16c4 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt | |||
| @@ -13,20 +13,17 @@ import androidx.core.view.WindowInsetsCompat | |||
| 13 | import androidx.core.view.updatePadding | 13 | import androidx.core.view.updatePadding |
| 14 | import androidx.fragment.app.Fragment | 14 | import androidx.fragment.app.Fragment |
| 15 | import androidx.fragment.app.activityViewModels | 15 | import androidx.fragment.app.activityViewModels |
| 16 | import androidx.lifecycle.Lifecycle | ||
| 17 | import androidx.lifecycle.lifecycleScope | ||
| 18 | import androidx.lifecycle.repeatOnLifecycle | ||
| 19 | import androidx.navigation.findNavController | 16 | import androidx.navigation.findNavController |
| 20 | import androidx.navigation.fragment.navArgs | 17 | import androidx.navigation.fragment.navArgs |
| 21 | import androidx.recyclerview.widget.LinearLayoutManager | 18 | import androidx.recyclerview.widget.LinearLayoutManager |
| 22 | import com.google.android.material.transition.MaterialSharedAxis | 19 | import com.google.android.material.transition.MaterialSharedAxis |
| 23 | import kotlinx.coroutines.flow.collectLatest | ||
| 24 | import kotlinx.coroutines.launch | ||
| 25 | import org.yuzu.yuzu_emu.R | 20 | import org.yuzu.yuzu_emu.R |
| 26 | import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding | 21 | import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding |
| 22 | import org.yuzu.yuzu_emu.features.input.NativeInput | ||
| 27 | import org.yuzu.yuzu_emu.features.settings.model.Settings | 23 | import org.yuzu.yuzu_emu.features.settings.model.Settings |
| 28 | import org.yuzu.yuzu_emu.model.SettingsViewModel | 24 | import org.yuzu.yuzu_emu.fragments.MessageDialogFragment |
| 29 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins | 25 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins |
| 26 | import org.yuzu.yuzu_emu.utils.collect | ||
| 30 | 27 | ||
| 31 | class SettingsFragment : Fragment() { | 28 | class SettingsFragment : Fragment() { |
| 32 | private lateinit var presenter: SettingsFragmentPresenter | 29 | private lateinit var presenter: SettingsFragmentPresenter |
| @@ -45,6 +42,12 @@ class SettingsFragment : Fragment() { | |||
| 45 | returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false) | 42 | returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false) |
| 46 | reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false) | 43 | reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false) |
| 47 | exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) | 44 | exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) |
| 45 | |||
| 46 | val playerIndex = getPlayerIndex() | ||
| 47 | if (playerIndex != -1) { | ||
| 48 | NativeInput.loadInputProfiles() | ||
| 49 | NativeInput.reloadInputDevices() | ||
| 50 | } | ||
| 48 | } | 51 | } |
| 49 | 52 | ||
| 50 | override fun onCreateView( | 53 | override fun onCreateView( |
| @@ -56,9 +59,9 @@ class SettingsFragment : Fragment() { | |||
| 56 | return binding.root | 59 | return binding.root |
| 57 | } | 60 | } |
| 58 | 61 | ||
| 59 | // This is using the correct scope, lint is just acting up | 62 | @SuppressLint("NotifyDataSetChanged") |
| 60 | @SuppressLint("UnsafeRepeatOnLifecycleDetector") | ||
| 61 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | 63 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| 64 | super.onViewCreated(view, savedInstanceState) | ||
| 62 | settingsAdapter = SettingsAdapter(this, requireContext()) | 65 | settingsAdapter = SettingsAdapter(this, requireContext()) |
| 63 | presenter = SettingsFragmentPresenter( | 66 | presenter = SettingsFragmentPresenter( |
| 64 | settingsViewModel, | 67 | settingsViewModel, |
| @@ -71,7 +74,17 @@ class SettingsFragment : Fragment() { | |||
| 71 | ) { | 74 | ) { |
| 72 | args.game!!.title | 75 | args.game!!.title |
| 73 | } else { | 76 | } else { |
| 74 | getString(args.menuTag.titleId) | 77 | when (args.menuTag) { |
| 78 | Settings.MenuTag.SECTION_INPUT_PLAYER_ONE -> Settings.getPlayerString(1) | ||
| 79 | Settings.MenuTag.SECTION_INPUT_PLAYER_TWO -> Settings.getPlayerString(2) | ||
| 80 | Settings.MenuTag.SECTION_INPUT_PLAYER_THREE -> Settings.getPlayerString(3) | ||
| 81 | Settings.MenuTag.SECTION_INPUT_PLAYER_FOUR -> Settings.getPlayerString(4) | ||
| 82 | Settings.MenuTag.SECTION_INPUT_PLAYER_FIVE -> Settings.getPlayerString(5) | ||
| 83 | Settings.MenuTag.SECTION_INPUT_PLAYER_SIX -> Settings.getPlayerString(6) | ||
| 84 | Settings.MenuTag.SECTION_INPUT_PLAYER_SEVEN -> Settings.getPlayerString(7) | ||
| 85 | Settings.MenuTag.SECTION_INPUT_PLAYER_EIGHT -> Settings.getPlayerString(8) | ||
| 86 | else -> getString(args.menuTag.titleId) | ||
| 87 | } | ||
| 75 | } | 88 | } |
| 76 | binding.listSettings.apply { | 89 | binding.listSettings.apply { |
| 77 | adapter = settingsAdapter | 90 | adapter = settingsAdapter |
| @@ -82,16 +95,37 @@ class SettingsFragment : Fragment() { | |||
| 82 | settingsViewModel.setShouldNavigateBack(true) | 95 | settingsViewModel.setShouldNavigateBack(true) |
| 83 | } | 96 | } |
| 84 | 97 | ||
| 85 | viewLifecycleOwner.lifecycleScope.apply { | 98 | settingsViewModel.shouldReloadSettingsList.collect( |
| 86 | launch { | 99 | viewLifecycleOwner, |
| 87 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 100 | resetState = { settingsViewModel.setShouldReloadSettingsList(false) } |
| 88 | settingsViewModel.shouldReloadSettingsList.collectLatest { | 101 | ) { if (it) presenter.loadSettingsList() } |
| 89 | if (it) { | 102 | settingsViewModel.adapterItemChanged.collect( |
| 90 | settingsViewModel.setShouldReloadSettingsList(false) | 103 | viewLifecycleOwner, |
| 91 | presenter.loadSettingsList() | 104 | resetState = { settingsViewModel.setAdapterItemChanged(-1) } |
| 92 | } | 105 | ) { if (it != -1) settingsAdapter?.notifyItemChanged(it) } |
| 93 | } | 106 | settingsViewModel.datasetChanged.collect( |
| 94 | } | 107 | viewLifecycleOwner, |
| 108 | resetState = { settingsViewModel.setDatasetChanged(false) } | ||
| 109 | ) { if (it) settingsAdapter?.notifyDataSetChanged() } | ||
| 110 | settingsViewModel.reloadListAndNotifyDataset.collect( | ||
| 111 | viewLifecycleOwner, | ||
| 112 | resetState = { settingsViewModel.setReloadListAndNotifyDataset(false) } | ||
| 113 | ) { if (it) presenter.loadSettingsList(true) } | ||
| 114 | settingsViewModel.shouldShowResetInputDialog.collect( | ||
| 115 | viewLifecycleOwner, | ||
| 116 | resetState = { settingsViewModel.setShouldShowResetInputDialog(false) } | ||
| 117 | ) { | ||
| 118 | if (it) { | ||
| 119 | MessageDialogFragment.newInstance( | ||
| 120 | activity = requireActivity(), | ||
| 121 | titleId = R.string.reset_mapping, | ||
| 122 | descriptionId = R.string.reset_mapping_description, | ||
| 123 | positiveAction = { | ||
| 124 | NativeInput.resetControllerMappings(getPlayerIndex()) | ||
| 125 | settingsViewModel.setReloadListAndNotifyDataset(true) | ||
| 126 | }, | ||
| 127 | negativeAction = {} | ||
| 128 | ).show(parentFragmentManager, MessageDialogFragment.TAG) | ||
| 95 | } | 129 | } |
| 96 | } | 130 | } |
| 97 | 131 | ||
| @@ -115,6 +149,19 @@ class SettingsFragment : Fragment() { | |||
| 115 | setInsets() | 149 | setInsets() |
| 116 | } | 150 | } |
| 117 | 151 | ||
| 152 | private fun getPlayerIndex(): Int = | ||
| 153 | when (args.menuTag) { | ||
| 154 | Settings.MenuTag.SECTION_INPUT_PLAYER_ONE -> 0 | ||
| 155 | Settings.MenuTag.SECTION_INPUT_PLAYER_TWO -> 1 | ||
| 156 | Settings.MenuTag.SECTION_INPUT_PLAYER_THREE -> 2 | ||
| 157 | Settings.MenuTag.SECTION_INPUT_PLAYER_FOUR -> 3 | ||
| 158 | Settings.MenuTag.SECTION_INPUT_PLAYER_FIVE -> 4 | ||
| 159 | Settings.MenuTag.SECTION_INPUT_PLAYER_SIX -> 5 | ||
| 160 | Settings.MenuTag.SECTION_INPUT_PLAYER_SEVEN -> 6 | ||
| 161 | Settings.MenuTag.SECTION_INPUT_PLAYER_EIGHT -> 7 | ||
| 162 | else -> -1 | ||
| 163 | } | ||
| 164 | |||
| 118 | private fun setInsets() { | 165 | private fun setInsets() { |
| 119 | ViewCompat.setOnApplyWindowInsetsListener( | 166 | ViewCompat.setOnApplyWindowInsetsListener( |
| 120 | binding.root | 167 | binding.root |
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 db1a58147..e491c29a2 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,11 +3,17 @@ | |||
| 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.annotation.SuppressLint | ||
| 6 | import android.os.Build | 7 | import android.os.Build |
| 7 | import android.widget.Toast | 8 | import android.widget.Toast |
| 8 | import org.yuzu.yuzu_emu.NativeLibrary | 9 | import org.yuzu.yuzu_emu.NativeLibrary |
| 9 | import org.yuzu.yuzu_emu.R | 10 | import org.yuzu.yuzu_emu.R |
| 10 | import org.yuzu.yuzu_emu.YuzuApplication | 11 | import org.yuzu.yuzu_emu.YuzuApplication |
| 12 | import org.yuzu.yuzu_emu.features.input.NativeInput | ||
| 13 | import org.yuzu.yuzu_emu.features.input.model.AnalogDirection | ||
| 14 | import org.yuzu.yuzu_emu.features.input.model.NativeAnalog | ||
| 15 | import org.yuzu.yuzu_emu.features.input.model.NativeButton | ||
| 16 | import org.yuzu.yuzu_emu.features.input.model.NpadStyleIndex | ||
| 11 | import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting | 17 | import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting |
| 12 | import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting | 18 | import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting |
| 13 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting | 19 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting |
| @@ -15,18 +21,21 @@ import org.yuzu.yuzu_emu.features.settings.model.ByteSetting | |||
| 15 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting | 21 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting |
| 16 | import org.yuzu.yuzu_emu.features.settings.model.LongSetting | 22 | import org.yuzu.yuzu_emu.features.settings.model.LongSetting |
| 17 | import org.yuzu.yuzu_emu.features.settings.model.Settings | 23 | import org.yuzu.yuzu_emu.features.settings.model.Settings |
| 24 | import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag | ||
| 18 | import org.yuzu.yuzu_emu.features.settings.model.ShortSetting | 25 | import org.yuzu.yuzu_emu.features.settings.model.ShortSetting |
| 19 | import org.yuzu.yuzu_emu.features.settings.model.view.* | 26 | import org.yuzu.yuzu_emu.features.settings.model.view.* |
| 20 | import org.yuzu.yuzu_emu.model.SettingsViewModel | 27 | import org.yuzu.yuzu_emu.utils.InputHandler |
| 21 | import org.yuzu.yuzu_emu.utils.NativeConfig | 28 | import org.yuzu.yuzu_emu.utils.NativeConfig |
| 22 | 29 | ||
| 23 | class SettingsFragmentPresenter( | 30 | class SettingsFragmentPresenter( |
| 24 | private val settingsViewModel: SettingsViewModel, | 31 | private val settingsViewModel: SettingsViewModel, |
| 25 | private val adapter: SettingsAdapter, | 32 | private val adapter: SettingsAdapter, |
| 26 | private var menuTag: Settings.MenuTag | 33 | private var menuTag: MenuTag |
| 27 | ) { | 34 | ) { |
| 28 | private var settingsList = ArrayList<SettingsItem>() | 35 | private var settingsList = ArrayList<SettingsItem>() |
| 29 | 36 | ||
| 37 | private val context get() = YuzuApplication.appContext | ||
| 38 | |||
| 30 | // Extension for altering settings list based on each setting's properties | 39 | // Extension for altering settings list based on each setting's properties |
| 31 | fun ArrayList<SettingsItem>.add(key: String) { | 40 | fun ArrayList<SettingsItem>.add(key: String) { |
| 32 | val item = SettingsItem.settingsItems[key]!! | 41 | val item = SettingsItem.settingsItems[key]!! |
| @@ -53,73 +62,90 @@ class SettingsFragmentPresenter( | |||
| 53 | add(item) | 62 | add(item) |
| 54 | } | 63 | } |
| 55 | 64 | ||
| 65 | // Allows you to show/hide abstract settings based on the paired setting key | ||
| 66 | fun ArrayList<SettingsItem>.addAbstract(item: SettingsItem) { | ||
| 67 | val pairedSettingKey = item.setting.pairedSettingKey | ||
| 68 | if (pairedSettingKey.isNotEmpty()) { | ||
| 69 | val pairedSettingsItem = | ||
| 70 | this.firstOrNull { it.setting.key == pairedSettingKey } ?: return | ||
| 71 | val pairedSetting = pairedSettingsItem.setting as AbstractBooleanSetting | ||
| 72 | if (!pairedSetting.getBoolean(!NativeConfig.isPerGameConfigLoaded())) return | ||
| 73 | } | ||
| 74 | add(item) | ||
| 75 | } | ||
| 76 | |||
| 56 | fun onViewCreated() { | 77 | fun onViewCreated() { |
| 57 | loadSettingsList() | 78 | loadSettingsList() |
| 58 | } | 79 | } |
| 59 | 80 | ||
| 60 | fun loadSettingsList() { | 81 | @SuppressLint("NotifyDataSetChanged") |
| 82 | fun loadSettingsList(notifyDataSetChanged: Boolean = false) { | ||
| 61 | val sl = ArrayList<SettingsItem>() | 83 | val sl = ArrayList<SettingsItem>() |
| 62 | when (menuTag) { | 84 | when (menuTag) { |
| 63 | Settings.MenuTag.SECTION_ROOT -> addConfigSettings(sl) | 85 | MenuTag.SECTION_ROOT -> addConfigSettings(sl) |
| 64 | Settings.MenuTag.SECTION_SYSTEM -> addSystemSettings(sl) | 86 | MenuTag.SECTION_SYSTEM -> addSystemSettings(sl) |
| 65 | Settings.MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl) | 87 | MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl) |
| 66 | Settings.MenuTag.SECTION_AUDIO -> addAudioSettings(sl) | 88 | MenuTag.SECTION_AUDIO -> addAudioSettings(sl) |
| 67 | Settings.MenuTag.SECTION_THEME -> addThemeSettings(sl) | 89 | MenuTag.SECTION_INPUT -> addInputSettings(sl) |
| 68 | Settings.MenuTag.SECTION_DEBUG -> addDebugSettings(sl) | 90 | MenuTag.SECTION_INPUT_PLAYER_ONE -> addInputPlayer(sl, 0) |
| 69 | else -> { | 91 | MenuTag.SECTION_INPUT_PLAYER_TWO -> addInputPlayer(sl, 1) |
| 70 | val context = YuzuApplication.appContext | 92 | MenuTag.SECTION_INPUT_PLAYER_THREE -> addInputPlayer(sl, 2) |
| 71 | Toast.makeText( | 93 | MenuTag.SECTION_INPUT_PLAYER_FOUR -> addInputPlayer(sl, 3) |
| 72 | context, | 94 | MenuTag.SECTION_INPUT_PLAYER_FIVE -> addInputPlayer(sl, 4) |
| 73 | context.getString(R.string.unimplemented_menu), | 95 | MenuTag.SECTION_INPUT_PLAYER_SIX -> addInputPlayer(sl, 5) |
| 74 | Toast.LENGTH_SHORT | 96 | MenuTag.SECTION_INPUT_PLAYER_SEVEN -> addInputPlayer(sl, 6) |
| 75 | ).show() | 97 | MenuTag.SECTION_INPUT_PLAYER_EIGHT -> addInputPlayer(sl, 7) |
| 76 | return | 98 | MenuTag.SECTION_THEME -> addThemeSettings(sl) |
| 77 | } | 99 | MenuTag.SECTION_DEBUG -> addDebugSettings(sl) |
| 78 | } | 100 | } |
| 79 | settingsList = sl | 101 | settingsList = sl |
| 80 | adapter.submitList(settingsList) | 102 | adapter.submitList(settingsList) { |
| 103 | if (notifyDataSetChanged) { | ||
| 104 | adapter.notifyDataSetChanged() | ||
| 105 | } | ||
| 106 | } | ||
| 81 | } | 107 | } |
| 82 | 108 | ||
| 83 | private fun addConfigSettings(sl: ArrayList<SettingsItem>) { | 109 | private fun addConfigSettings(sl: ArrayList<SettingsItem>) { |
| 84 | sl.apply { | 110 | sl.apply { |
| 85 | add( | 111 | add( |
| 86 | SubmenuSetting( | 112 | SubmenuSetting( |
| 87 | R.string.preferences_system, | 113 | titleId = R.string.preferences_system, |
| 88 | R.string.preferences_system_description, | 114 | descriptionId = R.string.preferences_system_description, |
| 89 | R.drawable.ic_system_settings, | 115 | iconId = R.drawable.ic_system_settings, |
| 90 | Settings.MenuTag.SECTION_SYSTEM | 116 | menuKey = MenuTag.SECTION_SYSTEM |
| 91 | ) | 117 | ) |
| 92 | ) | 118 | ) |
| 93 | add( | 119 | add( |
| 94 | SubmenuSetting( | 120 | SubmenuSetting( |
| 95 | R.string.preferences_graphics, | 121 | titleId = R.string.preferences_graphics, |
| 96 | R.string.preferences_graphics_description, | 122 | descriptionId = R.string.preferences_graphics_description, |
| 97 | R.drawable.ic_graphics, | 123 | iconId = R.drawable.ic_graphics, |
| 98 | Settings.MenuTag.SECTION_RENDERER | 124 | menuKey = MenuTag.SECTION_RENDERER |
| 99 | ) | 125 | ) |
| 100 | ) | 126 | ) |
| 101 | add( | 127 | add( |
| 102 | SubmenuSetting( | 128 | SubmenuSetting( |
| 103 | R.string.preferences_audio, | 129 | titleId = R.string.preferences_audio, |
| 104 | R.string.preferences_audio_description, | 130 | descriptionId = R.string.preferences_audio_description, |
| 105 | R.drawable.ic_audio, | 131 | iconId = R.drawable.ic_audio, |
| 106 | Settings.MenuTag.SECTION_AUDIO | 132 | menuKey = MenuTag.SECTION_AUDIO |
| 107 | ) | 133 | ) |
| 108 | ) | 134 | ) |
| 109 | add( | 135 | add( |
| 110 | SubmenuSetting( | 136 | SubmenuSetting( |
| 111 | R.string.preferences_debug, | 137 | titleId = R.string.preferences_debug, |
| 112 | R.string.preferences_debug_description, | 138 | descriptionId = R.string.preferences_debug_description, |
| 113 | R.drawable.ic_code, | 139 | iconId = R.drawable.ic_code, |
| 114 | Settings.MenuTag.SECTION_DEBUG | 140 | menuKey = MenuTag.SECTION_DEBUG |
| 115 | ) | 141 | ) |
| 116 | ) | 142 | ) |
| 117 | add( | 143 | add( |
| 118 | RunnableSetting( | 144 | RunnableSetting( |
| 119 | R.string.reset_to_default, | 145 | titleId = R.string.reset_to_default, |
| 120 | R.string.reset_to_default_description, | 146 | descriptionId = R.string.reset_to_default_description, |
| 121 | false, | 147 | isRunnable = !NativeLibrary.isRunning(), |
| 122 | R.drawable.ic_restore | 148 | iconId = R.drawable.ic_restore |
| 123 | ) { settingsViewModel.setShouldShowResetSettingsDialog(true) } | 149 | ) { settingsViewModel.setShouldShowResetSettingsDialog(true) } |
| 124 | ) | 150 | ) |
| 125 | } | 151 | } |
| @@ -164,6 +190,671 @@ class SettingsFragmentPresenter( | |||
| 164 | } | 190 | } |
| 165 | } | 191 | } |
| 166 | 192 | ||
| 193 | private fun addInputSettings(sl: ArrayList<SettingsItem>) { | ||
| 194 | settingsViewModel.currentDevice = 0 | ||
| 195 | |||
| 196 | if (NativeConfig.isPerGameConfigLoaded()) { | ||
| 197 | NativeInput.loadInputProfiles() | ||
| 198 | val profiles = NativeInput.getInputProfileNames().toMutableList() | ||
| 199 | profiles.add(0, "") | ||
| 200 | val prettyProfiles = profiles.toTypedArray() | ||
| 201 | prettyProfiles[0] = | ||
| 202 | context.getString(R.string.use_global_input_configuration) | ||
| 203 | sl.apply { | ||
| 204 | for (i in 0 until 8) { | ||
| 205 | add( | ||
| 206 | IntSingleChoiceSetting( | ||
| 207 | getPerGameProfileSetting(profiles, i), | ||
| 208 | titleString = getPlayerProfileString(i + 1), | ||
| 209 | choices = prettyProfiles, | ||
| 210 | values = IntArray(profiles.size) { it }.toTypedArray() | ||
| 211 | ) | ||
| 212 | ) | ||
| 213 | } | ||
| 214 | } | ||
| 215 | return | ||
| 216 | } | ||
| 217 | |||
| 218 | val getConnectedIcon: (Int) -> Int = { playerIndex: Int -> | ||
| 219 | if (NativeInput.getIsConnected(playerIndex)) { | ||
| 220 | R.drawable.ic_controller | ||
| 221 | } else { | ||
| 222 | R.drawable.ic_controller_disconnected | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | val inputSettings = NativeConfig.getInputSettings(true) | ||
| 227 | sl.apply { | ||
| 228 | add( | ||
| 229 | SubmenuSetting( | ||
| 230 | titleString = Settings.getPlayerString(1), | ||
| 231 | descriptionString = inputSettings[0].profileName, | ||
| 232 | menuKey = MenuTag.SECTION_INPUT_PLAYER_ONE, | ||
| 233 | iconId = getConnectedIcon(0) | ||
| 234 | ) | ||
| 235 | ) | ||
| 236 | add( | ||
| 237 | SubmenuSetting( | ||
| 238 | titleString = Settings.getPlayerString(2), | ||
| 239 | descriptionString = inputSettings[1].profileName, | ||
| 240 | menuKey = MenuTag.SECTION_INPUT_PLAYER_TWO, | ||
| 241 | iconId = getConnectedIcon(1) | ||
| 242 | ) | ||
| 243 | ) | ||
| 244 | add( | ||
| 245 | SubmenuSetting( | ||
| 246 | titleString = Settings.getPlayerString(3), | ||
| 247 | descriptionString = inputSettings[2].profileName, | ||
| 248 | menuKey = MenuTag.SECTION_INPUT_PLAYER_THREE, | ||
| 249 | iconId = getConnectedIcon(2) | ||
| 250 | ) | ||
| 251 | ) | ||
| 252 | add( | ||
| 253 | SubmenuSetting( | ||
| 254 | titleString = Settings.getPlayerString(4), | ||
| 255 | descriptionString = inputSettings[3].profileName, | ||
| 256 | menuKey = MenuTag.SECTION_INPUT_PLAYER_FOUR, | ||
| 257 | iconId = getConnectedIcon(3) | ||
| 258 | ) | ||
| 259 | ) | ||
| 260 | add( | ||
| 261 | SubmenuSetting( | ||
| 262 | titleString = Settings.getPlayerString(5), | ||
| 263 | descriptionString = inputSettings[4].profileName, | ||
| 264 | menuKey = MenuTag.SECTION_INPUT_PLAYER_FIVE, | ||
| 265 | iconId = getConnectedIcon(4) | ||
| 266 | ) | ||
| 267 | ) | ||
| 268 | add( | ||
| 269 | SubmenuSetting( | ||
| 270 | titleString = Settings.getPlayerString(6), | ||
| 271 | descriptionString = inputSettings[5].profileName, | ||
| 272 | menuKey = MenuTag.SECTION_INPUT_PLAYER_SIX, | ||
| 273 | iconId = getConnectedIcon(5) | ||
| 274 | ) | ||
| 275 | ) | ||
| 276 | add( | ||
| 277 | SubmenuSetting( | ||
| 278 | titleString = Settings.getPlayerString(7), | ||
| 279 | descriptionString = inputSettings[6].profileName, | ||
| 280 | menuKey = MenuTag.SECTION_INPUT_PLAYER_SEVEN, | ||
| 281 | iconId = getConnectedIcon(6) | ||
| 282 | ) | ||
| 283 | ) | ||
| 284 | add( | ||
| 285 | SubmenuSetting( | ||
| 286 | titleString = Settings.getPlayerString(8), | ||
| 287 | descriptionString = inputSettings[7].profileName, | ||
| 288 | menuKey = MenuTag.SECTION_INPUT_PLAYER_EIGHT, | ||
| 289 | iconId = getConnectedIcon(7) | ||
| 290 | ) | ||
| 291 | ) | ||
| 292 | } | ||
| 293 | } | ||
| 294 | |||
| 295 | private fun getPlayerProfileString(player: Int): String = | ||
| 296 | context.getString(R.string.player_num_profile, player) | ||
| 297 | |||
| 298 | private fun getPerGameProfileSetting( | ||
| 299 | profiles: List<String>, | ||
| 300 | playerIndex: Int | ||
| 301 | ): AbstractIntSetting { | ||
| 302 | return object : AbstractIntSetting { | ||
| 303 | private val players | ||
| 304 | get() = NativeConfig.getInputSettings(false) | ||
| 305 | |||
| 306 | override val key = "" | ||
| 307 | |||
| 308 | override fun getInt(needsGlobal: Boolean): Int { | ||
| 309 | val currentProfile = players[playerIndex].profileName | ||
| 310 | profiles.forEachIndexed { i, profile -> | ||
| 311 | if (profile == currentProfile) { | ||
| 312 | return i | ||
| 313 | } | ||
| 314 | } | ||
| 315 | return 0 | ||
| 316 | } | ||
| 317 | |||
| 318 | override fun setInt(value: Int) { | ||
| 319 | NativeInput.loadPerGameConfiguration(playerIndex, value, profiles[value]) | ||
| 320 | NativeInput.connectControllers(playerIndex) | ||
| 321 | NativeConfig.saveControlPlayerValues() | ||
| 322 | } | ||
| 323 | |||
| 324 | override val defaultValue = 0 | ||
| 325 | |||
| 326 | override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString() | ||
| 327 | |||
| 328 | override fun reset() = setInt(defaultValue) | ||
| 329 | |||
| 330 | override var global = true | ||
| 331 | |||
| 332 | override val isRuntimeModifiable = true | ||
| 333 | |||
| 334 | override val isSaveable = true | ||
| 335 | } | ||
| 336 | } | ||
| 337 | |||
| 338 | private fun addInputPlayer(sl: ArrayList<SettingsItem>, playerIndex: Int) { | ||
| 339 | sl.apply { | ||
| 340 | val connectedSetting = object : AbstractBooleanSetting { | ||
| 341 | override val key = "connected" | ||
| 342 | |||
| 343 | override fun getBoolean(needsGlobal: Boolean): Boolean = | ||
| 344 | NativeInput.getIsConnected(playerIndex) | ||
| 345 | |||
| 346 | override fun setBoolean(value: Boolean) = | ||
| 347 | NativeInput.connectControllers(playerIndex, value) | ||
| 348 | |||
| 349 | override val defaultValue = playerIndex == 0 | ||
| 350 | |||
| 351 | override fun getValueAsString(needsGlobal: Boolean): String = | ||
| 352 | getBoolean(needsGlobal).toString() | ||
| 353 | |||
| 354 | override fun reset() = setBoolean(defaultValue) | ||
| 355 | } | ||
| 356 | add(SwitchSetting(connectedSetting, R.string.connected)) | ||
| 357 | |||
| 358 | val styleTags = NativeInput.getSupportedStyleTags(playerIndex) | ||
| 359 | val npadType = object : AbstractIntSetting { | ||
| 360 | override val key = "npad_type" | ||
| 361 | override fun getInt(needsGlobal: Boolean): Int { | ||
| 362 | val styleIndex = NativeInput.getStyleIndex(playerIndex) | ||
| 363 | return styleTags.indexOfFirst { it == styleIndex } | ||
| 364 | } | ||
| 365 | |||
| 366 | override fun setInt(value: Int) { | ||
| 367 | NativeInput.setStyleIndex(playerIndex, styleTags[value]) | ||
| 368 | settingsViewModel.setReloadListAndNotifyDataset(true) | ||
| 369 | } | ||
| 370 | |||
| 371 | override val defaultValue = NpadStyleIndex.Fullkey.int | ||
| 372 | override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString() | ||
| 373 | override fun reset() = setInt(defaultValue) | ||
| 374 | override val pairedSettingKey: String = "connected" | ||
| 375 | } | ||
| 376 | addAbstract( | ||
| 377 | IntSingleChoiceSetting( | ||
| 378 | npadType, | ||
| 379 | titleId = R.string.controller_type, | ||
| 380 | choices = styleTags.map { context.getString(it.nameId) } | ||
| 381 | .toTypedArray(), | ||
| 382 | values = IntArray(styleTags.size) { it }.toTypedArray() | ||
| 383 | ) | ||
| 384 | ) | ||
| 385 | |||
| 386 | InputHandler.updateControllerData() | ||
| 387 | |||
| 388 | val autoMappingSetting = object : AbstractIntSetting { | ||
| 389 | override val key = "auto_mapping_device" | ||
| 390 | |||
| 391 | override fun getInt(needsGlobal: Boolean): Int = -1 | ||
| 392 | |||
| 393 | override fun setInt(value: Int) { | ||
| 394 | val registeredController = InputHandler.registeredControllers[value + 1] | ||
| 395 | val displayName = registeredController.get( | ||
| 396 | "display", | ||
| 397 | context.getString(R.string.unknown) | ||
| 398 | ) | ||
| 399 | NativeInput.updateMappingsWithDefault( | ||
| 400 | playerIndex, | ||
| 401 | registeredController, | ||
| 402 | displayName | ||
| 403 | ) | ||
| 404 | Toast.makeText( | ||
| 405 | context, | ||
| 406 | context.getString(R.string.attempted_auto_map, displayName), | ||
| 407 | Toast.LENGTH_SHORT | ||
| 408 | ).show() | ||
| 409 | settingsViewModel.setReloadListAndNotifyDataset(true) | ||
| 410 | } | ||
| 411 | |||
| 412 | override val defaultValue = -1 | ||
| 413 | |||
| 414 | override fun getValueAsString(needsGlobal: Boolean) = getInt().toString() | ||
| 415 | |||
| 416 | override fun reset() = setInt(defaultValue) | ||
| 417 | |||
| 418 | override val isRuntimeModifiable: Boolean = true | ||
| 419 | } | ||
| 420 | |||
| 421 | val unknownString = context.getString(R.string.unknown) | ||
| 422 | val prettyAutoMappingControllerList = InputHandler.registeredControllers.mapNotNull { | ||
| 423 | val port = it.get("port", -1) | ||
| 424 | return@mapNotNull if (port == 100 || port == -1) { | ||
| 425 | null | ||
| 426 | } else { | ||
| 427 | it.get("display", unknownString) | ||
| 428 | } | ||
| 429 | }.toTypedArray() | ||
| 430 | add( | ||
| 431 | IntSingleChoiceSetting( | ||
| 432 | autoMappingSetting, | ||
| 433 | titleId = R.string.auto_map, | ||
| 434 | descriptionId = R.string.auto_map_description, | ||
| 435 | choices = prettyAutoMappingControllerList, | ||
| 436 | values = IntArray(prettyAutoMappingControllerList.size) { it }.toTypedArray() | ||
| 437 | ) | ||
| 438 | ) | ||
| 439 | |||
| 440 | val mappingFilterSetting = object : AbstractIntSetting { | ||
| 441 | override val key = "mapping_filter" | ||
| 442 | |||
| 443 | override fun getInt(needsGlobal: Boolean): Int = settingsViewModel.currentDevice | ||
| 444 | |||
| 445 | override fun setInt(value: Int) { | ||
| 446 | settingsViewModel.currentDevice = value | ||
| 447 | } | ||
| 448 | |||
| 449 | override val defaultValue = 0 | ||
| 450 | |||
| 451 | override fun getValueAsString(needsGlobal: Boolean) = getInt().toString() | ||
| 452 | |||
| 453 | override fun reset() = setInt(defaultValue) | ||
| 454 | |||
| 455 | override val isRuntimeModifiable: Boolean = true | ||
| 456 | } | ||
| 457 | |||
| 458 | val prettyControllerList = InputHandler.registeredControllers.mapNotNull { | ||
| 459 | return@mapNotNull if (it.get("port", 0) == 100) { | ||
| 460 | null | ||
| 461 | } else { | ||
| 462 | it.get("display", unknownString) | ||
| 463 | } | ||
| 464 | }.toTypedArray() | ||
| 465 | add( | ||
| 466 | IntSingleChoiceSetting( | ||
| 467 | mappingFilterSetting, | ||
| 468 | titleId = R.string.input_mapping_filter, | ||
| 469 | descriptionId = R.string.input_mapping_filter_description, | ||
| 470 | choices = prettyControllerList, | ||
| 471 | values = IntArray(prettyControllerList.size) { it }.toTypedArray() | ||
| 472 | ) | ||
| 473 | ) | ||
| 474 | |||
| 475 | add(InputProfileSetting(playerIndex)) | ||
| 476 | add( | ||
| 477 | RunnableSetting(titleId = R.string.reset_to_default, isRunnable = true) { | ||
| 478 | settingsViewModel.setShouldShowResetInputDialog(true) | ||
| 479 | } | ||
| 480 | ) | ||
| 481 | |||
| 482 | val styleIndex = NativeInput.getStyleIndex(playerIndex) | ||
| 483 | |||
| 484 | // Buttons | ||
| 485 | when (styleIndex) { | ||
| 486 | NpadStyleIndex.Fullkey, | ||
| 487 | NpadStyleIndex.Handheld, | ||
| 488 | NpadStyleIndex.JoyconDual -> { | ||
| 489 | add(HeaderSetting(R.string.buttons)) | ||
| 490 | add(ButtonInputSetting(playerIndex, NativeButton.A, R.string.button_a)) | ||
| 491 | add(ButtonInputSetting(playerIndex, NativeButton.B, R.string.button_b)) | ||
| 492 | add(ButtonInputSetting(playerIndex, NativeButton.X, R.string.button_x)) | ||
| 493 | add(ButtonInputSetting(playerIndex, NativeButton.Y, R.string.button_y)) | ||
| 494 | add(ButtonInputSetting(playerIndex, NativeButton.Plus, R.string.button_plus)) | ||
| 495 | add(ButtonInputSetting(playerIndex, NativeButton.Minus, R.string.button_minus)) | ||
| 496 | add(ButtonInputSetting(playerIndex, NativeButton.Home, R.string.button_home)) | ||
| 497 | add( | ||
| 498 | ButtonInputSetting( | ||
| 499 | playerIndex, | ||
| 500 | NativeButton.Capture, | ||
| 501 | R.string.button_capture | ||
| 502 | ) | ||
| 503 | ) | ||
| 504 | } | ||
| 505 | |||
| 506 | NpadStyleIndex.JoyconLeft -> { | ||
| 507 | add(HeaderSetting(R.string.buttons)) | ||
| 508 | add(ButtonInputSetting(playerIndex, NativeButton.Minus, R.string.button_minus)) | ||
| 509 | add( | ||
| 510 | ButtonInputSetting( | ||
| 511 | playerIndex, | ||
| 512 | NativeButton.Capture, | ||
| 513 | R.string.button_capture | ||
| 514 | ) | ||
| 515 | ) | ||
| 516 | } | ||
| 517 | |||
| 518 | NpadStyleIndex.JoyconRight -> { | ||
| 519 | add(HeaderSetting(R.string.buttons)) | ||
| 520 | add(ButtonInputSetting(playerIndex, NativeButton.A, R.string.button_a)) | ||
| 521 | add(ButtonInputSetting(playerIndex, NativeButton.B, R.string.button_b)) | ||
| 522 | add(ButtonInputSetting(playerIndex, NativeButton.X, R.string.button_x)) | ||
| 523 | add(ButtonInputSetting(playerIndex, NativeButton.Y, R.string.button_y)) | ||
| 524 | add(ButtonInputSetting(playerIndex, NativeButton.Plus, R.string.button_plus)) | ||
| 525 | add(ButtonInputSetting(playerIndex, NativeButton.Home, R.string.button_home)) | ||
| 526 | } | ||
| 527 | |||
| 528 | NpadStyleIndex.GameCube -> { | ||
| 529 | add(HeaderSetting(R.string.buttons)) | ||
| 530 | add(ButtonInputSetting(playerIndex, NativeButton.A, R.string.button_a)) | ||
| 531 | add(ButtonInputSetting(playerIndex, NativeButton.B, R.string.button_b)) | ||
| 532 | add(ButtonInputSetting(playerIndex, NativeButton.X, R.string.button_x)) | ||
| 533 | add(ButtonInputSetting(playerIndex, NativeButton.Y, R.string.button_y)) | ||
| 534 | add(ButtonInputSetting(playerIndex, NativeButton.Plus, R.string.start_pause)) | ||
| 535 | } | ||
| 536 | |||
| 537 | else -> { | ||
| 538 | // No-op | ||
| 539 | } | ||
| 540 | } | ||
| 541 | |||
| 542 | when (styleIndex) { | ||
| 543 | NpadStyleIndex.Fullkey, | ||
| 544 | NpadStyleIndex.Handheld, | ||
| 545 | NpadStyleIndex.JoyconDual, | ||
| 546 | NpadStyleIndex.JoyconLeft -> { | ||
| 547 | add(HeaderSetting(R.string.dpad)) | ||
| 548 | add(ButtonInputSetting(playerIndex, NativeButton.DUp, R.string.up)) | ||
| 549 | add(ButtonInputSetting(playerIndex, NativeButton.DDown, R.string.down)) | ||
| 550 | add(ButtonInputSetting(playerIndex, NativeButton.DLeft, R.string.left)) | ||
| 551 | add(ButtonInputSetting(playerIndex, NativeButton.DRight, R.string.right)) | ||
| 552 | } | ||
| 553 | |||
| 554 | else -> { | ||
| 555 | // No-op | ||
| 556 | } | ||
| 557 | } | ||
| 558 | |||
| 559 | // Left stick | ||
| 560 | when (styleIndex) { | ||
| 561 | NpadStyleIndex.Fullkey, | ||
| 562 | NpadStyleIndex.Handheld, | ||
| 563 | NpadStyleIndex.JoyconDual, | ||
| 564 | NpadStyleIndex.JoyconLeft -> { | ||
| 565 | add(HeaderSetting(R.string.left_stick)) | ||
| 566 | addAll(getStickDirections(playerIndex, NativeAnalog.LStick)) | ||
| 567 | add(ButtonInputSetting(playerIndex, NativeButton.LStick, R.string.pressed)) | ||
| 568 | addAll(getExtraStickSettings(playerIndex, NativeAnalog.LStick)) | ||
| 569 | } | ||
| 570 | |||
| 571 | NpadStyleIndex.GameCube -> { | ||
| 572 | add(HeaderSetting(R.string.control_stick)) | ||
| 573 | addAll(getStickDirections(playerIndex, NativeAnalog.LStick)) | ||
| 574 | addAll(getExtraStickSettings(playerIndex, NativeAnalog.LStick)) | ||
| 575 | } | ||
| 576 | |||
| 577 | else -> { | ||
| 578 | // No-op | ||
| 579 | } | ||
| 580 | } | ||
| 581 | |||
| 582 | // Right stick | ||
| 583 | when (styleIndex) { | ||
| 584 | NpadStyleIndex.Fullkey, | ||
| 585 | NpadStyleIndex.Handheld, | ||
| 586 | NpadStyleIndex.JoyconDual, | ||
| 587 | NpadStyleIndex.JoyconRight -> { | ||
| 588 | add(HeaderSetting(R.string.right_stick)) | ||
| 589 | addAll(getStickDirections(playerIndex, NativeAnalog.RStick)) | ||
| 590 | add(ButtonInputSetting(playerIndex, NativeButton.RStick, R.string.pressed)) | ||
| 591 | addAll(getExtraStickSettings(playerIndex, NativeAnalog.RStick)) | ||
| 592 | } | ||
| 593 | |||
| 594 | NpadStyleIndex.GameCube -> { | ||
| 595 | add(HeaderSetting(R.string.c_stick)) | ||
| 596 | addAll(getStickDirections(playerIndex, NativeAnalog.RStick)) | ||
| 597 | addAll(getExtraStickSettings(playerIndex, NativeAnalog.RStick)) | ||
| 598 | } | ||
| 599 | |||
| 600 | else -> { | ||
| 601 | // No-op | ||
| 602 | } | ||
| 603 | } | ||
| 604 | |||
| 605 | // L/R, ZL/ZR, and SL/SR | ||
| 606 | when (styleIndex) { | ||
| 607 | NpadStyleIndex.Fullkey, | ||
| 608 | NpadStyleIndex.Handheld -> { | ||
| 609 | add(HeaderSetting(R.string.triggers)) | ||
| 610 | add(ButtonInputSetting(playerIndex, NativeButton.L, R.string.button_l)) | ||
| 611 | add(ButtonInputSetting(playerIndex, NativeButton.R, R.string.button_r)) | ||
| 612 | add(ButtonInputSetting(playerIndex, NativeButton.ZL, R.string.button_zl)) | ||
| 613 | add(ButtonInputSetting(playerIndex, NativeButton.ZR, R.string.button_zr)) | ||
| 614 | } | ||
| 615 | |||
| 616 | NpadStyleIndex.JoyconDual -> { | ||
| 617 | add(HeaderSetting(R.string.triggers)) | ||
| 618 | add(ButtonInputSetting(playerIndex, NativeButton.L, R.string.button_l)) | ||
| 619 | add(ButtonInputSetting(playerIndex, NativeButton.R, R.string.button_r)) | ||
| 620 | add(ButtonInputSetting(playerIndex, NativeButton.ZL, R.string.button_zl)) | ||
| 621 | add(ButtonInputSetting(playerIndex, NativeButton.ZR, R.string.button_zr)) | ||
| 622 | add( | ||
| 623 | ButtonInputSetting( | ||
| 624 | playerIndex, | ||
| 625 | NativeButton.SLLeft, | ||
| 626 | R.string.button_sl_left | ||
| 627 | ) | ||
| 628 | ) | ||
| 629 | add( | ||
| 630 | ButtonInputSetting( | ||
| 631 | playerIndex, | ||
| 632 | NativeButton.SRLeft, | ||
| 633 | R.string.button_sr_left | ||
| 634 | ) | ||
| 635 | ) | ||
| 636 | add( | ||
| 637 | ButtonInputSetting( | ||
| 638 | playerIndex, | ||
| 639 | NativeButton.SLRight, | ||
| 640 | R.string.button_sl_right | ||
| 641 | ) | ||
| 642 | ) | ||
| 643 | add( | ||
| 644 | ButtonInputSetting( | ||
| 645 | playerIndex, | ||
| 646 | NativeButton.SRRight, | ||
| 647 | R.string.button_sr_right | ||
| 648 | ) | ||
| 649 | ) | ||
| 650 | } | ||
| 651 | |||
| 652 | NpadStyleIndex.JoyconLeft -> { | ||
| 653 | add(HeaderSetting(R.string.triggers)) | ||
| 654 | add(ButtonInputSetting(playerIndex, NativeButton.L, R.string.button_l)) | ||
| 655 | add(ButtonInputSetting(playerIndex, NativeButton.ZL, R.string.button_zl)) | ||
| 656 | add( | ||
| 657 | ButtonInputSetting( | ||
| 658 | playerIndex, | ||
| 659 | NativeButton.SLLeft, | ||
| 660 | R.string.button_sl_left | ||
| 661 | ) | ||
| 662 | ) | ||
| 663 | add( | ||
| 664 | ButtonInputSetting( | ||
| 665 | playerIndex, | ||
| 666 | NativeButton.SRLeft, | ||
| 667 | R.string.button_sr_left | ||
| 668 | ) | ||
| 669 | ) | ||
| 670 | } | ||
| 671 | |||
| 672 | NpadStyleIndex.JoyconRight -> { | ||
| 673 | add(HeaderSetting(R.string.triggers)) | ||
| 674 | add(ButtonInputSetting(playerIndex, NativeButton.R, R.string.button_r)) | ||
| 675 | add(ButtonInputSetting(playerIndex, NativeButton.ZR, R.string.button_zr)) | ||
| 676 | add( | ||
| 677 | ButtonInputSetting( | ||
| 678 | playerIndex, | ||
| 679 | NativeButton.SLRight, | ||
| 680 | R.string.button_sl_right | ||
| 681 | ) | ||
| 682 | ) | ||
| 683 | add( | ||
| 684 | ButtonInputSetting( | ||
| 685 | playerIndex, | ||
| 686 | NativeButton.SRRight, | ||
| 687 | R.string.button_sr_right | ||
| 688 | ) | ||
| 689 | ) | ||
| 690 | } | ||
| 691 | |||
| 692 | NpadStyleIndex.GameCube -> { | ||
| 693 | add(HeaderSetting(R.string.triggers)) | ||
| 694 | add(ButtonInputSetting(playerIndex, NativeButton.R, R.string.button_z)) | ||
| 695 | add(ButtonInputSetting(playerIndex, NativeButton.ZL, R.string.button_l)) | ||
| 696 | add(ButtonInputSetting(playerIndex, NativeButton.ZR, R.string.button_r)) | ||
| 697 | } | ||
| 698 | |||
| 699 | else -> { | ||
| 700 | // No-op | ||
| 701 | } | ||
| 702 | } | ||
| 703 | |||
| 704 | add(HeaderSetting(R.string.vibration)) | ||
| 705 | val vibrationEnabledSetting = object : AbstractBooleanSetting { | ||
| 706 | override val key = "vibration" | ||
| 707 | |||
| 708 | override fun getBoolean(needsGlobal: Boolean): Boolean = | ||
| 709 | NativeConfig.getInputSettings(true)[playerIndex].vibrationEnabled | ||
| 710 | |||
| 711 | override fun setBoolean(value: Boolean) { | ||
| 712 | val settings = NativeConfig.getInputSettings(true) | ||
| 713 | settings[playerIndex].vibrationEnabled = value | ||
| 714 | NativeConfig.setInputSettings(settings, true) | ||
| 715 | } | ||
| 716 | |||
| 717 | override val defaultValue = true | ||
| 718 | |||
| 719 | override fun getValueAsString(needsGlobal: Boolean): String = | ||
| 720 | getBoolean(needsGlobal).toString() | ||
| 721 | |||
| 722 | override fun reset() = setBoolean(defaultValue) | ||
| 723 | } | ||
| 724 | add(SwitchSetting(vibrationEnabledSetting, R.string.vibration)) | ||
| 725 | |||
| 726 | val useSystemVibratorSetting = object : AbstractBooleanSetting { | ||
| 727 | override val key = "" | ||
| 728 | |||
| 729 | override fun getBoolean(needsGlobal: Boolean): Boolean = | ||
| 730 | NativeConfig.getInputSettings(true)[playerIndex].useSystemVibrator | ||
| 731 | |||
| 732 | override fun setBoolean(value: Boolean) { | ||
| 733 | val settings = NativeConfig.getInputSettings(true) | ||
| 734 | settings[playerIndex].useSystemVibrator = value | ||
| 735 | NativeConfig.setInputSettings(settings, true) | ||
| 736 | } | ||
| 737 | |||
| 738 | override val defaultValue = playerIndex == 0 | ||
| 739 | |||
| 740 | override fun getValueAsString(needsGlobal: Boolean): String = | ||
| 741 | getBoolean(needsGlobal).toString() | ||
| 742 | |||
| 743 | override fun reset() = setBoolean(defaultValue) | ||
| 744 | |||
| 745 | override val pairedSettingKey: String = "vibration" | ||
| 746 | } | ||
| 747 | addAbstract(SwitchSetting(useSystemVibratorSetting, R.string.use_system_vibrator)) | ||
| 748 | |||
| 749 | val vibrationStrengthSetting = object : AbstractIntSetting { | ||
| 750 | override val key = "" | ||
| 751 | |||
| 752 | override fun getInt(needsGlobal: Boolean): Int = | ||
| 753 | NativeConfig.getInputSettings(true)[playerIndex].vibrationStrength | ||
| 754 | |||
| 755 | override fun setInt(value: Int) { | ||
| 756 | val settings = NativeConfig.getInputSettings(true) | ||
| 757 | settings[playerIndex].vibrationStrength = value | ||
| 758 | NativeConfig.setInputSettings(settings, true) | ||
| 759 | } | ||
| 760 | |||
| 761 | override val defaultValue = 100 | ||
| 762 | |||
| 763 | override fun getValueAsString(needsGlobal: Boolean): String = | ||
| 764 | getInt(needsGlobal).toString() | ||
| 765 | |||
| 766 | override fun reset() = setInt(defaultValue) | ||
| 767 | |||
| 768 | override val pairedSettingKey: String = "vibration" | ||
| 769 | } | ||
| 770 | addAbstract( | ||
| 771 | SliderSetting(vibrationStrengthSetting, R.string.vibration_strength, units = "%") | ||
| 772 | ) | ||
| 773 | } | ||
| 774 | } | ||
| 775 | |||
| 776 | // Convenience function for creating AbstractIntSettings for modifier range/stick range/stick deadzones | ||
| 777 | private fun getStickIntSettingFromParam( | ||
| 778 | playerIndex: Int, | ||
| 779 | paramName: String, | ||
| 780 | stick: NativeAnalog, | ||
| 781 | defaultValue: Int | ||
| 782 | ): AbstractIntSetting = | ||
| 783 | object : AbstractIntSetting { | ||
| 784 | val params get() = NativeInput.getStickParam(playerIndex, stick) | ||
| 785 | |||
| 786 | override val key = "" | ||
| 787 | |||
| 788 | override fun getInt(needsGlobal: Boolean): Int = | ||
| 789 | (params.get(paramName, 0.15f) * 100).toInt() | ||
| 790 | |||
| 791 | override fun setInt(value: Int) { | ||
| 792 | val tempParams = params | ||
| 793 | tempParams.set(paramName, value.toFloat() / 100) | ||
| 794 | NativeInput.setStickParam(playerIndex, stick, tempParams) | ||
| 795 | } | ||
| 796 | |||
| 797 | override val defaultValue = defaultValue | ||
| 798 | |||
| 799 | override fun getValueAsString(needsGlobal: Boolean): String = | ||
| 800 | getInt(needsGlobal).toString() | ||
| 801 | |||
| 802 | override fun reset() = setInt(defaultValue) | ||
| 803 | } | ||
| 804 | |||
| 805 | private fun getExtraStickSettings( | ||
| 806 | playerIndex: Int, | ||
| 807 | nativeAnalog: NativeAnalog | ||
| 808 | ): List<SettingsItem> { | ||
| 809 | val stickIsController = | ||
| 810 | NativeInput.isController(NativeInput.getStickParam(playerIndex, nativeAnalog)) | ||
| 811 | val modifierRangeSetting = | ||
| 812 | getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 50) | ||
| 813 | val stickRangeSetting = | ||
| 814 | getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 95) | ||
| 815 | val stickDeadzoneSetting = | ||
| 816 | getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 15) | ||
| 817 | |||
| 818 | val out = mutableListOf<SettingsItem>().apply { | ||
| 819 | if (stickIsController) { | ||
| 820 | add(SliderSetting(stickRangeSetting, titleId = R.string.range, min = 25, max = 150)) | ||
| 821 | add(SliderSetting(stickDeadzoneSetting, R.string.deadzone)) | ||
| 822 | } else { | ||
| 823 | add(ModifierInputSetting(playerIndex, NativeAnalog.LStick, R.string.modifier)) | ||
| 824 | add(SliderSetting(modifierRangeSetting, R.string.modifier_range)) | ||
| 825 | } | ||
| 826 | } | ||
| 827 | return out | ||
| 828 | } | ||
| 829 | |||
| 830 | private fun getStickDirections(player: Int, stick: NativeAnalog): List<AnalogInputSetting> = | ||
| 831 | listOf( | ||
| 832 | AnalogInputSetting( | ||
| 833 | player, | ||
| 834 | stick, | ||
| 835 | AnalogDirection.Up, | ||
| 836 | R.string.up | ||
| 837 | ), | ||
| 838 | AnalogInputSetting( | ||
| 839 | player, | ||
| 840 | stick, | ||
| 841 | AnalogDirection.Down, | ||
| 842 | R.string.down | ||
| 843 | ), | ||
| 844 | AnalogInputSetting( | ||
| 845 | player, | ||
| 846 | stick, | ||
| 847 | AnalogDirection.Left, | ||
| 848 | R.string.left | ||
| 849 | ), | ||
| 850 | AnalogInputSetting( | ||
| 851 | player, | ||
| 852 | stick, | ||
| 853 | AnalogDirection.Right, | ||
| 854 | R.string.right | ||
| 855 | ) | ||
| 856 | ) | ||
| 857 | |||
| 167 | private fun addThemeSettings(sl: ArrayList<SettingsItem>) { | 858 | private fun addThemeSettings(sl: ArrayList<SettingsItem>) { |
| 168 | sl.apply { | 859 | sl.apply { |
| 169 | val theme: AbstractIntSetting = object : AbstractIntSetting { | 860 | val theme: AbstractIntSetting = object : AbstractIntSetting { |
| @@ -186,20 +877,18 @@ class SettingsFragmentPresenter( | |||
| 186 | add( | 877 | add( |
| 187 | SingleChoiceSetting( | 878 | SingleChoiceSetting( |
| 188 | theme, | 879 | theme, |
| 189 | R.string.change_app_theme, | 880 | titleId = R.string.change_app_theme, |
| 190 | 0, | 881 | choicesId = R.array.themeEntriesA12, |
| 191 | R.array.themeEntriesA12, | 882 | valuesId = R.array.themeValuesA12 |
| 192 | R.array.themeValuesA12 | ||
| 193 | ) | 883 | ) |
| 194 | ) | 884 | ) |
| 195 | } else { | 885 | } else { |
| 196 | add( | 886 | add( |
| 197 | SingleChoiceSetting( | 887 | SingleChoiceSetting( |
| 198 | theme, | 888 | theme, |
| 199 | R.string.change_app_theme, | 889 | titleId = R.string.change_app_theme, |
| 200 | 0, | 890 | choicesId = R.array.themeEntries, |
| 201 | R.array.themeEntries, | 891 | valuesId = R.array.themeValues |
| 202 | R.array.themeValues | ||
| 203 | ) | 892 | ) |
| 204 | ) | 893 | ) |
| 205 | } | 894 | } |
| @@ -228,10 +917,9 @@ class SettingsFragmentPresenter( | |||
| 228 | add( | 917 | add( |
| 229 | SingleChoiceSetting( | 918 | SingleChoiceSetting( |
| 230 | themeMode, | 919 | themeMode, |
| 231 | R.string.change_theme_mode, | 920 | titleId = R.string.change_theme_mode, |
| 232 | 0, | 921 | choicesId = R.array.themeModeEntries, |
| 233 | R.array.themeModeEntries, | 922 | valuesId = R.array.themeModeValues |
| 234 | R.array.themeModeValues | ||
| 235 | ) | 923 | ) |
| 236 | ) | 924 | ) |
| 237 | 925 | ||
| @@ -262,8 +950,8 @@ class SettingsFragmentPresenter( | |||
| 262 | add( | 950 | add( |
| 263 | SwitchSetting( | 951 | SwitchSetting( |
| 264 | blackBackgrounds, | 952 | blackBackgrounds, |
| 265 | R.string.use_black_backgrounds, | 953 | titleId = R.string.use_black_backgrounds, |
| 266 | R.string.use_black_backgrounds_description | 954 | descriptionId = R.string.use_black_backgrounds_description |
| 267 | ) | 955 | ) |
| 268 | ) | 956 | ) |
| 269 | } | 957 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsSearchFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsSearchFragment.kt index a135b80b4..ed60cf34f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsSearchFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsSearchFragment.kt | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.fragments | 4 | package org.yuzu.yuzu_emu.features.settings.ui |
| 5 | 5 | ||
| 6 | import android.content.Context | 6 | import android.content.Context |
| 7 | import android.os.Bundle | 7 | import android.os.Bundle |
| @@ -15,21 +15,17 @@ import androidx.core.view.updatePadding | |||
| 15 | import androidx.core.widget.doOnTextChanged | 15 | import androidx.core.widget.doOnTextChanged |
| 16 | import androidx.fragment.app.Fragment | 16 | import androidx.fragment.app.Fragment |
| 17 | import androidx.fragment.app.activityViewModels | 17 | import androidx.fragment.app.activityViewModels |
| 18 | import androidx.lifecycle.Lifecycle | ||
| 19 | import androidx.lifecycle.lifecycleScope | ||
| 20 | import androidx.lifecycle.repeatOnLifecycle | ||
| 21 | import androidx.recyclerview.widget.LinearLayoutManager | 18 | import androidx.recyclerview.widget.LinearLayoutManager |
| 22 | import com.google.android.material.divider.MaterialDividerItemDecoration | 19 | import com.google.android.material.divider.MaterialDividerItemDecoration |
| 23 | import com.google.android.material.transition.MaterialSharedAxis | 20 | import com.google.android.material.transition.MaterialSharedAxis |
| 24 | import info.debatty.java.stringsimilarity.Cosine | 21 | import info.debatty.java.stringsimilarity.Cosine |
| 25 | import kotlinx.coroutines.launch | ||
| 26 | import org.yuzu.yuzu_emu.R | 22 | import org.yuzu.yuzu_emu.R |
| 27 | import org.yuzu.yuzu_emu.databinding.FragmentSettingsSearchBinding | 23 | import org.yuzu.yuzu_emu.databinding.FragmentSettingsSearchBinding |
| 28 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem | 24 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem |
| 29 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter | ||
| 30 | import org.yuzu.yuzu_emu.model.SettingsViewModel | ||
| 31 | import org.yuzu.yuzu_emu.utils.NativeConfig | 25 | import org.yuzu.yuzu_emu.utils.NativeConfig |
| 26 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 32 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins | 27 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins |
| 28 | import org.yuzu.yuzu_emu.utils.collect | ||
| 33 | 29 | ||
| 34 | class SettingsSearchFragment : Fragment() { | 30 | class SettingsSearchFragment : Fragment() { |
| 35 | private var _binding: FragmentSettingsSearchBinding? = null | 31 | private var _binding: FragmentSettingsSearchBinding? = null |
| @@ -85,14 +81,10 @@ class SettingsSearchFragment : Fragment() { | |||
| 85 | search() | 81 | search() |
| 86 | binding.settingsList.smoothScrollToPosition(0) | 82 | binding.settingsList.smoothScrollToPosition(0) |
| 87 | } | 83 | } |
| 88 | viewLifecycleOwner.lifecycleScope.launch { | 84 | settingsViewModel.shouldReloadSettingsList.collect(viewLifecycleOwner) { |
| 89 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 85 | if (it) { |
| 90 | settingsViewModel.shouldReloadSettingsList.collect { | 86 | settingsViewModel.setShouldReloadSettingsList(false) |
| 91 | if (it) { | 87 | search() |
| 92 | settingsViewModel.setShouldReloadSettingsList(false) | ||
| 93 | search() | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | 88 | } |
| 97 | } | 89 | } |
| 98 | 90 | ||
| @@ -108,10 +100,9 @@ class SettingsSearchFragment : Fragment() { | |||
| 108 | 100 | ||
| 109 | private fun search() { | 101 | private fun search() { |
| 110 | val searchTerm = binding.searchText.text.toString().lowercase() | 102 | val searchTerm = binding.searchText.text.toString().lowercase() |
| 111 | binding.clearButton.visibility = | 103 | binding.clearButton.setVisible(visible = searchTerm.isNotEmpty(), gone = false) |
| 112 | if (searchTerm.isEmpty()) View.INVISIBLE else View.VISIBLE | ||
| 113 | if (searchTerm.isEmpty()) { | 104 | if (searchTerm.isEmpty()) { |
| 114 | binding.noResultsView.visibility = View.VISIBLE | 105 | binding.noResultsView.setVisible(visible = false, gone = false) |
| 115 | settingsAdapter?.submitList(emptyList()) | 106 | settingsAdapter?.submitList(emptyList()) |
| 116 | return | 107 | return |
| 117 | } | 108 | } |
| @@ -119,7 +110,7 @@ class SettingsSearchFragment : Fragment() { | |||
| 119 | val baseList = SettingsItem.settingsItems | 110 | val baseList = SettingsItem.settingsItems |
| 120 | val similarityAlgorithm = if (searchTerm.length > 2) Cosine() else Cosine(1) | 111 | val similarityAlgorithm = if (searchTerm.length > 2) Cosine() else Cosine(1) |
| 121 | val sortedList: List<SettingsItem> = baseList.mapNotNull { item -> | 112 | val sortedList: List<SettingsItem> = baseList.mapNotNull { item -> |
| 122 | val title = getString(item.value.nameId).lowercase() | 113 | val title = item.value.title.lowercase() |
| 123 | val similarity = similarityAlgorithm.similarity(searchTerm, title) | 114 | val similarity = similarityAlgorithm.similarity(searchTerm, title) |
| 124 | if (similarity > 0.08) { | 115 | if (similarity > 0.08) { |
| 125 | Pair(similarity, item) | 116 | Pair(similarity, item) |
| @@ -138,8 +129,7 @@ class SettingsSearchFragment : Fragment() { | |||
| 138 | optionalSetting | 129 | optionalSetting |
| 139 | } | 130 | } |
| 140 | settingsAdapter?.submitList(sortedList) | 131 | settingsAdapter?.submitList(sortedList) |
| 141 | binding.noResultsView.visibility = | 132 | binding.noResultsView.setVisible(visible = sortedList.isEmpty(), gone = false) |
| 142 | if (sortedList.isEmpty()) View.VISIBLE else View.INVISIBLE | ||
| 143 | } | 133 | } |
| 144 | 134 | ||
| 145 | private fun focusSearch() { | 135 | private fun focusSearch() { |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SettingsViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsViewModel.kt index 5cb6a5d57..fbdca04e9 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SettingsViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsViewModel.kt | |||
| @@ -1,20 +1,26 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.model | 4 | package org.yuzu.yuzu_emu.features.settings.ui |
| 5 | 5 | ||
| 6 | import androidx.lifecycle.ViewModel | 6 | import androidx.lifecycle.ViewModel |
| 7 | import kotlinx.coroutines.flow.MutableStateFlow | 7 | import kotlinx.coroutines.flow.MutableStateFlow |
| 8 | import kotlinx.coroutines.flow.StateFlow | 8 | import kotlinx.coroutines.flow.StateFlow |
| 9 | import kotlinx.coroutines.flow.asStateFlow | ||
| 9 | import org.yuzu.yuzu_emu.R | 10 | import org.yuzu.yuzu_emu.R |
| 10 | import org.yuzu.yuzu_emu.YuzuApplication | 11 | import org.yuzu.yuzu_emu.YuzuApplication |
| 11 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem | 12 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem |
| 13 | import org.yuzu.yuzu_emu.model.Game | ||
| 14 | import org.yuzu.yuzu_emu.utils.InputHandler | ||
| 15 | import org.yuzu.yuzu_emu.utils.ParamPackage | ||
| 12 | 16 | ||
| 13 | class SettingsViewModel : ViewModel() { | 17 | class SettingsViewModel : ViewModel() { |
| 14 | var game: Game? = null | 18 | var game: Game? = null |
| 15 | 19 | ||
| 16 | var clickedItem: SettingsItem? = null | 20 | var clickedItem: SettingsItem? = null |
| 17 | 21 | ||
| 22 | var currentDevice = 0 | ||
| 23 | |||
| 18 | val shouldRecreate: StateFlow<Boolean> get() = _shouldRecreate | 24 | val shouldRecreate: StateFlow<Boolean> get() = _shouldRecreate |
| 19 | private val _shouldRecreate = MutableStateFlow(false) | 25 | private val _shouldRecreate = MutableStateFlow(false) |
| 20 | 26 | ||
| @@ -36,6 +42,18 @@ class SettingsViewModel : ViewModel() { | |||
| 36 | val adapterItemChanged: StateFlow<Int> get() = _adapterItemChanged | 42 | val adapterItemChanged: StateFlow<Int> get() = _adapterItemChanged |
| 37 | private val _adapterItemChanged = MutableStateFlow(-1) | 43 | private val _adapterItemChanged = MutableStateFlow(-1) |
| 38 | 44 | ||
| 45 | private val _datasetChanged = MutableStateFlow(false) | ||
| 46 | val datasetChanged = _datasetChanged.asStateFlow() | ||
| 47 | |||
| 48 | private val _reloadListAndNotifyDataset = MutableStateFlow(false) | ||
| 49 | val reloadListAndNotifyDataset = _reloadListAndNotifyDataset.asStateFlow() | ||
| 50 | |||
| 51 | private val _shouldShowDeleteProfileDialog = MutableStateFlow("") | ||
| 52 | val shouldShowDeleteProfileDialog = _shouldShowDeleteProfileDialog.asStateFlow() | ||
| 53 | |||
| 54 | private val _shouldShowResetInputDialog = MutableStateFlow(false) | ||
| 55 | val shouldShowResetInputDialog = _shouldShowResetInputDialog.asStateFlow() | ||
| 56 | |||
| 39 | fun setShouldRecreate(value: Boolean) { | 57 | fun setShouldRecreate(value: Boolean) { |
| 40 | _shouldRecreate.value = value | 58 | _shouldRecreate.value = value |
| 41 | } | 59 | } |
| @@ -68,4 +86,27 @@ class SettingsViewModel : ViewModel() { | |||
| 68 | fun setAdapterItemChanged(value: Int) { | 86 | fun setAdapterItemChanged(value: Int) { |
| 69 | _adapterItemChanged.value = value | 87 | _adapterItemChanged.value = value |
| 70 | } | 88 | } |
| 89 | |||
| 90 | fun setDatasetChanged(value: Boolean) { | ||
| 91 | _datasetChanged.value = value | ||
| 92 | } | ||
| 93 | |||
| 94 | fun setReloadListAndNotifyDataset(value: Boolean) { | ||
| 95 | _reloadListAndNotifyDataset.value = value | ||
| 96 | } | ||
| 97 | |||
| 98 | fun setShouldShowDeleteProfileDialog(profile: String) { | ||
| 99 | _shouldShowDeleteProfileDialog.value = profile | ||
| 100 | } | ||
| 101 | |||
| 102 | fun setShouldShowResetInputDialog(value: Boolean) { | ||
| 103 | _shouldShowResetInputDialog.value = value | ||
| 104 | } | ||
| 105 | |||
| 106 | fun getCurrentDeviceParams(defaultParams: ParamPackage): ParamPackage = | ||
| 107 | try { | ||
| 108 | InputHandler.registeredControllers[currentDevice] | ||
| 109 | } catch (e: IndexOutOfBoundsException) { | ||
| 110 | defaultParams | ||
| 111 | } | ||
| 71 | } | 112 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt index 5ad0899dd..367db7fd2 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt | |||
| @@ -14,6 +14,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting | |||
| 14 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem | 14 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem |
| 15 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter | 15 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter |
| 16 | import org.yuzu.yuzu_emu.utils.NativeConfig | 16 | import org.yuzu.yuzu_emu.utils.NativeConfig |
| 17 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 17 | 18 | ||
| 18 | class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : | 19 | class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : |
| 19 | SettingViewHolder(binding.root, adapter) { | 20 | SettingViewHolder(binding.root, adapter) { |
| @@ -21,28 +22,19 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA | |||
| 21 | 22 | ||
| 22 | override fun bind(item: SettingsItem) { | 23 | override fun bind(item: SettingsItem) { |
| 23 | setting = item as DateTimeSetting | 24 | setting = item as DateTimeSetting |
| 24 | binding.textSettingName.setText(item.nameId) | 25 | binding.textSettingName.text = item.title |
| 25 | if (item.descriptionId != 0) { | 26 | binding.textSettingDescription.setVisible(item.description.isNotEmpty()) |
| 26 | binding.textSettingDescription.setText(item.descriptionId) | 27 | binding.textSettingDescription.text = item.description |
| 27 | binding.textSettingDescription.visibility = View.VISIBLE | 28 | binding.textSettingValue.setVisible(true) |
| 28 | } else { | ||
| 29 | binding.textSettingDescription.visibility = View.GONE | ||
| 30 | } | ||
| 31 | |||
| 32 | binding.textSettingValue.visibility = View.VISIBLE | ||
| 33 | val epochTime = setting.getValue() | 29 | val epochTime = setting.getValue() |
| 34 | val instant = Instant.ofEpochMilli(epochTime * 1000) | 30 | val instant = Instant.ofEpochMilli(epochTime * 1000) |
| 35 | val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC")) | 31 | val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC")) |
| 36 | val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) | 32 | val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) |
| 37 | binding.textSettingValue.text = dateFormatter.format(zonedTime) | 33 | binding.textSettingValue.text = dateFormatter.format(zonedTime) |
| 38 | 34 | ||
| 39 | binding.buttonClear.visibility = if (setting.setting.global || | 35 | binding.buttonClear.setVisible( |
| 40 | !NativeConfig.isPerGameConfigLoaded() | 36 | !setting.setting.global || NativeConfig.isPerGameConfigLoaded() |
| 41 | ) { | 37 | ) |
| 42 | View.GONE | ||
| 43 | } else { | ||
| 44 | View.VISIBLE | ||
| 45 | } | ||
| 46 | binding.buttonClear.setOnClickListener { | 38 | binding.buttonClear.setOnClickListener { |
| 47 | adapter.onClearClick(setting, bindingAdapterPosition) | 39 | adapter.onClearClick(setting, bindingAdapterPosition) |
| 48 | } | 40 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/HeaderViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/HeaderViewHolder.kt index f5bcf705c..0815c36e2 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/HeaderViewHolder.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/HeaderViewHolder.kt | |||
| @@ -16,7 +16,7 @@ class HeaderViewHolder(val binding: ListItemSettingsHeaderBinding, adapter: Sett | |||
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | override fun bind(item: SettingsItem) { | 18 | override fun bind(item: SettingsItem) { |
| 19 | binding.textHeaderName.setText(item.nameId) | 19 | binding.textHeaderName.text = item.title |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | override fun onClick(clicked: View) { | 22 | override fun onClick(clicked: View) { |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/InputProfileViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/InputProfileViewHolder.kt new file mode 100644 index 000000000..86af3a226 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/InputProfileViewHolder.kt | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.ui.viewholder | ||
| 5 | |||
| 6 | import android.view.View | ||
| 7 | import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding | ||
| 8 | import org.yuzu.yuzu_emu.features.settings.model.view.InputProfileSetting | ||
| 9 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem | ||
| 10 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter | ||
| 11 | import org.yuzu.yuzu_emu.R | ||
| 12 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 13 | |||
| 14 | class InputProfileViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : | ||
| 15 | SettingViewHolder(binding.root, adapter) { | ||
| 16 | private lateinit var setting: InputProfileSetting | ||
| 17 | |||
| 18 | override fun bind(item: SettingsItem) { | ||
| 19 | setting = item as InputProfileSetting | ||
| 20 | binding.textSettingName.text = setting.title | ||
| 21 | binding.textSettingValue.text = | ||
| 22 | setting.getCurrentProfile().ifEmpty { binding.root.context.getString(R.string.not_set) } | ||
| 23 | |||
| 24 | binding.textSettingDescription.setVisible(false) | ||
| 25 | binding.buttonClear.setVisible(false) | ||
| 26 | binding.icon.setVisible(false) | ||
| 27 | binding.buttonClear.setVisible(false) | ||
| 28 | } | ||
| 29 | |||
| 30 | override fun onClick(clicked: View) = | ||
| 31 | adapter.onInputProfileClick(setting, bindingAdapterPosition) | ||
| 32 | |||
| 33 | override fun onLongClick(clicked: View): Boolean = false | ||
| 34 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/InputViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/InputViewHolder.kt new file mode 100644 index 000000000..9d9047804 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/InputViewHolder.kt | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.ui.viewholder | ||
| 5 | |||
| 6 | import android.view.View | ||
| 7 | import org.yuzu.yuzu_emu.databinding.ListItemSettingInputBinding | ||
| 8 | import org.yuzu.yuzu_emu.features.input.NativeInput | ||
| 9 | import org.yuzu.yuzu_emu.features.settings.model.view.AnalogInputSetting | ||
| 10 | import org.yuzu.yuzu_emu.features.settings.model.view.ButtonInputSetting | ||
| 11 | import org.yuzu.yuzu_emu.features.settings.model.view.InputSetting | ||
| 12 | import org.yuzu.yuzu_emu.features.settings.model.view.ModifierInputSetting | ||
| 13 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem | ||
| 14 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter | ||
| 15 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 16 | |||
| 17 | class InputViewHolder(val binding: ListItemSettingInputBinding, adapter: SettingsAdapter) : | ||
| 18 | SettingViewHolder(binding.root, adapter) { | ||
| 19 | private lateinit var setting: InputSetting | ||
| 20 | |||
| 21 | override fun bind(item: SettingsItem) { | ||
| 22 | setting = item as InputSetting | ||
| 23 | binding.textSettingName.text = setting.title | ||
| 24 | binding.textSettingValue.text = setting.getSelectedValue() | ||
| 25 | |||
| 26 | when (item) { | ||
| 27 | is AnalogInputSetting -> { | ||
| 28 | val param = NativeInput.getStickParam(item.playerIndex, item.nativeAnalog) | ||
| 29 | binding.buttonOptions.setVisible( | ||
| 30 | param.get("engine", "") == "analog_from_button" || | ||
| 31 | param.has("axis_x") || param.has("axis_y") | ||
| 32 | ) | ||
| 33 | } | ||
| 34 | |||
| 35 | is ButtonInputSetting -> { | ||
| 36 | val param = NativeInput.getButtonParam(item.playerIndex, item.nativeButton) | ||
| 37 | binding.buttonOptions.setVisible( | ||
| 38 | param.has("code") || param.has("button") || param.has("hat") || | ||
| 39 | param.has("axis") | ||
| 40 | ) | ||
| 41 | } | ||
| 42 | |||
| 43 | is ModifierInputSetting -> { | ||
| 44 | val params = NativeInput.getStickParam(item.playerIndex, item.nativeAnalog) | ||
| 45 | binding.buttonOptions.setVisible(params.has("modifier")) | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | binding.buttonOptions.setOnClickListener(null) | ||
| 50 | binding.buttonOptions.setOnClickListener { | ||
| 51 | adapter.onInputOptionsClick(binding.buttonOptions, setting, bindingAdapterPosition) | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | override fun onClick(clicked: View) = | ||
| 56 | adapter.onInputClick(setting, bindingAdapterPosition) | ||
| 57 | |||
| 58 | override fun onLongClick(clicked: View): Boolean = | ||
| 59 | adapter.onLongClick(setting, bindingAdapterPosition) | ||
| 60 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/RunnableViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/RunnableViewHolder.kt index 507184238..fc2ffb515 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/RunnableViewHolder.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/RunnableViewHolder.kt | |||
| @@ -5,11 +5,11 @@ package org.yuzu.yuzu_emu.features.settings.ui.viewholder | |||
| 5 | 5 | ||
| 6 | import android.view.View | 6 | import android.view.View |
| 7 | import androidx.core.content.res.ResourcesCompat | 7 | import androidx.core.content.res.ResourcesCompat |
| 8 | import org.yuzu.yuzu_emu.NativeLibrary | ||
| 9 | import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding | 8 | import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding |
| 10 | import org.yuzu.yuzu_emu.features.settings.model.view.RunnableSetting | 9 | import org.yuzu.yuzu_emu.features.settings.model.view.RunnableSetting |
| 11 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem | 10 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem |
| 12 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter | 11 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter |
| 12 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 13 | 13 | ||
| 14 | class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : | 14 | class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : |
| 15 | SettingViewHolder(binding.root, adapter) { | 15 | SettingViewHolder(binding.root, adapter) { |
| @@ -17,34 +17,28 @@ class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA | |||
| 17 | 17 | ||
| 18 | override fun bind(item: SettingsItem) { | 18 | override fun bind(item: SettingsItem) { |
| 19 | setting = item as RunnableSetting | 19 | setting = item as RunnableSetting |
| 20 | if (item.iconId != 0) { | 20 | binding.icon.setVisible(setting.iconId != 0) |
| 21 | binding.icon.visibility = View.VISIBLE | 21 | if (setting.iconId != 0) { |
| 22 | binding.icon.setImageDrawable( | 22 | binding.icon.setImageDrawable( |
| 23 | ResourcesCompat.getDrawable( | 23 | ResourcesCompat.getDrawable( |
| 24 | binding.icon.resources, | 24 | binding.icon.resources, |
| 25 | item.iconId, | 25 | setting.iconId, |
| 26 | binding.icon.context.theme | 26 | binding.icon.context.theme |
| 27 | ) | 27 | ) |
| 28 | ) | 28 | ) |
| 29 | } else { | ||
| 30 | binding.icon.visibility = View.GONE | ||
| 31 | } | 29 | } |
| 32 | 30 | ||
| 33 | binding.textSettingName.setText(item.nameId) | 31 | binding.textSettingName.text = setting.title |
| 34 | if (item.descriptionId != 0) { | 32 | binding.textSettingDescription.setVisible(setting.description.isNotEmpty()) |
| 35 | binding.textSettingDescription.setText(item.descriptionId) | 33 | binding.textSettingDescription.text = item.description |
| 36 | binding.textSettingDescription.visibility = View.VISIBLE | 34 | binding.textSettingValue.setVisible(false) |
| 37 | } else { | 35 | binding.buttonClear.setVisible(false) |
| 38 | binding.textSettingDescription.visibility = View.GONE | ||
| 39 | } | ||
| 40 | binding.textSettingValue.visibility = View.GONE | ||
| 41 | binding.buttonClear.visibility = View.GONE | ||
| 42 | 36 | ||
| 43 | setStyle(setting.isEditable, binding) | 37 | setStyle(setting.isEditable, binding) |
| 44 | } | 38 | } |
| 45 | 39 | ||
| 46 | override fun onClick(clicked: View) { | 40 | override fun onClick(clicked: View) { |
| 47 | if (!setting.isRuntimeRunnable && !NativeLibrary.isRunning()) { | 41 | if (setting.isRunnable) { |
| 48 | setting.runnable.invoke() | 42 | setting.runnable.invoke() |
| 49 | } | 43 | } |
| 50 | } | 44 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt index 02dab3785..e2fe0b072 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt | |||
| @@ -5,11 +5,13 @@ package org.yuzu.yuzu_emu.features.settings.ui.viewholder | |||
| 5 | 5 | ||
| 6 | import android.view.View | 6 | import android.view.View |
| 7 | import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding | 7 | import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding |
| 8 | import org.yuzu.yuzu_emu.features.settings.model.view.IntSingleChoiceSetting | ||
| 8 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem | 9 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem |
| 9 | import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting | 10 | import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting |
| 10 | import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting | 11 | import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting |
| 11 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter | 12 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter |
| 12 | import org.yuzu.yuzu_emu.utils.NativeConfig | 13 | import org.yuzu.yuzu_emu.utils.NativeConfig |
| 14 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 13 | 15 | ||
| 14 | class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : | 16 | class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : |
| 15 | SettingViewHolder(binding.root, adapter) { | 17 | SettingViewHolder(binding.root, adapter) { |
| @@ -17,40 +19,38 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti | |||
| 17 | 19 | ||
| 18 | override fun bind(item: SettingsItem) { | 20 | override fun bind(item: SettingsItem) { |
| 19 | setting = item | 21 | setting = item |
| 20 | binding.textSettingName.setText(item.nameId) | 22 | binding.textSettingName.text = setting.title |
| 21 | if (item.descriptionId != 0) { | 23 | binding.textSettingDescription.setVisible(item.description.isNotEmpty()) |
| 22 | binding.textSettingDescription.setText(item.descriptionId) | 24 | binding.textSettingDescription.text = item.description |
| 23 | binding.textSettingDescription.visibility = View.VISIBLE | ||
| 24 | } else { | ||
| 25 | binding.textSettingDescription.visibility = View.GONE | ||
| 26 | } | ||
| 27 | 25 | ||
| 28 | binding.textSettingValue.visibility = View.VISIBLE | 26 | binding.textSettingValue.setVisible(true) |
| 29 | if (item is SingleChoiceSetting) { | 27 | when (item) { |
| 30 | val resMgr = binding.textSettingValue.context.resources | 28 | is SingleChoiceSetting -> { |
| 31 | val values = resMgr.getIntArray(item.valuesId) | 29 | val resMgr = binding.textSettingValue.context.resources |
| 32 | for (i in values.indices) { | 30 | val values = resMgr.getIntArray(item.valuesId) |
| 33 | if (values[i] == item.getSelectedValue()) { | 31 | for (i in values.indices) { |
| 34 | binding.textSettingValue.text = resMgr.getStringArray(item.choicesId)[i] | 32 | if (values[i] == item.getSelectedValue()) { |
| 35 | break | 33 | binding.textSettingValue.text = resMgr.getStringArray(item.choicesId)[i] |
| 34 | break | ||
| 35 | } | ||
| 36 | } | 36 | } |
| 37 | } | 37 | } |
| 38 | } else if (item is StringSingleChoiceSetting) { | 38 | |
| 39 | for (i in item.values.indices) { | 39 | is StringSingleChoiceSetting -> { |
| 40 | if (item.values[i] == item.getSelectedValue()) { | 40 | binding.textSettingValue.text = item.getSelectedValue() |
| 41 | binding.textSettingValue.text = item.choices[i] | ||
| 42 | break | ||
| 43 | } | ||
| 44 | } | 41 | } |
| 45 | } | ||
| 46 | 42 | ||
| 47 | binding.buttonClear.visibility = if (setting.setting.global || | 43 | is IntSingleChoiceSetting -> { |
| 48 | !NativeConfig.isPerGameConfigLoaded() | 44 | binding.textSettingValue.text = item.getChoiceAt(item.getSelectedValue()) |
| 49 | ) { | 45 | } |
| 50 | View.GONE | 46 | } |
| 51 | } else { | 47 | if (binding.textSettingValue.text.isEmpty()) { |
| 52 | View.VISIBLE | 48 | binding.textSettingValue.setVisible(false) |
| 53 | } | 49 | } |
| 50 | |||
| 51 | binding.buttonClear.setVisible( | ||
| 52 | !setting.setting.global || NativeConfig.isPerGameConfigLoaded() | ||
| 53 | ) | ||
| 54 | binding.buttonClear.setOnClickListener { | 54 | binding.buttonClear.setOnClickListener { |
| 55 | adapter.onClearClick(setting, bindingAdapterPosition) | 55 | adapter.onClearClick(setting, bindingAdapterPosition) |
| 56 | } | 56 | } |
| @@ -63,16 +63,25 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti | |||
| 63 | return | 63 | return |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | if (setting is SingleChoiceSetting) { | 66 | when (setting) { |
| 67 | adapter.onSingleChoiceClick( | 67 | is SingleChoiceSetting -> adapter.onSingleChoiceClick( |
| 68 | (setting as SingleChoiceSetting), | 68 | setting as SingleChoiceSetting, |
| 69 | bindingAdapterPosition | ||
| 70 | ) | ||
| 71 | } else if (setting is StringSingleChoiceSetting) { | ||
| 72 | adapter.onStringSingleChoiceClick( | ||
| 73 | (setting as StringSingleChoiceSetting), | ||
| 74 | bindingAdapterPosition | 69 | bindingAdapterPosition |
| 75 | ) | 70 | ) |
| 71 | |||
| 72 | is StringSingleChoiceSetting -> { | ||
| 73 | adapter.onStringSingleChoiceClick( | ||
| 74 | setting as StringSingleChoiceSetting, | ||
| 75 | bindingAdapterPosition | ||
| 76 | ) | ||
| 77 | } | ||
| 78 | |||
| 79 | is IntSingleChoiceSetting -> { | ||
| 80 | adapter.onIntSingleChoiceClick( | ||
| 81 | setting as IntSingleChoiceSetting, | ||
| 82 | bindingAdapterPosition | ||
| 83 | ) | ||
| 84 | } | ||
| 76 | } | 85 | } |
| 77 | } | 86 | } |
| 78 | 87 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt index 596c18012..a37b59b44 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt | |||
| @@ -10,6 +10,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem | |||
| 10 | import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting | 10 | import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting |
| 11 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter | 11 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter |
| 12 | import org.yuzu.yuzu_emu.utils.NativeConfig | 12 | import org.yuzu.yuzu_emu.utils.NativeConfig |
| 13 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 13 | 14 | ||
| 14 | class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : | 15 | class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : |
| 15 | SettingViewHolder(binding.root, adapter) { | 16 | SettingViewHolder(binding.root, adapter) { |
| @@ -17,27 +18,19 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda | |||
| 17 | 18 | ||
| 18 | override fun bind(item: SettingsItem) { | 19 | override fun bind(item: SettingsItem) { |
| 19 | setting = item as SliderSetting | 20 | setting = item as SliderSetting |
| 20 | binding.textSettingName.setText(item.nameId) | 21 | binding.textSettingName.text = setting.title |
| 21 | if (item.descriptionId != 0) { | 22 | binding.textSettingDescription.setVisible(item.description.isNotEmpty()) |
| 22 | binding.textSettingDescription.setText(item.descriptionId) | 23 | binding.textSettingDescription.text = setting.description |
| 23 | binding.textSettingDescription.visibility = View.VISIBLE | 24 | binding.textSettingValue.setVisible(true) |
| 24 | } else { | ||
| 25 | binding.textSettingDescription.visibility = View.GONE | ||
| 26 | } | ||
| 27 | binding.textSettingValue.visibility = View.VISIBLE | ||
| 28 | binding.textSettingValue.text = String.format( | 25 | binding.textSettingValue.text = String.format( |
| 29 | binding.textSettingValue.context.getString(R.string.value_with_units), | 26 | binding.textSettingValue.context.getString(R.string.value_with_units), |
| 30 | setting.getSelectedValue(), | 27 | setting.getSelectedValue(), |
| 31 | setting.units | 28 | setting.units |
| 32 | ) | 29 | ) |
| 33 | 30 | ||
| 34 | binding.buttonClear.visibility = if (setting.setting.global || | 31 | binding.buttonClear.setVisible( |
| 35 | !NativeConfig.isPerGameConfigLoaded() | 32 | !setting.setting.global || NativeConfig.isPerGameConfigLoaded() |
| 36 | ) { | 33 | ) |
| 37 | View.GONE | ||
| 38 | } else { | ||
| 39 | View.VISIBLE | ||
| 40 | } | ||
| 41 | binding.buttonClear.setOnClickListener { | 34 | binding.buttonClear.setOnClickListener { |
| 42 | adapter.onClearClick(setting, bindingAdapterPosition) | 35 | adapter.onClearClick(setting, bindingAdapterPosition) |
| 43 | } | 36 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SubmenuViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SubmenuViewHolder.kt index 20d35a17d..f7a9c08c3 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SubmenuViewHolder.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SubmenuViewHolder.kt | |||
| @@ -9,39 +9,34 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding | |||
| 9 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem | 9 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem |
| 10 | import org.yuzu.yuzu_emu.features.settings.model.view.SubmenuSetting | 10 | import org.yuzu.yuzu_emu.features.settings.model.view.SubmenuSetting |
| 11 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter | 11 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter |
| 12 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 12 | 13 | ||
| 13 | class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : | 14 | class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : |
| 14 | SettingViewHolder(binding.root, adapter) { | 15 | SettingViewHolder(binding.root, adapter) { |
| 15 | private lateinit var item: SubmenuSetting | 16 | private lateinit var setting: SubmenuSetting |
| 16 | 17 | ||
| 17 | override fun bind(item: SettingsItem) { | 18 | override fun bind(item: SettingsItem) { |
| 18 | this.item = item as SubmenuSetting | 19 | setting = item as SubmenuSetting |
| 19 | if (item.iconId != 0) { | 20 | binding.icon.setVisible(setting.iconId != 0) |
| 20 | binding.icon.visibility = View.VISIBLE | 21 | if (setting.iconId != 0) { |
| 21 | binding.icon.setImageDrawable( | 22 | binding.icon.setImageDrawable( |
| 22 | ResourcesCompat.getDrawable( | 23 | ResourcesCompat.getDrawable( |
| 23 | binding.icon.resources, | 24 | binding.icon.resources, |
| 24 | item.iconId, | 25 | setting.iconId, |
| 25 | binding.icon.context.theme | 26 | binding.icon.context.theme |
| 26 | ) | 27 | ) |
| 27 | ) | 28 | ) |
| 28 | } else { | ||
| 29 | binding.icon.visibility = View.GONE | ||
| 30 | } | 29 | } |
| 31 | 30 | ||
| 32 | binding.textSettingName.setText(item.nameId) | 31 | binding.textSettingName.text = setting.title |
| 33 | if (item.descriptionId != 0) { | 32 | binding.textSettingDescription.setVisible(setting.description.isNotEmpty()) |
| 34 | binding.textSettingDescription.setText(item.descriptionId) | 33 | binding.textSettingDescription.text = setting.description |
| 35 | binding.textSettingDescription.visibility = View.VISIBLE | 34 | binding.textSettingValue.setVisible(false) |
| 36 | } else { | 35 | binding.buttonClear.setVisible(false) |
| 37 | binding.textSettingDescription.visibility = View.GONE | ||
| 38 | } | ||
| 39 | binding.textSettingValue.visibility = View.GONE | ||
| 40 | binding.buttonClear.visibility = View.GONE | ||
| 41 | } | 36 | } |
| 42 | 37 | ||
| 43 | override fun onClick(clicked: View) { | 38 | override fun onClick(clicked: View) { |
| 44 | adapter.onSubmenuClick(item) | 39 | adapter.onSubmenuClick(setting) |
| 45 | } | 40 | } |
| 46 | 41 | ||
| 47 | override fun onLongClick(clicked: View): Boolean { | 42 | override fun onLongClick(clicked: View): Boolean { |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt index d26bf9374..53f7b301f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt | |||
| @@ -10,6 +10,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem | |||
| 10 | import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting | 10 | import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting |
| 11 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter | 11 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter |
| 12 | import org.yuzu.yuzu_emu.utils.NativeConfig | 12 | import org.yuzu.yuzu_emu.utils.NativeConfig |
| 13 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 13 | 14 | ||
| 14 | class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) : | 15 | class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) : |
| 15 | SettingViewHolder(binding.root, adapter) { | 16 | SettingViewHolder(binding.root, adapter) { |
| @@ -18,28 +19,19 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter | |||
| 18 | 19 | ||
| 19 | override fun bind(item: SettingsItem) { | 20 | override fun bind(item: SettingsItem) { |
| 20 | setting = item as SwitchSetting | 21 | setting = item as SwitchSetting |
| 21 | binding.textSettingName.setText(item.nameId) | 22 | binding.textSettingName.text = setting.title |
| 22 | if (item.descriptionId != 0) { | 23 | binding.textSettingDescription.setVisible(setting.description.isNotEmpty()) |
| 23 | binding.textSettingDescription.setText(item.descriptionId) | 24 | binding.textSettingDescription.text = setting.description |
| 24 | binding.textSettingDescription.visibility = View.VISIBLE | ||
| 25 | } else { | ||
| 26 | binding.textSettingDescription.text = "" | ||
| 27 | binding.textSettingDescription.visibility = View.GONE | ||
| 28 | } | ||
| 29 | 25 | ||
| 30 | binding.switchWidget.setOnCheckedChangeListener(null) | 26 | binding.switchWidget.setOnCheckedChangeListener(null) |
| 31 | binding.switchWidget.isChecked = setting.getIsChecked(setting.needsRuntimeGlobal) | 27 | binding.switchWidget.isChecked = setting.getIsChecked(setting.needsRuntimeGlobal) |
| 32 | binding.switchWidget.setOnCheckedChangeListener { _: CompoundButton, _: Boolean -> | 28 | binding.switchWidget.setOnCheckedChangeListener { _: CompoundButton, _: Boolean -> |
| 33 | adapter.onBooleanClick(item, binding.switchWidget.isChecked, bindingAdapterPosition) | 29 | adapter.onBooleanClick(setting, binding.switchWidget.isChecked, bindingAdapterPosition) |
| 34 | } | 30 | } |
| 35 | 31 | ||
| 36 | binding.buttonClear.visibility = if (setting.setting.global || | 32 | binding.buttonClear.setVisible( |
| 37 | !NativeConfig.isPerGameConfigLoaded() | 33 | !setting.setting.global || NativeConfig.isPerGameConfigLoaded() |
| 38 | ) { | 34 | ) |
| 39 | View.GONE | ||
| 40 | } else { | ||
| 41 | View.VISIBLE | ||
| 42 | } | ||
| 43 | binding.buttonClear.setOnClickListener { | 35 | binding.buttonClear.setOnClickListener { |
| 44 | adapter.onClearClick(setting, bindingAdapterPosition) | 36 | adapter.onClearClick(setting, bindingAdapterPosition) |
| 45 | } | 37 | } |
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 872553ac4..110aa2960 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 | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.fragments | 4 | package org.yuzu.yuzu_emu.fragments |
| 5 | 5 | ||
| 6 | import android.annotation.SuppressLint | ||
| 7 | import android.content.Intent | 6 | import android.content.Intent |
| 8 | import android.os.Bundle | 7 | import android.os.Bundle |
| 9 | import android.view.LayoutInflater | 8 | import android.view.LayoutInflater |
| @@ -16,9 +15,6 @@ import androidx.core.view.updatePadding | |||
| 16 | import androidx.documentfile.provider.DocumentFile | 15 | import androidx.documentfile.provider.DocumentFile |
| 17 | import androidx.fragment.app.Fragment | 16 | import androidx.fragment.app.Fragment |
| 18 | import androidx.fragment.app.activityViewModels | 17 | import androidx.fragment.app.activityViewModels |
| 19 | import androidx.lifecycle.Lifecycle | ||
| 20 | import androidx.lifecycle.lifecycleScope | ||
| 21 | import androidx.lifecycle.repeatOnLifecycle | ||
| 22 | import androidx.navigation.findNavController | 18 | import androidx.navigation.findNavController |
| 23 | import androidx.navigation.fragment.navArgs | 19 | import androidx.navigation.fragment.navArgs |
| 24 | import androidx.recyclerview.widget.LinearLayoutManager | 20 | import androidx.recyclerview.widget.LinearLayoutManager |
| @@ -32,6 +28,7 @@ import org.yuzu.yuzu_emu.model.HomeViewModel | |||
| 32 | import org.yuzu.yuzu_emu.utils.AddonUtil | 28 | import org.yuzu.yuzu_emu.utils.AddonUtil |
| 33 | import org.yuzu.yuzu_emu.utils.FileUtil.copyFilesTo | 29 | import org.yuzu.yuzu_emu.utils.FileUtil.copyFilesTo |
| 34 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins | 30 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins |
| 31 | import org.yuzu.yuzu_emu.utils.collect | ||
| 35 | import java.io.File | 32 | import java.io.File |
| 36 | 33 | ||
| 37 | class AddonsFragment : Fragment() { | 34 | class AddonsFragment : Fragment() { |
| @@ -60,8 +57,6 @@ class AddonsFragment : Fragment() { | |||
| 60 | return binding.root | 57 | return binding.root |
| 61 | } | 58 | } |
| 62 | 59 | ||
| 63 | // This is using the correct scope, lint is just acting up | ||
| 64 | @SuppressLint("UnsafeRepeatOnLifecycleDetector") | ||
| 65 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | 60 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| 66 | super.onViewCreated(view, savedInstanceState) | 61 | super.onViewCreated(view, savedInstanceState) |
| 67 | homeViewModel.setNavigationVisibility(visible = false, animated = false) | 62 | homeViewModel.setNavigationVisibility(visible = false, animated = false) |
| @@ -78,57 +73,41 @@ class AddonsFragment : Fragment() { | |||
| 78 | adapter = AddonAdapter(addonViewModel) | 73 | adapter = AddonAdapter(addonViewModel) |
| 79 | } | 74 | } |
| 80 | 75 | ||
| 81 | viewLifecycleOwner.lifecycleScope.apply { | 76 | addonViewModel.addonList.collect(viewLifecycleOwner) { |
| 82 | launch { | 77 | (binding.listAddons.adapter as AddonAdapter).submitList(it) |
| 83 | repeatOnLifecycle(Lifecycle.State.STARTED) { | 78 | } |
| 84 | addonViewModel.addonList.collect { | 79 | addonViewModel.showModInstallPicker.collect( |
| 85 | (binding.listAddons.adapter as AddonAdapter).submitList(it) | 80 | viewLifecycleOwner, |
| 86 | } | 81 | resetState = { addonViewModel.showModInstallPicker(false) } |
| 87 | } | 82 | ) { if (it) installAddon.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data) } |
| 88 | } | 83 | addonViewModel.showModNoticeDialog.collect( |
| 89 | launch { | 84 | viewLifecycleOwner, |
| 90 | repeatOnLifecycle(Lifecycle.State.STARTED) { | 85 | resetState = { addonViewModel.showModNoticeDialog(false) } |
| 91 | addonViewModel.showModInstallPicker.collect { | 86 | ) { |
| 92 | if (it) { | 87 | if (it) { |
| 93 | installAddon.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data) | 88 | MessageDialogFragment.newInstance( |
| 94 | addonViewModel.showModInstallPicker(false) | 89 | requireActivity(), |
| 95 | } | 90 | titleId = R.string.addon_notice, |
| 96 | } | 91 | descriptionId = R.string.addon_notice_description, |
| 97 | } | 92 | dismissible = false, |
| 98 | } | 93 | positiveAction = { addonViewModel.showModInstallPicker(true) }, |
| 99 | launch { | 94 | negativeAction = {}, |
| 100 | repeatOnLifecycle(Lifecycle.State.STARTED) { | 95 | negativeButtonTitleId = R.string.close |
| 101 | addonViewModel.showModNoticeDialog.collect { | 96 | ).show(parentFragmentManager, MessageDialogFragment.TAG) |
| 102 | if (it) { | ||
| 103 | MessageDialogFragment.newInstance( | ||
| 104 | requireActivity(), | ||
| 105 | titleId = R.string.addon_notice, | ||
| 106 | descriptionId = R.string.addon_notice_description, | ||
| 107 | dismissible = false, | ||
| 108 | positiveAction = { addonViewModel.showModInstallPicker(true) }, | ||
| 109 | negativeAction = {}, | ||
| 110 | negativeButtonTitleId = R.string.close | ||
| 111 | ).show(parentFragmentManager, MessageDialogFragment.TAG) | ||
| 112 | addonViewModel.showModNoticeDialog(false) | ||
| 113 | } | ||
| 114 | } | ||
| 115 | } | ||
| 116 | } | 97 | } |
| 117 | launch { | 98 | } |
| 118 | repeatOnLifecycle(Lifecycle.State.STARTED) { | 99 | addonViewModel.addonToDelete.collect( |
| 119 | addonViewModel.addonToDelete.collect { | 100 | viewLifecycleOwner, |
| 120 | if (it != null) { | 101 | resetState = { addonViewModel.setAddonToDelete(null) } |
| 121 | MessageDialogFragment.newInstance( | 102 | ) { |
| 122 | requireActivity(), | 103 | if (it != null) { |
| 123 | titleId = R.string.confirm_uninstall, | 104 | MessageDialogFragment.newInstance( |
| 124 | descriptionId = R.string.confirm_uninstall_description, | 105 | requireActivity(), |
| 125 | positiveAction = { addonViewModel.onDeleteAddon(it) }, | 106 | titleId = R.string.confirm_uninstall, |
| 126 | negativeAction = {} | 107 | descriptionId = R.string.confirm_uninstall_description, |
| 127 | ).show(parentFragmentManager, MessageDialogFragment.TAG) | 108 | positiveAction = { addonViewModel.onDeleteAddon(it) }, |
| 128 | addonViewModel.setAddonToDelete(null) | 109 | negativeAction = {} |
| 129 | } | 110 | ).show(parentFragmentManager, MessageDialogFragment.TAG) |
| 130 | } | ||
| 131 | } | ||
| 132 | } | 111 | } |
| 133 | } | 112 | } |
| 134 | 113 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/CoreErrorDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/CoreErrorDialogFragment.kt new file mode 100644 index 000000000..299f8da71 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/CoreErrorDialogFragment.kt | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.fragments | ||
| 5 | |||
| 6 | import android.app.Dialog | ||
| 7 | import android.content.DialogInterface | ||
| 8 | import android.os.Bundle | ||
| 9 | import androidx.fragment.app.DialogFragment | ||
| 10 | import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||
| 11 | import org.yuzu.yuzu_emu.NativeLibrary | ||
| 12 | import org.yuzu.yuzu_emu.R | ||
| 13 | |||
| 14 | class CoreErrorDialogFragment : DialogFragment() { | ||
| 15 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = | ||
| 16 | MaterialAlertDialogBuilder(requireActivity()) | ||
| 17 | .setTitle(requireArguments().getString(TITLE)) | ||
| 18 | .setMessage(requireArguments().getString(MESSAGE)) | ||
| 19 | .setPositiveButton(R.string.continue_button, null) | ||
| 20 | .setNegativeButton(R.string.abort_button) { _: DialogInterface?, _: Int -> | ||
| 21 | NativeLibrary.coreErrorAlertResult = false | ||
| 22 | synchronized(NativeLibrary.coreErrorAlertLock) { | ||
| 23 | NativeLibrary.coreErrorAlertLock.notify() | ||
| 24 | } | ||
| 25 | } | ||
| 26 | .create() | ||
| 27 | |||
| 28 | override fun onDismiss(dialog: DialogInterface) { | ||
| 29 | super.onDismiss(dialog) | ||
| 30 | NativeLibrary.coreErrorAlertResult = true | ||
| 31 | synchronized(NativeLibrary.coreErrorAlertLock) { NativeLibrary.coreErrorAlertLock.notify() } | ||
| 32 | } | ||
| 33 | |||
| 34 | companion object { | ||
| 35 | const val TITLE = "Title" | ||
| 36 | const val MESSAGE = "Message" | ||
| 37 | |||
| 38 | fun newInstance(title: String, message: String): CoreErrorDialogFragment { | ||
| 39 | val frag = CoreErrorDialogFragment() | ||
| 40 | val args = Bundle() | ||
| 41 | args.putString(TITLE, title) | ||
| 42 | args.putString(MESSAGE, message) | ||
| 43 | frag.arguments = args | ||
| 44 | return frag | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt index 41cff46c1..8b23a1021 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.fragments | 4 | package org.yuzu.yuzu_emu.fragments |
| 5 | 5 | ||
| 6 | import android.annotation.SuppressLint | ||
| 7 | import android.os.Bundle | 6 | import android.os.Bundle |
| 8 | import android.view.LayoutInflater | 7 | import android.view.LayoutInflater |
| 9 | import android.view.View | 8 | import android.view.View |
| @@ -14,9 +13,6 @@ import androidx.core.view.WindowInsetsCompat | |||
| 14 | import androidx.core.view.updatePadding | 13 | import androidx.core.view.updatePadding |
| 15 | import androidx.fragment.app.Fragment | 14 | import androidx.fragment.app.Fragment |
| 16 | import androidx.fragment.app.activityViewModels | 15 | import androidx.fragment.app.activityViewModels |
| 17 | import androidx.lifecycle.Lifecycle | ||
| 18 | import androidx.lifecycle.lifecycleScope | ||
| 19 | import androidx.lifecycle.repeatOnLifecycle | ||
| 20 | import androidx.navigation.findNavController | 16 | import androidx.navigation.findNavController |
| 21 | import androidx.navigation.fragment.navArgs | 17 | import androidx.navigation.fragment.navArgs |
| 22 | import androidx.recyclerview.widget.GridLayoutManager | 18 | import androidx.recyclerview.widget.GridLayoutManager |
| @@ -35,6 +31,7 @@ import org.yuzu.yuzu_emu.utils.FileUtil | |||
| 35 | import org.yuzu.yuzu_emu.utils.GpuDriverHelper | 31 | import org.yuzu.yuzu_emu.utils.GpuDriverHelper |
| 36 | import org.yuzu.yuzu_emu.utils.NativeConfig | 32 | import org.yuzu.yuzu_emu.utils.NativeConfig |
| 37 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins | 33 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins |
| 34 | import org.yuzu.yuzu_emu.utils.collect | ||
| 38 | import java.io.File | 35 | import java.io.File |
| 39 | import java.io.IOException | 36 | import java.io.IOException |
| 40 | 37 | ||
| @@ -63,8 +60,6 @@ class DriverManagerFragment : Fragment() { | |||
| 63 | return binding.root | 60 | return binding.root |
| 64 | } | 61 | } |
| 65 | 62 | ||
| 66 | // This is using the correct scope, lint is just acting up | ||
| 67 | @SuppressLint("UnsafeRepeatOnLifecycleDetector") | ||
| 68 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | 63 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| 69 | super.onViewCreated(view, savedInstanceState) | 64 | super.onViewCreated(view, savedInstanceState) |
| 70 | homeViewModel.setNavigationVisibility(visible = false, animated = true) | 65 | homeViewModel.setNavigationVisibility(visible = false, animated = true) |
| @@ -89,15 +84,8 @@ class DriverManagerFragment : Fragment() { | |||
| 89 | } | 84 | } |
| 90 | } | 85 | } |
| 91 | 86 | ||
| 92 | viewLifecycleOwner.lifecycleScope.apply { | 87 | driverViewModel.showClearButton.collect(viewLifecycleOwner) { |
| 93 | launch { | 88 | binding.toolbarDrivers.menu.findItem(R.id.menu_driver_use_global).isVisible = it |
| 94 | repeatOnLifecycle(Lifecycle.State.STARTED) { | ||
| 95 | driverViewModel.showClearButton.collect { | ||
| 96 | binding.toolbarDrivers.menu | ||
| 97 | .findItem(R.id.menu_driver_use_global).isVisible = it | ||
| 98 | } | ||
| 99 | } | ||
| 100 | } | ||
| 101 | } | 89 | } |
| 102 | } | 90 | } |
| 103 | 91 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriversLoadingDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriversLoadingDialogFragment.kt index 6a47b29f0..bad56e434 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriversLoadingDialogFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriversLoadingDialogFragment.kt | |||
| @@ -10,14 +10,11 @@ import android.view.View | |||
| 10 | import android.view.ViewGroup | 10 | import android.view.ViewGroup |
| 11 | import androidx.fragment.app.DialogFragment | 11 | import androidx.fragment.app.DialogFragment |
| 12 | import androidx.fragment.app.activityViewModels | 12 | import androidx.fragment.app.activityViewModels |
| 13 | import androidx.lifecycle.Lifecycle | ||
| 14 | import androidx.lifecycle.lifecycleScope | ||
| 15 | import androidx.lifecycle.repeatOnLifecycle | ||
| 16 | import com.google.android.material.dialog.MaterialAlertDialogBuilder | 13 | import com.google.android.material.dialog.MaterialAlertDialogBuilder |
| 17 | import kotlinx.coroutines.launch | ||
| 18 | import org.yuzu.yuzu_emu.R | 14 | import org.yuzu.yuzu_emu.R |
| 19 | import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding | 15 | import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding |
| 20 | import org.yuzu.yuzu_emu.model.DriverViewModel | 16 | import org.yuzu.yuzu_emu.model.DriverViewModel |
| 17 | import org.yuzu.yuzu_emu.utils.collect | ||
| 21 | 18 | ||
| 22 | class DriversLoadingDialogFragment : DialogFragment() { | 19 | class DriversLoadingDialogFragment : DialogFragment() { |
| 23 | private val driverViewModel: DriverViewModel by activityViewModels() | 20 | private val driverViewModel: DriverViewModel by activityViewModels() |
| @@ -44,13 +41,7 @@ class DriversLoadingDialogFragment : DialogFragment() { | |||
| 44 | 41 | ||
| 45 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | 42 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| 46 | super.onViewCreated(view, savedInstanceState) | 43 | super.onViewCreated(view, savedInstanceState) |
| 47 | viewLifecycleOwner.lifecycleScope.apply { | 44 | driverViewModel.isInteractionAllowed.collect(viewLifecycleOwner) { if (it) dismiss() } |
| 48 | launch { | ||
| 49 | repeatOnLifecycle(Lifecycle.State.RESUMED) { | ||
| 50 | driverViewModel.isInteractionAllowed.collect { if (it) dismiss() } | ||
| 51 | } | ||
| 52 | } | ||
| 53 | } | ||
| 54 | } | 45 | } |
| 55 | 46 | ||
| 56 | companion object { | 47 | companion object { |
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 6b25cc525..bcc880e17 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 | |||
| @@ -32,9 +32,6 @@ import androidx.drawerlayout.widget.DrawerLayout | |||
| 32 | import androidx.drawerlayout.widget.DrawerLayout.DrawerListener | 32 | import androidx.drawerlayout.widget.DrawerLayout.DrawerListener |
| 33 | import androidx.fragment.app.Fragment | 33 | import androidx.fragment.app.Fragment |
| 34 | import androidx.fragment.app.activityViewModels | 34 | import androidx.fragment.app.activityViewModels |
| 35 | import androidx.lifecycle.Lifecycle | ||
| 36 | import androidx.lifecycle.lifecycleScope | ||
| 37 | import androidx.lifecycle.repeatOnLifecycle | ||
| 38 | import androidx.navigation.findNavController | 35 | import androidx.navigation.findNavController |
| 39 | import androidx.navigation.fragment.navArgs | 36 | import androidx.navigation.fragment.navArgs |
| 40 | import androidx.window.layout.FoldingFeature | 37 | import androidx.window.layout.FoldingFeature |
| @@ -42,9 +39,6 @@ import androidx.window.layout.WindowInfoTracker | |||
| 42 | import androidx.window.layout.WindowLayoutInfo | 39 | import androidx.window.layout.WindowLayoutInfo |
| 43 | import com.google.android.material.dialog.MaterialAlertDialogBuilder | 40 | import com.google.android.material.dialog.MaterialAlertDialogBuilder |
| 44 | import com.google.android.material.slider.Slider | 41 | import com.google.android.material.slider.Slider |
| 45 | import kotlinx.coroutines.Dispatchers | ||
| 46 | import kotlinx.coroutines.flow.collectLatest | ||
| 47 | import kotlinx.coroutines.launch | ||
| 48 | import org.yuzu.yuzu_emu.HomeNavigationDirections | 42 | import org.yuzu.yuzu_emu.HomeNavigationDirections |
| 49 | import org.yuzu.yuzu_emu.NativeLibrary | 43 | import org.yuzu.yuzu_emu.NativeLibrary |
| 50 | import org.yuzu.yuzu_emu.R | 44 | import org.yuzu.yuzu_emu.R |
| @@ -63,6 +57,7 @@ import org.yuzu.yuzu_emu.model.EmulationViewModel | |||
| 63 | import org.yuzu.yuzu_emu.overlay.model.OverlayControl | 57 | import org.yuzu.yuzu_emu.overlay.model.OverlayControl |
| 64 | import org.yuzu.yuzu_emu.overlay.model.OverlayLayout | 58 | import org.yuzu.yuzu_emu.overlay.model.OverlayLayout |
| 65 | import org.yuzu.yuzu_emu.utils.* | 59 | import org.yuzu.yuzu_emu.utils.* |
| 60 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 66 | import java.lang.NullPointerException | 61 | import java.lang.NullPointerException |
| 67 | 62 | ||
| 68 | class EmulationFragment : Fragment(), SurfaceHolder.Callback { | 63 | class EmulationFragment : Fragment(), SurfaceHolder.Callback { |
| @@ -90,14 +85,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 90 | if (context is EmulationActivity) { | 85 | if (context is EmulationActivity) { |
| 91 | emulationActivity = context | 86 | emulationActivity = context |
| 92 | NativeLibrary.setEmulationActivity(context) | 87 | NativeLibrary.setEmulationActivity(context) |
| 93 | |||
| 94 | lifecycleScope.launch(Dispatchers.Main) { | ||
| 95 | lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { | ||
| 96 | WindowInfoTracker.getOrCreate(context) | ||
| 97 | .windowLayoutInfo(context) | ||
| 98 | .collect { updateFoldableLayout(context, it) } | ||
| 99 | } | ||
| 100 | } | ||
| 101 | } else { | 88 | } else { |
| 102 | throw IllegalStateException("EmulationFragment must have EmulationActivity parent") | 89 | throw IllegalStateException("EmulationFragment must have EmulationActivity parent") |
| 103 | } | 90 | } |
| @@ -168,8 +155,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 168 | return binding.root | 155 | return binding.root |
| 169 | } | 156 | } |
| 170 | 157 | ||
| 171 | // This is using the correct scope, lint is just acting up | ||
| 172 | @SuppressLint("UnsafeRepeatOnLifecycleDetector") | ||
| 173 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | 158 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| 174 | super.onViewCreated(view, savedInstanceState) | 159 | super.onViewCreated(view, savedInstanceState) |
| 175 | if (requireActivity().isFinishing) { | 160 | if (requireActivity().isFinishing) { |
| @@ -277,6 +262,15 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 277 | true | 262 | true |
| 278 | } | 263 | } |
| 279 | 264 | ||
| 265 | R.id.menu_controls -> { | ||
| 266 | val action = HomeNavigationDirections.actionGlobalSettingsActivity( | ||
| 267 | null, | ||
| 268 | Settings.MenuTag.SECTION_INPUT | ||
| 269 | ) | ||
| 270 | binding.root.findNavController().navigate(action) | ||
| 271 | true | ||
| 272 | } | ||
| 273 | |||
| 280 | R.id.menu_overlay_controls -> { | 274 | R.id.menu_overlay_controls -> { |
| 281 | showOverlayOptions() | 275 | showOverlayOptions() |
| 282 | true | 276 | true |
| @@ -341,129 +335,86 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 341 | binding.loadingTitle.isSelected = true | 335 | binding.loadingTitle.isSelected = true |
| 342 | binding.loadingText.isSelected = true | 336 | binding.loadingText.isSelected = true |
| 343 | 337 | ||
| 344 | viewLifecycleOwner.lifecycleScope.apply { | 338 | WindowInfoTracker.getOrCreate(requireContext()) |
| 345 | launch { | 339 | .windowLayoutInfo(requireActivity()).collect(viewLifecycleOwner) { |
| 346 | repeatOnLifecycle(Lifecycle.State.STARTED) { | 340 | updateFoldableLayout(requireActivity() as EmulationActivity, it) |
| 347 | WindowInfoTracker.getOrCreate(requireContext()) | ||
| 348 | .windowLayoutInfo(requireActivity()) | ||
| 349 | .collect { | ||
| 350 | updateFoldableLayout(requireActivity() as EmulationActivity, it) | ||
| 351 | } | ||
| 352 | } | ||
| 353 | } | 341 | } |
| 354 | launch { | 342 | emulationViewModel.shaderProgress.collect(viewLifecycleOwner) { |
| 355 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 343 | if (it > 0 && it != emulationViewModel.totalShaders.value) { |
| 356 | emulationViewModel.shaderProgress.collectLatest { | 344 | binding.loadingProgressIndicator.isIndeterminate = false |
| 357 | if (it > 0 && it != emulationViewModel.totalShaders.value) { | ||
| 358 | binding.loadingProgressIndicator.isIndeterminate = false | ||
| 359 | |||
| 360 | if (it < binding.loadingProgressIndicator.max) { | ||
| 361 | binding.loadingProgressIndicator.progress = it | ||
| 362 | } | ||
| 363 | } | ||
| 364 | 345 | ||
| 365 | if (it == emulationViewModel.totalShaders.value) { | 346 | if (it < binding.loadingProgressIndicator.max) { |
| 366 | binding.loadingText.setText(R.string.loading) | 347 | binding.loadingProgressIndicator.progress = it |
| 367 | binding.loadingProgressIndicator.isIndeterminate = true | ||
| 368 | } | ||
| 369 | } | ||
| 370 | } | 348 | } |
| 371 | } | 349 | } |
| 372 | launch { | 350 | |
| 373 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 351 | if (it == emulationViewModel.totalShaders.value) { |
| 374 | emulationViewModel.totalShaders.collectLatest { | 352 | binding.loadingText.setText(R.string.loading) |
| 375 | binding.loadingProgressIndicator.max = it | 353 | binding.loadingProgressIndicator.isIndeterminate = true |
| 376 | } | ||
| 377 | } | ||
| 378 | } | ||
| 379 | launch { | ||
| 380 | repeatOnLifecycle(Lifecycle.State.CREATED) { | ||
| 381 | emulationViewModel.shaderMessage.collectLatest { | ||
| 382 | if (it.isNotEmpty()) { | ||
| 383 | binding.loadingText.text = it | ||
| 384 | } | ||
| 385 | } | ||
| 386 | } | ||
| 387 | } | 354 | } |
| 388 | launch { | 355 | } |
| 389 | repeatOnLifecycle(Lifecycle.State.RESUMED) { | 356 | emulationViewModel.totalShaders.collect(viewLifecycleOwner) { |
| 390 | driverViewModel.isInteractionAllowed.collect { | 357 | binding.loadingProgressIndicator.max = it |
| 391 | if (it) { | 358 | } |
| 392 | startEmulation() | 359 | emulationViewModel.shaderMessage.collect(viewLifecycleOwner) { |
| 393 | } | 360 | if (it.isNotEmpty()) { |
| 394 | } | 361 | binding.loadingText.text = it |
| 395 | } | ||
| 396 | } | 362 | } |
| 397 | launch { | 363 | } |
| 398 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 364 | |
| 399 | emulationViewModel.emulationStarted.collectLatest { | 365 | emulationViewModel.emulationStarted.collect(viewLifecycleOwner) { |
| 400 | if (it) { | 366 | if (it) { |
| 401 | binding.drawerLayout.setDrawerLockMode(IntSetting.LOCK_DRAWER.getInt()) | 367 | binding.drawerLayout.setDrawerLockMode(IntSetting.LOCK_DRAWER.getInt()) |
| 402 | ViewUtils.showView(binding.surfaceInputOverlay) | 368 | ViewUtils.showView(binding.surfaceInputOverlay) |
| 403 | ViewUtils.hideView(binding.loadingIndicator) | 369 | ViewUtils.hideView(binding.loadingIndicator) |
| 404 | 370 | ||
| 405 | emulationState.updateSurface() | 371 | emulationState.updateSurface() |
| 406 | 372 | ||
| 407 | // Setup overlays | 373 | // Setup overlays |
| 408 | updateShowFpsOverlay() | 374 | updateShowFpsOverlay() |
| 409 | updateThermalOverlay() | 375 | updateThermalOverlay() |
| 410 | } | ||
| 411 | } | ||
| 412 | } | ||
| 413 | } | 376 | } |
| 414 | launch { | 377 | } |
| 415 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 378 | emulationViewModel.isEmulationStopping.collect(viewLifecycleOwner) { |
| 416 | emulationViewModel.isEmulationStopping.collectLatest { | 379 | if (it) { |
| 417 | if (it) { | 380 | binding.loadingText.setText(R.string.shutting_down) |
| 418 | binding.loadingText.setText(R.string.shutting_down) | 381 | ViewUtils.showView(binding.loadingIndicator) |
| 419 | ViewUtils.showView(binding.loadingIndicator) | 382 | ViewUtils.hideView(binding.inputContainer) |
| 420 | ViewUtils.hideView(binding.inputContainer) | 383 | ViewUtils.hideView(binding.showFpsText) |
| 421 | ViewUtils.hideView(binding.showFpsText) | ||
| 422 | } | ||
| 423 | } | ||
| 424 | } | ||
| 425 | } | 384 | } |
| 426 | launch { | 385 | } |
| 427 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 386 | emulationViewModel.drawerOpen.collect(viewLifecycleOwner) { |
| 428 | emulationViewModel.drawerOpen.collect { | 387 | if (it) { |
| 429 | if (it) { | 388 | binding.drawerLayout.open() |
| 430 | binding.drawerLayout.open() | 389 | binding.inGameMenu.requestFocus() |
| 431 | binding.inGameMenu.requestFocus() | 390 | } else { |
| 432 | } else { | 391 | binding.drawerLayout.close() |
| 433 | binding.drawerLayout.close() | ||
| 434 | } | ||
| 435 | } | ||
| 436 | } | ||
| 437 | } | 392 | } |
| 438 | launch { | 393 | } |
| 439 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 394 | emulationViewModel.programChanged.collect(viewLifecycleOwner) { |
| 440 | emulationViewModel.programChanged.collect { | 395 | if (it != 0) { |
| 441 | if (it != 0) { | 396 | emulationViewModel.setEmulationStarted(false) |
| 442 | emulationViewModel.setEmulationStarted(false) | 397 | binding.drawerLayout.close() |
| 443 | binding.drawerLayout.close() | 398 | binding.drawerLayout |
| 444 | binding.drawerLayout | 399 | .setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) |
| 445 | .setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) | 400 | ViewUtils.hideView(binding.surfaceInputOverlay) |
| 446 | ViewUtils.hideView(binding.surfaceInputOverlay) | 401 | ViewUtils.showView(binding.loadingIndicator) |
| 447 | ViewUtils.showView(binding.loadingIndicator) | ||
| 448 | } | ||
| 449 | } | ||
| 450 | } | ||
| 451 | } | 402 | } |
| 452 | launch { | 403 | } |
| 453 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 404 | emulationViewModel.emulationStopped.collect(viewLifecycleOwner) { |
| 454 | emulationViewModel.emulationStopped.collect { | 405 | if (it && emulationViewModel.programChanged.value != -1) { |
| 455 | if (it && emulationViewModel.programChanged.value != -1) { | 406 | if (perfStatsUpdater != null) { |
| 456 | if (perfStatsUpdater != null) { | 407 | perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!) |
| 457 | perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!) | ||
| 458 | } | ||
| 459 | emulationState.changeProgram(emulationViewModel.programChanged.value) | ||
| 460 | emulationViewModel.setProgramChanged(-1) | ||
| 461 | emulationViewModel.setEmulationStopped(false) | ||
| 462 | } | ||
| 463 | } | ||
| 464 | } | 408 | } |
| 409 | emulationState.changeProgram(emulationViewModel.programChanged.value) | ||
| 410 | emulationViewModel.setProgramChanged(-1) | ||
| 411 | emulationViewModel.setEmulationStopped(false) | ||
| 465 | } | 412 | } |
| 466 | } | 413 | } |
| 414 | |||
| 415 | driverViewModel.isInteractionAllowed.collect(viewLifecycleOwner) { | ||
| 416 | if (it) startEmulation() | ||
| 417 | } | ||
| 467 | } | 418 | } |
| 468 | 419 | ||
| 469 | private fun startEmulation(programIndex: Int = 0) { | 420 | private fun startEmulation(programIndex: Int = 0) { |
| @@ -491,14 +442,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 491 | binding.drawerLayout.close() | 442 | binding.drawerLayout.close() |
| 492 | } | 443 | } |
| 493 | if (showInputOverlay) { | 444 | if (showInputOverlay) { |
| 494 | binding.surfaceInputOverlay.visibility = View.INVISIBLE | 445 | binding.surfaceInputOverlay.setVisible(visible = false, gone = false) |
| 495 | } | 446 | } |
| 496 | } else { | 447 | } else { |
| 497 | if (showInputOverlay && emulationViewModel.emulationStarted.value) { | 448 | binding.surfaceInputOverlay.setVisible( |
| 498 | binding.surfaceInputOverlay.visibility = View.VISIBLE | 449 | showInputOverlay && emulationViewModel.emulationStarted.value |
| 499 | } else { | 450 | ) |
| 500 | binding.surfaceInputOverlay.visibility = View.INVISIBLE | ||
| 501 | } | ||
| 502 | if (!isInFoldableLayout) { | 451 | if (!isInFoldableLayout) { |
| 503 | if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { | 452 | if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { |
| 504 | binding.surfaceInputOverlay.layout = OverlayLayout.Portrait | 453 | binding.surfaceInputOverlay.layout = OverlayLayout.Portrait |
| @@ -535,7 +484,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 535 | } | 484 | } |
| 536 | 485 | ||
| 537 | private fun updateShowFpsOverlay() { | 486 | private fun updateShowFpsOverlay() { |
| 538 | if (BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()) { | 487 | val showOverlay = BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean() |
| 488 | binding.showFpsText.setVisible(showOverlay) | ||
| 489 | if (showOverlay) { | ||
| 539 | val SYSTEM_FPS = 0 | 490 | val SYSTEM_FPS = 0 |
| 540 | val FPS = 1 | 491 | val FPS = 1 |
| 541 | val FRAMETIME = 2 | 492 | val FRAMETIME = 2 |
| @@ -555,17 +506,17 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 555 | } | 506 | } |
| 556 | } | 507 | } |
| 557 | perfStatsUpdateHandler.post(perfStatsUpdater!!) | 508 | perfStatsUpdateHandler.post(perfStatsUpdater!!) |
| 558 | binding.showFpsText.visibility = View.VISIBLE | ||
| 559 | } else { | 509 | } else { |
| 560 | if (perfStatsUpdater != null) { | 510 | if (perfStatsUpdater != null) { |
| 561 | perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!) | 511 | perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!) |
| 562 | } | 512 | } |
| 563 | binding.showFpsText.visibility = View.GONE | ||
| 564 | } | 513 | } |
| 565 | } | 514 | } |
| 566 | 515 | ||
| 567 | private fun updateThermalOverlay() { | 516 | private fun updateThermalOverlay() { |
| 568 | if (BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean()) { | 517 | val showOverlay = BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean() |
| 518 | binding.showThermalsText.setVisible(showOverlay) | ||
| 519 | if (showOverlay) { | ||
| 569 | thermalStatsUpdater = { | 520 | thermalStatsUpdater = { |
| 570 | if (emulationViewModel.emulationStarted.value && | 521 | if (emulationViewModel.emulationStarted.value && |
| 571 | !emulationViewModel.isEmulationStopping.value | 522 | !emulationViewModel.isEmulationStopping.value |
| @@ -587,12 +538,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 587 | } | 538 | } |
| 588 | } | 539 | } |
| 589 | thermalStatsUpdateHandler.post(thermalStatsUpdater!!) | 540 | thermalStatsUpdateHandler.post(thermalStatsUpdater!!) |
| 590 | binding.showThermalsText.visibility = View.VISIBLE | ||
| 591 | } else { | 541 | } else { |
| 592 | if (thermalStatsUpdater != null) { | 542 | if (thermalStatsUpdater != null) { |
| 593 | thermalStatsUpdateHandler.removeCallbacks(thermalStatsUpdater!!) | 543 | thermalStatsUpdateHandler.removeCallbacks(thermalStatsUpdater!!) |
| 594 | } | 544 | } |
| 595 | binding.showThermalsText.visibility = View.GONE | ||
| 596 | } | 545 | } |
| 597 | } | 546 | } |
| 598 | 547 | ||
| @@ -861,12 +810,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 861 | } | 810 | } |
| 862 | } | 811 | } |
| 863 | } | 812 | } |
| 864 | binding.doneControlConfig.visibility = View.VISIBLE | 813 | binding.doneControlConfig.setVisible(true) |
| 865 | binding.surfaceInputOverlay.setIsInEditMode(true) | 814 | binding.surfaceInputOverlay.setIsInEditMode(true) |
| 866 | } | 815 | } |
| 867 | 816 | ||
| 868 | private fun stopConfiguringControls() { | 817 | private fun stopConfiguringControls() { |
| 869 | binding.doneControlConfig.visibility = View.GONE | 818 | binding.doneControlConfig.setVisible(false) |
| 870 | binding.surfaceInputOverlay.setIsInEditMode(false) | 819 | binding.surfaceInputOverlay.setIsInEditMode(false) |
| 871 | // Unlock the orientation if it was locked for editing | 820 | // Unlock the orientation if it was locked for editing |
| 872 | if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == EmulationOrientation.Unspecified.int) { | 821 | if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == EmulationOrientation.Unspecified.int) { |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameFoldersFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameFoldersFragment.kt index 5c558b1a5..3a6f7a38c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameFoldersFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameFoldersFragment.kt | |||
| @@ -13,9 +13,6 @@ import androidx.core.view.WindowInsetsCompat | |||
| 13 | import androidx.core.view.updatePadding | 13 | import androidx.core.view.updatePadding |
| 14 | import androidx.fragment.app.Fragment | 14 | import androidx.fragment.app.Fragment |
| 15 | import androidx.fragment.app.activityViewModels | 15 | import androidx.fragment.app.activityViewModels |
| 16 | import androidx.lifecycle.Lifecycle | ||
| 17 | import androidx.lifecycle.lifecycleScope | ||
| 18 | import androidx.lifecycle.repeatOnLifecycle | ||
| 19 | import androidx.navigation.findNavController | 16 | import androidx.navigation.findNavController |
| 20 | import androidx.recyclerview.widget.GridLayoutManager | 17 | import androidx.recyclerview.widget.GridLayoutManager |
| 21 | import com.google.android.material.transition.MaterialSharedAxis | 18 | import com.google.android.material.transition.MaterialSharedAxis |
| @@ -27,6 +24,7 @@ import org.yuzu.yuzu_emu.model.GamesViewModel | |||
| 27 | import org.yuzu.yuzu_emu.model.HomeViewModel | 24 | import org.yuzu.yuzu_emu.model.HomeViewModel |
| 28 | import org.yuzu.yuzu_emu.ui.main.MainActivity | 25 | import org.yuzu.yuzu_emu.ui.main.MainActivity |
| 29 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins | 26 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins |
| 27 | import org.yuzu.yuzu_emu.utils.collect | ||
| 30 | 28 | ||
| 31 | class GameFoldersFragment : Fragment() { | 29 | class GameFoldersFragment : Fragment() { |
| 32 | private var _binding: FragmentFoldersBinding? = null | 30 | private var _binding: FragmentFoldersBinding? = null |
| @@ -70,12 +68,8 @@ class GameFoldersFragment : Fragment() { | |||
| 70 | adapter = FolderAdapter(requireActivity(), gamesViewModel) | 68 | adapter = FolderAdapter(requireActivity(), gamesViewModel) |
| 71 | } | 69 | } |
| 72 | 70 | ||
| 73 | viewLifecycleOwner.lifecycleScope.launch { | 71 | gamesViewModel.folders.collect(viewLifecycleOwner) { |
| 74 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 72 | (binding.listFolders.adapter as FolderAdapter).submitList(it) |
| 75 | gamesViewModel.folders.collect { | ||
| 76 | (binding.listFolders.adapter as FolderAdapter).submitList(it) | ||
| 77 | } | ||
| 78 | } | ||
| 79 | } | 73 | } |
| 80 | 74 | ||
| 81 | val mainActivity = requireActivity() as MainActivity | 75 | val mainActivity = requireActivity() as MainActivity |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameInfoFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameInfoFragment.kt index dbd56e84f..97a8954bb 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameInfoFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GameInfoFragment.kt | |||
| @@ -27,6 +27,7 @@ import org.yuzu.yuzu_emu.databinding.FragmentGameInfoBinding | |||
| 27 | import org.yuzu.yuzu_emu.model.GameVerificationResult | 27 | import org.yuzu.yuzu_emu.model.GameVerificationResult |
| 28 | import org.yuzu.yuzu_emu.model.HomeViewModel | 28 | import org.yuzu.yuzu_emu.model.HomeViewModel |
| 29 | import org.yuzu.yuzu_emu.utils.GameMetadata | 29 | import org.yuzu.yuzu_emu.utils.GameMetadata |
| 30 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 30 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins | 31 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins |
| 31 | 32 | ||
| 32 | class GameInfoFragment : Fragment() { | 33 | class GameInfoFragment : Fragment() { |
| @@ -85,7 +86,7 @@ class GameInfoFragment : Fragment() { | |||
| 85 | copyToClipboard(getString(R.string.developer), args.game.developer) | 86 | copyToClipboard(getString(R.string.developer), args.game.developer) |
| 86 | } | 87 | } |
| 87 | } else { | 88 | } else { |
| 88 | developer.visibility = View.GONE | 89 | developer.setVisible(false) |
| 89 | } | 90 | } |
| 90 | 91 | ||
| 91 | version.setHint(R.string.version) | 92 | version.setHint(R.string.version) |
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 3ea5e16ca..c06842c59 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 | |||
| @@ -3,11 +3,9 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.fragments | 4 | package org.yuzu.yuzu_emu.fragments |
| 5 | 5 | ||
| 6 | import android.annotation.SuppressLint | ||
| 7 | import android.content.pm.ShortcutInfo | 6 | import android.content.pm.ShortcutInfo |
| 8 | import android.content.pm.ShortcutManager | 7 | import android.content.pm.ShortcutManager |
| 9 | import android.os.Bundle | 8 | import android.os.Bundle |
| 10 | import android.text.TextUtils | ||
| 11 | import android.view.LayoutInflater | 9 | import android.view.LayoutInflater |
| 12 | import android.view.View | 10 | import android.view.View |
| 13 | import android.view.ViewGroup | 11 | import android.view.ViewGroup |
| @@ -18,9 +16,7 @@ import androidx.core.view.WindowInsetsCompat | |||
| 18 | import androidx.core.view.updatePadding | 16 | import androidx.core.view.updatePadding |
| 19 | import androidx.fragment.app.Fragment | 17 | import androidx.fragment.app.Fragment |
| 20 | import androidx.fragment.app.activityViewModels | 18 | import androidx.fragment.app.activityViewModels |
| 21 | import androidx.lifecycle.Lifecycle | ||
| 22 | import androidx.lifecycle.lifecycleScope | 19 | import androidx.lifecycle.lifecycleScope |
| 23 | import androidx.lifecycle.repeatOnLifecycle | ||
| 24 | import androidx.navigation.findNavController | 20 | import androidx.navigation.findNavController |
| 25 | import androidx.navigation.fragment.navArgs | 21 | import androidx.navigation.fragment.navArgs |
| 26 | import androidx.recyclerview.widget.GridLayoutManager | 22 | import androidx.recyclerview.widget.GridLayoutManager |
| @@ -46,7 +42,9 @@ import org.yuzu.yuzu_emu.utils.FileUtil | |||
| 46 | import org.yuzu.yuzu_emu.utils.GameIconUtils | 42 | import org.yuzu.yuzu_emu.utils.GameIconUtils |
| 47 | import org.yuzu.yuzu_emu.utils.GpuDriverHelper | 43 | import org.yuzu.yuzu_emu.utils.GpuDriverHelper |
| 48 | import org.yuzu.yuzu_emu.utils.MemoryUtil | 44 | import org.yuzu.yuzu_emu.utils.MemoryUtil |
| 45 | import org.yuzu.yuzu_emu.utils.ViewUtils.marquee | ||
| 49 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins | 46 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins |
| 47 | import org.yuzu.yuzu_emu.utils.collect | ||
| 50 | import java.io.BufferedOutputStream | 48 | import java.io.BufferedOutputStream |
| 51 | import java.io.File | 49 | import java.io.File |
| 52 | 50 | ||
| @@ -76,8 +74,6 @@ class GamePropertiesFragment : Fragment() { | |||
| 76 | return binding.root | 74 | return binding.root |
| 77 | } | 75 | } |
| 78 | 76 | ||
| 79 | // This is using the correct scope, lint is just acting up | ||
| 80 | @SuppressLint("UnsafeRepeatOnLifecycleDetector") | ||
| 81 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | 77 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| 82 | super.onViewCreated(view, savedInstanceState) | 78 | super.onViewCreated(view, savedInstanceState) |
| 83 | homeViewModel.setNavigationVisibility(visible = false, animated = true) | 79 | homeViewModel.setNavigationVisibility(visible = false, animated = true) |
| @@ -107,13 +103,7 @@ class GamePropertiesFragment : Fragment() { | |||
| 107 | 103 | ||
| 108 | GameIconUtils.loadGameIcon(args.game, binding.imageGameScreen) | 104 | GameIconUtils.loadGameIcon(args.game, binding.imageGameScreen) |
| 109 | binding.title.text = args.game.title | 105 | binding.title.text = args.game.title |
| 110 | binding.title.postDelayed( | 106 | binding.title.marquee() |
| 111 | { | ||
| 112 | binding.title.ellipsize = TextUtils.TruncateAt.MARQUEE | ||
| 113 | binding.title.isSelected = true | ||
| 114 | }, | ||
| 115 | 3000 | ||
| 116 | ) | ||
| 117 | 107 | ||
| 118 | binding.buttonStart.setOnClickListener { | 108 | binding.buttonStart.setOnClickListener { |
| 119 | LaunchGameDialogFragment.newInstance(args.game) | 109 | LaunchGameDialogFragment.newInstance(args.game) |
| @@ -122,28 +112,14 @@ class GamePropertiesFragment : Fragment() { | |||
| 122 | 112 | ||
| 123 | reloadList() | 113 | reloadList() |
| 124 | 114 | ||
| 125 | viewLifecycleOwner.lifecycleScope.apply { | 115 | homeViewModel.openImportSaves.collect( |
| 126 | launch { | 116 | viewLifecycleOwner, |
| 127 | repeatOnLifecycle(Lifecycle.State.STARTED) { | 117 | resetState = { homeViewModel.setOpenImportSaves(false) } |
| 128 | homeViewModel.openImportSaves.collect { | 118 | ) { if (it) importSaves.launch(arrayOf("application/zip")) } |
| 129 | if (it) { | 119 | homeViewModel.reloadPropertiesList.collect( |
| 130 | importSaves.launch(arrayOf("application/zip")) | 120 | viewLifecycleOwner, |
| 131 | homeViewModel.setOpenImportSaves(false) | 121 | resetState = { homeViewModel.reloadPropertiesList(false) } |
| 132 | } | 122 | ) { if (it) reloadList() } |
| 133 | } | ||
| 134 | } | ||
| 135 | } | ||
| 136 | launch { | ||
| 137 | repeatOnLifecycle(Lifecycle.State.STARTED) { | ||
| 138 | homeViewModel.reloadPropertiesList.collect { | ||
| 139 | if (it) { | ||
| 140 | reloadList() | ||
| 141 | homeViewModel.reloadPropertiesList(false) | ||
| 142 | } | ||
| 143 | } | ||
| 144 | } | ||
| 145 | } | ||
| 146 | } | ||
| 147 | 123 | ||
| 148 | setInsets() | 124 | setInsets() |
| 149 | } | 125 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt index 87e130d3e..14a2504b6 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt | |||
| @@ -91,6 +91,20 @@ class HomeSettingsFragment : Fragment() { | |||
| 91 | ) | 91 | ) |
| 92 | add( | 92 | add( |
| 93 | HomeSetting( | 93 | HomeSetting( |
| 94 | R.string.preferences_controls, | ||
| 95 | R.string.preferences_controls_description, | ||
| 96 | R.drawable.ic_controller, | ||
| 97 | { | ||
| 98 | val action = HomeNavigationDirections.actionGlobalSettingsActivity( | ||
| 99 | null, | ||
| 100 | Settings.MenuTag.SECTION_INPUT | ||
| 101 | ) | ||
| 102 | binding.root.findNavController().navigate(action) | ||
| 103 | } | ||
| 104 | ) | ||
| 105 | ) | ||
| 106 | add( | ||
| 107 | HomeSetting( | ||
| 94 | R.string.gpu_driver_manager, | 108 | R.string.gpu_driver_manager, |
| 95 | R.string.install_gpu_driver_description, | 109 | R.string.install_gpu_driver_description, |
| 96 | R.drawable.ic_build, | 110 | R.drawable.ic_build, |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt index 63112dc6f..d218da1c8 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt | |||
| @@ -14,9 +14,6 @@ import androidx.core.view.WindowInsetsCompat | |||
| 14 | import androidx.core.view.updatePadding | 14 | import androidx.core.view.updatePadding |
| 15 | import androidx.fragment.app.Fragment | 15 | import androidx.fragment.app.Fragment |
| 16 | import androidx.fragment.app.activityViewModels | 16 | import androidx.fragment.app.activityViewModels |
| 17 | import androidx.lifecycle.Lifecycle | ||
| 18 | import androidx.lifecycle.lifecycleScope | ||
| 19 | import androidx.lifecycle.repeatOnLifecycle | ||
| 20 | import androidx.navigation.findNavController | 17 | import androidx.navigation.findNavController |
| 21 | import androidx.recyclerview.widget.GridLayoutManager | 18 | import androidx.recyclerview.widget.GridLayoutManager |
| 22 | import com.google.android.material.transition.MaterialSharedAxis | 19 | import com.google.android.material.transition.MaterialSharedAxis |
| @@ -35,6 +32,7 @@ import org.yuzu.yuzu_emu.ui.main.MainActivity | |||
| 35 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization | 32 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization |
| 36 | import org.yuzu.yuzu_emu.utils.FileUtil | 33 | import org.yuzu.yuzu_emu.utils.FileUtil |
| 37 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins | 34 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins |
| 35 | import org.yuzu.yuzu_emu.utils.collect | ||
| 38 | import java.io.BufferedOutputStream | 36 | import java.io.BufferedOutputStream |
| 39 | import java.io.File | 37 | import java.io.File |
| 40 | import java.math.BigInteger | 38 | import java.math.BigInteger |
| @@ -75,14 +73,10 @@ class InstallableFragment : Fragment() { | |||
| 75 | binding.root.findNavController().popBackStack() | 73 | binding.root.findNavController().popBackStack() |
| 76 | } | 74 | } |
| 77 | 75 | ||
| 78 | viewLifecycleOwner.lifecycleScope.launch { | 76 | homeViewModel.openImportSaves.collect(viewLifecycleOwner) { |
| 79 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 77 | if (it) { |
| 80 | homeViewModel.openImportSaves.collect { | 78 | importSaves.launch(arrayOf("application/zip")) |
| 81 | if (it) { | 79 | homeViewModel.setOpenImportSaves(false) |
| 82 | importSaves.launch(arrayOf("application/zip")) | ||
| 83 | homeViewModel.setOpenImportSaves(false) | ||
| 84 | } | ||
| 85 | } | ||
| 86 | } | 80 | } |
| 87 | } | 81 | } |
| 88 | 82 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProgressDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProgressDialogFragment.kt index d201cb80c..ee3bb0386 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProgressDialogFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProgressDialogFragment.kt | |||
| @@ -13,15 +13,13 @@ import androidx.appcompat.app.AlertDialog | |||
| 13 | import androidx.fragment.app.DialogFragment | 13 | import androidx.fragment.app.DialogFragment |
| 14 | import androidx.fragment.app.FragmentActivity | 14 | import androidx.fragment.app.FragmentActivity |
| 15 | import androidx.fragment.app.activityViewModels | 15 | import androidx.fragment.app.activityViewModels |
| 16 | import androidx.lifecycle.Lifecycle | ||
| 17 | import androidx.lifecycle.ViewModelProvider | 16 | import androidx.lifecycle.ViewModelProvider |
| 18 | import androidx.lifecycle.lifecycleScope | ||
| 19 | import androidx.lifecycle.repeatOnLifecycle | ||
| 20 | import com.google.android.material.dialog.MaterialAlertDialogBuilder | 17 | import com.google.android.material.dialog.MaterialAlertDialogBuilder |
| 21 | import kotlinx.coroutines.launch | ||
| 22 | import org.yuzu.yuzu_emu.R | 18 | import org.yuzu.yuzu_emu.R |
| 23 | import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding | 19 | import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding |
| 24 | import org.yuzu.yuzu_emu.model.TaskViewModel | 20 | import org.yuzu.yuzu_emu.model.TaskViewModel |
| 21 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 22 | import org.yuzu.yuzu_emu.utils.collect | ||
| 25 | 23 | ||
| 26 | class ProgressDialogFragment : DialogFragment() { | 24 | class ProgressDialogFragment : DialogFragment() { |
| 27 | private val taskViewModel: TaskViewModel by activityViewModels() | 25 | private val taskViewModel: TaskViewModel by activityViewModels() |
| @@ -64,72 +62,50 @@ class ProgressDialogFragment : DialogFragment() { | |||
| 64 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | 62 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| 65 | super.onViewCreated(view, savedInstanceState) | 63 | super.onViewCreated(view, savedInstanceState) |
| 66 | binding.message.isSelected = true | 64 | binding.message.isSelected = true |
| 67 | viewLifecycleOwner.lifecycleScope.apply { | 65 | taskViewModel.isComplete.collect(viewLifecycleOwner) { |
| 68 | launch { | 66 | if (it) { |
| 69 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 67 | dismiss() |
| 70 | taskViewModel.isComplete.collect { | 68 | when (val result = taskViewModel.result.value) { |
| 71 | if (it) { | 69 | is String -> Toast.makeText( |
| 72 | dismiss() | 70 | requireContext(), |
| 73 | when (val result = taskViewModel.result.value) { | 71 | result, |
| 74 | is String -> Toast.makeText( | 72 | Toast.LENGTH_LONG |
| 75 | requireContext(), | 73 | ).show() |
| 76 | result, | 74 | |
| 77 | Toast.LENGTH_LONG | 75 | is MessageDialogFragment -> result.show( |
| 78 | ).show() | 76 | requireActivity().supportFragmentManager, |
| 79 | 77 | MessageDialogFragment.TAG | |
| 80 | is MessageDialogFragment -> result.show( | 78 | ) |
| 81 | requireActivity().supportFragmentManager, | 79 | |
| 82 | MessageDialogFragment.TAG | 80 | else -> { |
| 83 | ) | 81 | // Do nothing |
| 84 | |||
| 85 | else -> { | ||
| 86 | // Do nothing | ||
| 87 | } | ||
| 88 | } | ||
| 89 | taskViewModel.clear() | ||
| 90 | } | ||
| 91 | } | 82 | } |
| 92 | } | 83 | } |
| 84 | taskViewModel.clear() | ||
| 93 | } | 85 | } |
| 94 | launch { | 86 | } |
| 95 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 87 | taskViewModel.cancelled.collect(viewLifecycleOwner) { |
| 96 | taskViewModel.cancelled.collect { | 88 | if (it) { |
| 97 | if (it) { | 89 | dialog?.setTitle(R.string.cancelling) |
| 98 | dialog?.setTitle(R.string.cancelling) | ||
| 99 | } | ||
| 100 | } | ||
| 101 | } | ||
| 102 | } | ||
| 103 | launch { | ||
| 104 | repeatOnLifecycle(Lifecycle.State.CREATED) { | ||
| 105 | taskViewModel.progress.collect { | ||
| 106 | if (it != 0.0) { | ||
| 107 | binding.progressBar.apply { | ||
| 108 | isIndeterminate = false | ||
| 109 | progress = ( | ||
| 110 | (it / taskViewModel.maxProgress.value) * | ||
| 111 | PROGRESS_BAR_RESOLUTION | ||
| 112 | ).toInt() | ||
| 113 | min = 0 | ||
| 114 | max = PROGRESS_BAR_RESOLUTION | ||
| 115 | } | ||
| 116 | } | ||
| 117 | } | ||
| 118 | } | ||
| 119 | } | 90 | } |
| 120 | launch { | 91 | } |
| 121 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 92 | taskViewModel.progress.collect(viewLifecycleOwner) { |
| 122 | taskViewModel.message.collect { | 93 | if (it != 0.0) { |
| 123 | if (it.isEmpty()) { | 94 | binding.progressBar.apply { |
| 124 | binding.message.visibility = View.GONE | 95 | isIndeterminate = false |
| 125 | } else { | 96 | progress = ( |
| 126 | binding.message.visibility = View.VISIBLE | 97 | (it / taskViewModel.maxProgress.value) * |
| 127 | binding.message.text = it | 98 | PROGRESS_BAR_RESOLUTION |
| 128 | } | 99 | ).toInt() |
| 129 | } | 100 | min = 0 |
| 101 | max = PROGRESS_BAR_RESOLUTION | ||
| 130 | } | 102 | } |
| 131 | } | 103 | } |
| 132 | } | 104 | } |
| 105 | taskViewModel.message.collect(viewLifecycleOwner) { | ||
| 106 | binding.message.setVisible(it.isNotEmpty()) | ||
| 107 | binding.message.text = it | ||
| 108 | } | ||
| 133 | } | 109 | } |
| 134 | 110 | ||
| 135 | // By default, the ProgressDialog will immediately dismiss itself upon a button being pressed. | 111 | // By default, the ProgressDialog will immediately dismiss itself upon a button being pressed. |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt index 20b10b1a0..662ae9760 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.fragments | 4 | package org.yuzu.yuzu_emu.fragments |
| 5 | 5 | ||
| 6 | import android.annotation.SuppressLint | ||
| 7 | import android.content.Context | 6 | import android.content.Context |
| 8 | import android.content.SharedPreferences | 7 | import android.content.SharedPreferences |
| 9 | import android.os.Bundle | 8 | import android.os.Bundle |
| @@ -18,14 +17,9 @@ import androidx.core.view.updatePadding | |||
| 18 | import androidx.core.widget.doOnTextChanged | 17 | import androidx.core.widget.doOnTextChanged |
| 19 | import androidx.fragment.app.Fragment | 18 | import androidx.fragment.app.Fragment |
| 20 | import androidx.fragment.app.activityViewModels | 19 | import androidx.fragment.app.activityViewModels |
| 21 | import androidx.lifecycle.Lifecycle | ||
| 22 | import androidx.lifecycle.lifecycleScope | ||
| 23 | import androidx.lifecycle.repeatOnLifecycle | ||
| 24 | import androidx.preference.PreferenceManager | 20 | import androidx.preference.PreferenceManager |
| 25 | import info.debatty.java.stringsimilarity.Jaccard | 21 | import info.debatty.java.stringsimilarity.Jaccard |
| 26 | import info.debatty.java.stringsimilarity.JaroWinkler | 22 | import info.debatty.java.stringsimilarity.JaroWinkler |
| 27 | import kotlinx.coroutines.flow.collectLatest | ||
| 28 | import kotlinx.coroutines.launch | ||
| 29 | import java.util.Locale | 23 | import java.util.Locale |
| 30 | import org.yuzu.yuzu_emu.R | 24 | import org.yuzu.yuzu_emu.R |
| 31 | import org.yuzu.yuzu_emu.YuzuApplication | 25 | import org.yuzu.yuzu_emu.YuzuApplication |
| @@ -35,6 +29,8 @@ import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager | |||
| 35 | import org.yuzu.yuzu_emu.model.Game | 29 | import org.yuzu.yuzu_emu.model.Game |
| 36 | import org.yuzu.yuzu_emu.model.GamesViewModel | 30 | import org.yuzu.yuzu_emu.model.GamesViewModel |
| 37 | import org.yuzu.yuzu_emu.model.HomeViewModel | 31 | import org.yuzu.yuzu_emu.model.HomeViewModel |
| 32 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 33 | import org.yuzu.yuzu_emu.utils.collect | ||
| 38 | 34 | ||
| 39 | class SearchFragment : Fragment() { | 35 | class SearchFragment : Fragment() { |
| 40 | private var _binding: FragmentSearchBinding? = null | 36 | private var _binding: FragmentSearchBinding? = null |
| @@ -58,8 +54,6 @@ class SearchFragment : Fragment() { | |||
| 58 | return binding.root | 54 | return binding.root |
| 59 | } | 55 | } |
| 60 | 56 | ||
| 61 | // This is using the correct scope, lint is just acting up | ||
| 62 | @SuppressLint("UnsafeRepeatOnLifecycleDetector") | ||
| 63 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | 57 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| 64 | super.onViewCreated(view, savedInstanceState) | 58 | super.onViewCreated(view, savedInstanceState) |
| 65 | homeViewModel.setNavigationVisibility(visible = true, animated = true) | 59 | homeViewModel.setNavigationVisibility(visible = true, animated = true) |
| @@ -81,42 +75,18 @@ class SearchFragment : Fragment() { | |||
| 81 | binding.chipGroup.setOnCheckedStateChangeListener { _, _ -> filterAndSearch() } | 75 | binding.chipGroup.setOnCheckedStateChangeListener { _, _ -> filterAndSearch() } |
| 82 | 76 | ||
| 83 | binding.searchText.doOnTextChanged { text: CharSequence?, _: Int, _: Int, _: Int -> | 77 | binding.searchText.doOnTextChanged { text: CharSequence?, _: Int, _: Int, _: Int -> |
| 84 | if (text.toString().isNotEmpty()) { | 78 | binding.clearButton.setVisible(text.toString().isNotEmpty()) |
| 85 | binding.clearButton.visibility = View.VISIBLE | ||
| 86 | } else { | ||
| 87 | binding.clearButton.visibility = View.INVISIBLE | ||
| 88 | } | ||
| 89 | filterAndSearch() | 79 | filterAndSearch() |
| 90 | } | 80 | } |
| 91 | 81 | ||
| 92 | viewLifecycleOwner.lifecycleScope.apply { | 82 | gamesViewModel.searchFocused.collect( |
| 93 | launch { | 83 | viewLifecycleOwner, |
| 94 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 84 | resetState = { gamesViewModel.setSearchFocused(false) } |
| 95 | gamesViewModel.searchFocused.collect { | 85 | ) { if (it) focusSearch() } |
| 96 | if (it) { | 86 | gamesViewModel.games.collect(viewLifecycleOwner) { filterAndSearch() } |
| 97 | focusSearch() | 87 | gamesViewModel.searchedGames.collect(viewLifecycleOwner) { |
| 98 | gamesViewModel.setSearchFocused(false) | 88 | (binding.gridGamesSearch.adapter as GameAdapter).submitList(it) |
| 99 | } | 89 | binding.noResultsView.setVisible(it.isNotEmpty()) |
| 100 | } | ||
| 101 | } | ||
| 102 | } | ||
| 103 | launch { | ||
| 104 | repeatOnLifecycle(Lifecycle.State.CREATED) { | ||
| 105 | gamesViewModel.games.collectLatest { filterAndSearch() } | ||
| 106 | } | ||
| 107 | } | ||
| 108 | launch { | ||
| 109 | repeatOnLifecycle(Lifecycle.State.CREATED) { | ||
| 110 | gamesViewModel.searchedGames.collect { | ||
| 111 | (binding.gridGamesSearch.adapter as GameAdapter).submitList(it) | ||
| 112 | if (it.isEmpty()) { | ||
| 113 | binding.noResultsView.visibility = View.VISIBLE | ||
| 114 | } else { | ||
| 115 | binding.noResultsView.visibility = View.GONE | ||
| 116 | } | ||
| 117 | } | ||
| 118 | } | ||
| 119 | } | ||
| 120 | } | 90 | } |
| 121 | 91 | ||
| 122 | binding.clearButton.setOnClickListener { binding.searchText.setText("") } | 92 | binding.clearButton.setOnClickListener { binding.searchText.setText("") } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt index ebf41a639..4f7548e98 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | package org.yuzu.yuzu_emu.fragments | 4 | package org.yuzu.yuzu_emu.fragments |
| 5 | 5 | ||
| 6 | import android.Manifest | 6 | import android.Manifest |
| 7 | import android.annotation.SuppressLint | ||
| 8 | import android.content.Intent | 7 | import android.content.Intent |
| 9 | import android.os.Build | 8 | import android.os.Build |
| 10 | import android.os.Bundle | 9 | import android.os.Bundle |
| @@ -23,9 +22,6 @@ import androidx.core.view.isVisible | |||
| 23 | import androidx.core.view.updatePadding | 22 | import androidx.core.view.updatePadding |
| 24 | import androidx.fragment.app.Fragment | 23 | import androidx.fragment.app.Fragment |
| 25 | import androidx.fragment.app.activityViewModels | 24 | import androidx.fragment.app.activityViewModels |
| 26 | import androidx.lifecycle.Lifecycle | ||
| 27 | import androidx.lifecycle.lifecycleScope | ||
| 28 | import androidx.lifecycle.repeatOnLifecycle | ||
| 29 | import androidx.navigation.findNavController | 25 | import androidx.navigation.findNavController |
| 30 | import androidx.preference.PreferenceManager | 26 | import androidx.preference.PreferenceManager |
| 31 | import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback | 27 | import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback |
| @@ -46,6 +42,8 @@ import org.yuzu.yuzu_emu.ui.main.MainActivity | |||
| 46 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization | 42 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization |
| 47 | import org.yuzu.yuzu_emu.utils.NativeConfig | 43 | import org.yuzu.yuzu_emu.utils.NativeConfig |
| 48 | import org.yuzu.yuzu_emu.utils.ViewUtils | 44 | import org.yuzu.yuzu_emu.utils.ViewUtils |
| 45 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 46 | import org.yuzu.yuzu_emu.utils.collect | ||
| 49 | 47 | ||
| 50 | class SetupFragment : Fragment() { | 48 | class SetupFragment : Fragment() { |
| 51 | private var _binding: FragmentSetupBinding? = null | 49 | private var _binding: FragmentSetupBinding? = null |
| @@ -77,8 +75,6 @@ class SetupFragment : Fragment() { | |||
| 77 | return binding.root | 75 | return binding.root |
| 78 | } | 76 | } |
| 79 | 77 | ||
| 80 | // This is using the correct scope, lint is just acting up | ||
| 81 | @SuppressLint("UnsafeRepeatOnLifecycleDetector") | ||
| 82 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | 78 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| 83 | mainActivity = requireActivity() as MainActivity | 79 | mainActivity = requireActivity() as MainActivity |
| 84 | 80 | ||
| @@ -210,28 +206,14 @@ class SetupFragment : Fragment() { | |||
| 210 | ) | 206 | ) |
| 211 | } | 207 | } |
| 212 | 208 | ||
| 213 | viewLifecycleOwner.lifecycleScope.apply { | 209 | homeViewModel.shouldPageForward.collect( |
| 214 | launch { | 210 | viewLifecycleOwner, |
| 215 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 211 | resetState = { homeViewModel.setShouldPageForward(false) } |
| 216 | homeViewModel.shouldPageForward.collect { | 212 | ) { if (it) pageForward() } |
| 217 | if (it) { | 213 | homeViewModel.gamesDirSelected.collect( |
| 218 | pageForward() | 214 | viewLifecycleOwner, |
| 219 | homeViewModel.setShouldPageForward(false) | 215 | resetState = { homeViewModel.setGamesDirSelected(false) } |
| 220 | } | 216 | ) { if (it) gamesDirCallback.onStepCompleted() } |
| 221 | } | ||
| 222 | } | ||
| 223 | } | ||
| 224 | launch { | ||
| 225 | repeatOnLifecycle(Lifecycle.State.CREATED) { | ||
| 226 | homeViewModel.gamesDirSelected.collect { | ||
| 227 | if (it) { | ||
| 228 | gamesDirCallback.onStepCompleted() | ||
| 229 | homeViewModel.setGamesDirSelected(false) | ||
| 230 | } | ||
| 231 | } | ||
| 232 | } | ||
| 233 | } | ||
| 234 | } | ||
| 235 | 217 | ||
| 236 | binding.viewPager2.apply { | 218 | binding.viewPager2.apply { |
| 237 | adapter = SetupAdapter(requireActivity() as AppCompatActivity, pages) | 219 | adapter = SetupAdapter(requireActivity() as AppCompatActivity, pages) |
| @@ -292,12 +274,8 @@ class SetupFragment : Fragment() { | |||
| 292 | val backIsVisible = savedInstanceState.getBoolean(KEY_BACK_VISIBILITY) | 274 | val backIsVisible = savedInstanceState.getBoolean(KEY_BACK_VISIBILITY) |
| 293 | hasBeenWarned = savedInstanceState.getBooleanArray(KEY_HAS_BEEN_WARNED)!! | 275 | hasBeenWarned = savedInstanceState.getBooleanArray(KEY_HAS_BEEN_WARNED)!! |
| 294 | 276 | ||
| 295 | if (nextIsVisible) { | 277 | binding.buttonNext.setVisible(nextIsVisible) |
| 296 | binding.buttonNext.visibility = View.VISIBLE | 278 | binding.buttonBack.setVisible(backIsVisible) |
| 297 | } | ||
| 298 | if (backIsVisible) { | ||
| 299 | binding.buttonBack.visibility = View.VISIBLE | ||
| 300 | } | ||
| 301 | } else { | 279 | } else { |
| 302 | hasBeenWarned = BooleanArray(pages.size) | 280 | hasBeenWarned = BooleanArray(pages.size) |
| 303 | } | 281 | } |
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 c87486c90..ed112a38d 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 | |||
| @@ -24,10 +24,10 @@ import androidx.core.content.ContextCompat | |||
| 24 | import androidx.window.layout.WindowMetricsCalculator | 24 | import androidx.window.layout.WindowMetricsCalculator |
| 25 | import kotlin.math.max | 25 | import kotlin.math.max |
| 26 | import kotlin.math.min | 26 | import kotlin.math.min |
| 27 | import org.yuzu.yuzu_emu.NativeLibrary | 27 | import org.yuzu.yuzu_emu.features.input.NativeInput |
| 28 | import org.yuzu.yuzu_emu.NativeLibrary.ButtonType | ||
| 29 | import org.yuzu.yuzu_emu.NativeLibrary.StickType | ||
| 30 | import org.yuzu.yuzu_emu.R | 28 | import org.yuzu.yuzu_emu.R |
| 29 | import org.yuzu.yuzu_emu.features.input.model.NativeAnalog | ||
| 30 | import org.yuzu.yuzu_emu.features.input.model.NativeButton | ||
| 31 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting | 31 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting |
| 32 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting | 32 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting |
| 33 | import org.yuzu.yuzu_emu.overlay.model.OverlayControl | 33 | import org.yuzu.yuzu_emu.overlay.model.OverlayControl |
| @@ -100,19 +100,19 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 100 | 100 | ||
| 101 | var shouldUpdateView = false | 101 | var shouldUpdateView = false |
| 102 | val playerIndex = | 102 | val playerIndex = |
| 103 | if (NativeLibrary.isHandheldOnly()) { | 103 | if (NativeInput.isHandheldOnly()) { |
| 104 | NativeLibrary.ConsoleDevice | 104 | NativeInput.ConsoleDevice |
| 105 | } else { | 105 | } else { |
| 106 | NativeLibrary.Player1Device | 106 | NativeInput.Player1Device |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | for (button in overlayButtons) { | 109 | for (button in overlayButtons) { |
| 110 | if (!button.updateStatus(event)) { | 110 | if (!button.updateStatus(event)) { |
| 111 | continue | 111 | continue |
| 112 | } | 112 | } |
| 113 | NativeLibrary.onGamePadButtonEvent( | 113 | NativeInput.onOverlayButtonEvent( |
| 114 | playerIndex, | 114 | playerIndex, |
| 115 | button.buttonId, | 115 | button.button, |
| 116 | button.status | 116 | button.status |
| 117 | ) | 117 | ) |
| 118 | playHaptics(event) | 118 | playHaptics(event) |
| @@ -123,24 +123,24 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 123 | if (!dpad.updateStatus(event, BooleanSetting.DPAD_SLIDE.getBoolean())) { | 123 | if (!dpad.updateStatus(event, BooleanSetting.DPAD_SLIDE.getBoolean())) { |
| 124 | continue | 124 | continue |
| 125 | } | 125 | } |
| 126 | NativeLibrary.onGamePadButtonEvent( | 126 | NativeInput.onOverlayButtonEvent( |
| 127 | playerIndex, | 127 | playerIndex, |
| 128 | dpad.upId, | 128 | dpad.up, |
| 129 | dpad.upStatus | 129 | dpad.upStatus |
| 130 | ) | 130 | ) |
| 131 | NativeLibrary.onGamePadButtonEvent( | 131 | NativeInput.onOverlayButtonEvent( |
| 132 | playerIndex, | 132 | playerIndex, |
| 133 | dpad.downId, | 133 | dpad.down, |
| 134 | dpad.downStatus | 134 | dpad.downStatus |
| 135 | ) | 135 | ) |
| 136 | NativeLibrary.onGamePadButtonEvent( | 136 | NativeInput.onOverlayButtonEvent( |
| 137 | playerIndex, | 137 | playerIndex, |
| 138 | dpad.leftId, | 138 | dpad.left, |
| 139 | dpad.leftStatus | 139 | dpad.leftStatus |
| 140 | ) | 140 | ) |
| 141 | NativeLibrary.onGamePadButtonEvent( | 141 | NativeInput.onOverlayButtonEvent( |
| 142 | playerIndex, | 142 | playerIndex, |
| 143 | dpad.rightId, | 143 | dpad.right, |
| 144 | dpad.rightStatus | 144 | dpad.rightStatus |
| 145 | ) | 145 | ) |
| 146 | playHaptics(event) | 146 | playHaptics(event) |
| @@ -151,16 +151,15 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 151 | if (!joystick.updateStatus(event)) { | 151 | if (!joystick.updateStatus(event)) { |
| 152 | continue | 152 | continue |
| 153 | } | 153 | } |
| 154 | val axisID = joystick.joystickId | 154 | NativeInput.onOverlayJoystickEvent( |
| 155 | NativeLibrary.onGamePadJoystickEvent( | ||
| 156 | playerIndex, | 155 | playerIndex, |
| 157 | axisID, | 156 | joystick.joystick, |
| 158 | joystick.xAxis, | 157 | joystick.xAxis, |
| 159 | joystick.realYAxis | 158 | joystick.realYAxis |
| 160 | ) | 159 | ) |
| 161 | NativeLibrary.onGamePadButtonEvent( | 160 | NativeInput.onOverlayButtonEvent( |
| 162 | playerIndex, | 161 | playerIndex, |
| 163 | joystick.buttonId, | 162 | joystick.button, |
| 164 | joystick.buttonStatus | 163 | joystick.buttonStatus |
| 165 | ) | 164 | ) |
| 166 | playHaptics(event) | 165 | playHaptics(event) |
| @@ -187,7 +186,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 187 | motionEvent == MotionEvent.ACTION_UP || motionEvent == MotionEvent.ACTION_POINTER_UP | 186 | motionEvent == MotionEvent.ACTION_UP || motionEvent == MotionEvent.ACTION_POINTER_UP |
| 188 | 187 | ||
| 189 | if (isActionDown && !isTouchInputConsumed(pointerId)) { | 188 | if (isActionDown && !isTouchInputConsumed(pointerId)) { |
| 190 | NativeLibrary.onTouchPressed(pointerId, xPosition.toFloat(), yPosition.toFloat()) | 189 | NativeInput.onTouchPressed(pointerId, xPosition.toFloat(), yPosition.toFloat()) |
| 191 | } | 190 | } |
| 192 | 191 | ||
| 193 | if (isActionMove) { | 192 | if (isActionMove) { |
| @@ -196,12 +195,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 196 | if (isTouchInputConsumed(fingerId)) { | 195 | if (isTouchInputConsumed(fingerId)) { |
| 197 | continue | 196 | continue |
| 198 | } | 197 | } |
| 199 | NativeLibrary.onTouchMoved(fingerId, event.getX(i), event.getY(i)) | 198 | NativeInput.onTouchMoved(fingerId, event.getX(i), event.getY(i)) |
| 200 | } | 199 | } |
| 201 | } | 200 | } |
| 202 | 201 | ||
| 203 | if (isActionUp && !isTouchInputConsumed(pointerId)) { | 202 | if (isActionUp && !isTouchInputConsumed(pointerId)) { |
| 204 | NativeLibrary.onTouchReleased(pointerId) | 203 | NativeInput.onTouchReleased(pointerId) |
| 205 | } | 204 | } |
| 206 | 205 | ||
| 207 | return true | 206 | return true |
| @@ -359,7 +358,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 359 | windowSize, | 358 | windowSize, |
| 360 | R.drawable.facebutton_a, | 359 | R.drawable.facebutton_a, |
| 361 | R.drawable.facebutton_a_depressed, | 360 | R.drawable.facebutton_a_depressed, |
| 362 | ButtonType.BUTTON_A, | 361 | NativeButton.A, |
| 363 | data, | 362 | data, |
| 364 | position | 363 | position |
| 365 | ) | 364 | ) |
| @@ -373,7 +372,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 373 | windowSize, | 372 | windowSize, |
| 374 | R.drawable.facebutton_b, | 373 | R.drawable.facebutton_b, |
| 375 | R.drawable.facebutton_b_depressed, | 374 | R.drawable.facebutton_b_depressed, |
| 376 | ButtonType.BUTTON_B, | 375 | NativeButton.B, |
| 377 | data, | 376 | data, |
| 378 | position | 377 | position |
| 379 | ) | 378 | ) |
| @@ -387,7 +386,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 387 | windowSize, | 386 | windowSize, |
| 388 | R.drawable.facebutton_x, | 387 | R.drawable.facebutton_x, |
| 389 | R.drawable.facebutton_x_depressed, | 388 | R.drawable.facebutton_x_depressed, |
| 390 | ButtonType.BUTTON_X, | 389 | NativeButton.X, |
| 391 | data, | 390 | data, |
| 392 | position | 391 | position |
| 393 | ) | 392 | ) |
| @@ -401,7 +400,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 401 | windowSize, | 400 | windowSize, |
| 402 | R.drawable.facebutton_y, | 401 | R.drawable.facebutton_y, |
| 403 | R.drawable.facebutton_y_depressed, | 402 | R.drawable.facebutton_y_depressed, |
| 404 | ButtonType.BUTTON_Y, | 403 | NativeButton.Y, |
| 405 | data, | 404 | data, |
| 406 | position | 405 | position |
| 407 | ) | 406 | ) |
| @@ -415,7 +414,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 415 | windowSize, | 414 | windowSize, |
| 416 | R.drawable.facebutton_plus, | 415 | R.drawable.facebutton_plus, |
| 417 | R.drawable.facebutton_plus_depressed, | 416 | R.drawable.facebutton_plus_depressed, |
| 418 | ButtonType.BUTTON_PLUS, | 417 | NativeButton.Plus, |
| 419 | data, | 418 | data, |
| 420 | position | 419 | position |
| 421 | ) | 420 | ) |
| @@ -429,7 +428,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 429 | windowSize, | 428 | windowSize, |
| 430 | R.drawable.facebutton_minus, | 429 | R.drawable.facebutton_minus, |
| 431 | R.drawable.facebutton_minus_depressed, | 430 | R.drawable.facebutton_minus_depressed, |
| 432 | ButtonType.BUTTON_MINUS, | 431 | NativeButton.Minus, |
| 433 | data, | 432 | data, |
| 434 | position | 433 | position |
| 435 | ) | 434 | ) |
| @@ -443,7 +442,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 443 | windowSize, | 442 | windowSize, |
| 444 | R.drawable.facebutton_home, | 443 | R.drawable.facebutton_home, |
| 445 | R.drawable.facebutton_home_depressed, | 444 | R.drawable.facebutton_home_depressed, |
| 446 | ButtonType.BUTTON_HOME, | 445 | NativeButton.Home, |
| 447 | data, | 446 | data, |
| 448 | position | 447 | position |
| 449 | ) | 448 | ) |
| @@ -457,7 +456,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 457 | windowSize, | 456 | windowSize, |
| 458 | R.drawable.facebutton_screenshot, | 457 | R.drawable.facebutton_screenshot, |
| 459 | R.drawable.facebutton_screenshot_depressed, | 458 | R.drawable.facebutton_screenshot_depressed, |
| 460 | ButtonType.BUTTON_CAPTURE, | 459 | NativeButton.Capture, |
| 461 | data, | 460 | data, |
| 462 | position | 461 | position |
| 463 | ) | 462 | ) |
| @@ -471,7 +470,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 471 | windowSize, | 470 | windowSize, |
| 472 | R.drawable.l_shoulder, | 471 | R.drawable.l_shoulder, |
| 473 | R.drawable.l_shoulder_depressed, | 472 | R.drawable.l_shoulder_depressed, |
| 474 | ButtonType.TRIGGER_L, | 473 | NativeButton.L, |
| 475 | data, | 474 | data, |
| 476 | position | 475 | position |
| 477 | ) | 476 | ) |
| @@ -485,7 +484,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 485 | windowSize, | 484 | windowSize, |
| 486 | R.drawable.r_shoulder, | 485 | R.drawable.r_shoulder, |
| 487 | R.drawable.r_shoulder_depressed, | 486 | R.drawable.r_shoulder_depressed, |
| 488 | ButtonType.TRIGGER_R, | 487 | NativeButton.R, |
| 489 | data, | 488 | data, |
| 490 | position | 489 | position |
| 491 | ) | 490 | ) |
| @@ -499,7 +498,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 499 | windowSize, | 498 | windowSize, |
| 500 | R.drawable.zl_trigger, | 499 | R.drawable.zl_trigger, |
| 501 | R.drawable.zl_trigger_depressed, | 500 | R.drawable.zl_trigger_depressed, |
| 502 | ButtonType.TRIGGER_ZL, | 501 | NativeButton.ZL, |
| 503 | data, | 502 | data, |
| 504 | position | 503 | position |
| 505 | ) | 504 | ) |
| @@ -513,7 +512,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 513 | windowSize, | 512 | windowSize, |
| 514 | R.drawable.zr_trigger, | 513 | R.drawable.zr_trigger, |
| 515 | R.drawable.zr_trigger_depressed, | 514 | R.drawable.zr_trigger_depressed, |
| 516 | ButtonType.TRIGGER_ZR, | 515 | NativeButton.ZR, |
| 517 | data, | 516 | data, |
| 518 | position | 517 | position |
| 519 | ) | 518 | ) |
| @@ -527,7 +526,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 527 | windowSize, | 526 | windowSize, |
| 528 | R.drawable.button_l3, | 527 | R.drawable.button_l3, |
| 529 | R.drawable.button_l3_depressed, | 528 | R.drawable.button_l3_depressed, |
| 530 | ButtonType.STICK_L, | 529 | NativeButton.LStick, |
| 531 | data, | 530 | data, |
| 532 | position | 531 | position |
| 533 | ) | 532 | ) |
| @@ -541,7 +540,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 541 | windowSize, | 540 | windowSize, |
| 542 | R.drawable.button_r3, | 541 | R.drawable.button_r3, |
| 543 | R.drawable.button_r3_depressed, | 542 | R.drawable.button_r3_depressed, |
| 544 | ButtonType.STICK_R, | 543 | NativeButton.RStick, |
| 545 | data, | 544 | data, |
| 546 | position | 545 | position |
| 547 | ) | 546 | ) |
| @@ -556,8 +555,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 556 | R.drawable.joystick_range, | 555 | R.drawable.joystick_range, |
| 557 | R.drawable.joystick, | 556 | R.drawable.joystick, |
| 558 | R.drawable.joystick_depressed, | 557 | R.drawable.joystick_depressed, |
| 559 | StickType.STICK_L, | 558 | NativeAnalog.LStick, |
| 560 | ButtonType.STICK_L, | 559 | NativeButton.LStick, |
| 561 | data, | 560 | data, |
| 562 | position | 561 | position |
| 563 | ) | 562 | ) |
| @@ -572,8 +571,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 572 | R.drawable.joystick_range, | 571 | R.drawable.joystick_range, |
| 573 | R.drawable.joystick, | 572 | R.drawable.joystick, |
| 574 | R.drawable.joystick_depressed, | 573 | R.drawable.joystick_depressed, |
| 575 | StickType.STICK_R, | 574 | NativeAnalog.RStick, |
| 576 | ButtonType.STICK_R, | 575 | NativeButton.RStick, |
| 577 | data, | 576 | data, |
| 578 | position | 577 | position |
| 579 | ) | 578 | ) |
| @@ -665,7 +664,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 665 | 664 | ||
| 666 | val overlayControlData = NativeConfig.getOverlayControlData() | 665 | val overlayControlData = NativeConfig.getOverlayControlData() |
| 667 | overlayControlData.forEach { | 666 | overlayControlData.forEach { |
| 668 | it.enabled = OverlayControl.from(it.id)?.defaultVisibility == false | 667 | it.enabled = OverlayControl.from(it.id)?.defaultVisibility == true |
| 669 | } | 668 | } |
| 670 | NativeConfig.setOverlayControlData(overlayControlData) | 669 | NativeConfig.setOverlayControlData(overlayControlData) |
| 671 | 670 | ||
| @@ -835,7 +834,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 835 | windowSize: Pair<Point, Point>, | 834 | windowSize: Pair<Point, Point>, |
| 836 | defaultResId: Int, | 835 | defaultResId: Int, |
| 837 | pressedResId: Int, | 836 | pressedResId: Int, |
| 838 | buttonId: Int, | 837 | button: NativeButton, |
| 839 | overlayControlData: OverlayControlData, | 838 | overlayControlData: OverlayControlData, |
| 840 | position: Pair<Double, Double> | 839 | position: Pair<Double, Double> |
| 841 | ): InputOverlayDrawableButton { | 840 | ): InputOverlayDrawableButton { |
| @@ -869,7 +868,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 869 | res, | 868 | res, |
| 870 | defaultStateBitmap, | 869 | defaultStateBitmap, |
| 871 | pressedStateBitmap, | 870 | pressedStateBitmap, |
| 872 | buttonId, | 871 | button, |
| 873 | overlayControlData | 872 | overlayControlData |
| 874 | ) | 873 | ) |
| 875 | 874 | ||
| @@ -940,11 +939,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 940 | res, | 939 | res, |
| 941 | defaultStateBitmap, | 940 | defaultStateBitmap, |
| 942 | pressedOneDirectionStateBitmap, | 941 | pressedOneDirectionStateBitmap, |
| 943 | pressedTwoDirectionsStateBitmap, | 942 | pressedTwoDirectionsStateBitmap |
| 944 | ButtonType.DPAD_UP, | ||
| 945 | ButtonType.DPAD_DOWN, | ||
| 946 | ButtonType.DPAD_LEFT, | ||
| 947 | ButtonType.DPAD_RIGHT | ||
| 948 | ) | 943 | ) |
| 949 | 944 | ||
| 950 | // Get the minimum and maximum coordinates of the screen where the button can be placed. | 945 | // Get the minimum and maximum coordinates of the screen where the button can be placed. |
| @@ -993,8 +988,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 993 | resOuter: Int, | 988 | resOuter: Int, |
| 994 | defaultResInner: Int, | 989 | defaultResInner: Int, |
| 995 | pressedResInner: Int, | 990 | pressedResInner: Int, |
| 996 | joystick: Int, | 991 | joystick: NativeAnalog, |
| 997 | buttonId: Int, | 992 | button: NativeButton, |
| 998 | overlayControlData: OverlayControlData, | 993 | overlayControlData: OverlayControlData, |
| 999 | position: Pair<Double, Double> | 994 | position: Pair<Double, Double> |
| 1000 | ): InputOverlayDrawableJoystick { | 995 | ): InputOverlayDrawableJoystick { |
| @@ -1042,7 +1037,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : | |||
| 1042 | outerRect, | 1037 | outerRect, |
| 1043 | innerRect, | 1038 | innerRect, |
| 1044 | joystick, | 1039 | joystick, |
| 1045 | buttonId, | 1040 | button, |
| 1046 | overlayControlData.id | 1041 | overlayControlData.id |
| 1047 | ) | 1042 | ) |
| 1048 | 1043 | ||
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 b14a4f96e..fee3d04ee 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 | |||
| @@ -9,7 +9,8 @@ import android.graphics.Canvas | |||
| 9 | import android.graphics.Rect | 9 | 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.features.input.NativeInput.ButtonState |
| 13 | import org.yuzu.yuzu_emu.features.input.model.NativeButton | ||
| 13 | import org.yuzu.yuzu_emu.overlay.model.OverlayControlData | 14 | import org.yuzu.yuzu_emu.overlay.model.OverlayControlData |
| 14 | 15 | ||
| 15 | /** | 16 | /** |
| @@ -19,13 +20,13 @@ import org.yuzu.yuzu_emu.overlay.model.OverlayControlData | |||
| 19 | * @param res [Resources] instance. | 20 | * @param res [Resources] instance. |
| 20 | * @param defaultStateBitmap [Bitmap] to use with the default state Drawable. | 21 | * @param defaultStateBitmap [Bitmap] to use with the default state Drawable. |
| 21 | * @param pressedStateBitmap [Bitmap] to use with the pressed state Drawable. | 22 | * @param pressedStateBitmap [Bitmap] to use with the pressed state Drawable. |
| 22 | * @param buttonId Identifier for this type of button. | 23 | * @param button [NativeButton] for this type of button. |
| 23 | */ | 24 | */ |
| 24 | class InputOverlayDrawableButton( | 25 | class InputOverlayDrawableButton( |
| 25 | res: Resources, | 26 | res: Resources, |
| 26 | defaultStateBitmap: Bitmap, | 27 | defaultStateBitmap: Bitmap, |
| 27 | pressedStateBitmap: Bitmap, | 28 | pressedStateBitmap: Bitmap, |
| 28 | val buttonId: Int, | 29 | val button: NativeButton, |
| 29 | val overlayControlData: OverlayControlData | 30 | val overlayControlData: OverlayControlData |
| 30 | ) { | 31 | ) { |
| 31 | // The ID value what motion event is tracking | 32 | // The ID value what motion event is tracking |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableDpad.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableDpad.kt index 8aef6f5a5..0cb6ff244 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableDpad.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableDpad.kt | |||
| @@ -9,7 +9,8 @@ import android.graphics.Canvas | |||
| 9 | import android.graphics.Rect | 9 | 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.features.input.NativeInput.ButtonState |
| 13 | import org.yuzu.yuzu_emu.features.input.model.NativeButton | ||
| 13 | 14 | ||
| 14 | /** | 15 | /** |
| 15 | * Custom [BitmapDrawable] that is capable | 16 | * Custom [BitmapDrawable] that is capable |
| @@ -19,20 +20,12 @@ import org.yuzu.yuzu_emu.NativeLibrary.ButtonState | |||
| 19 | * @param defaultStateBitmap [Bitmap] of the default state. | 20 | * @param defaultStateBitmap [Bitmap] of the default state. |
| 20 | * @param pressedOneDirectionStateBitmap [Bitmap] of the pressed state in one direction. | 21 | * @param pressedOneDirectionStateBitmap [Bitmap] of the pressed state in one direction. |
| 21 | * @param pressedTwoDirectionsStateBitmap [Bitmap] of the pressed state in two direction. | 22 | * @param pressedTwoDirectionsStateBitmap [Bitmap] of the pressed state in two direction. |
| 22 | * @param buttonUp Identifier for the up button. | ||
| 23 | * @param buttonDown Identifier for the down button. | ||
| 24 | * @param buttonLeft Identifier for the left button. | ||
| 25 | * @param buttonRight Identifier for the right button. | ||
| 26 | */ | 23 | */ |
| 27 | class InputOverlayDrawableDpad( | 24 | class InputOverlayDrawableDpad( |
| 28 | res: Resources, | 25 | res: Resources, |
| 29 | defaultStateBitmap: Bitmap, | 26 | defaultStateBitmap: Bitmap, |
| 30 | pressedOneDirectionStateBitmap: Bitmap, | 27 | pressedOneDirectionStateBitmap: Bitmap, |
| 31 | pressedTwoDirectionsStateBitmap: Bitmap, | 28 | pressedTwoDirectionsStateBitmap: Bitmap |
| 32 | buttonUp: Int, | ||
| 33 | buttonDown: Int, | ||
| 34 | buttonLeft: Int, | ||
| 35 | buttonRight: Int | ||
| 36 | ) { | 29 | ) { |
| 37 | /** | 30 | /** |
| 38 | * Gets one of the InputOverlayDrawableDpad's button IDs. | 31 | * Gets one of the InputOverlayDrawableDpad's button IDs. |
| @@ -40,10 +33,10 @@ class InputOverlayDrawableDpad( | |||
| 40 | * @return the requested InputOverlayDrawableDpad's button ID. | 33 | * @return the requested InputOverlayDrawableDpad's button ID. |
| 41 | */ | 34 | */ |
| 42 | // The ID identifying what type of button this Drawable represents. | 35 | // The ID identifying what type of button this Drawable represents. |
| 43 | val upId: Int | 36 | val up = NativeButton.DUp |
| 44 | val downId: Int | 37 | val down = NativeButton.DDown |
| 45 | val leftId: Int | 38 | val left = NativeButton.DLeft |
| 46 | val rightId: Int | 39 | val right = NativeButton.DRight |
| 47 | var trackId: Int | 40 | var trackId: Int |
| 48 | 41 | ||
| 49 | val width: Int | 42 | val width: Int |
| @@ -69,10 +62,6 @@ class InputOverlayDrawableDpad( | |||
| 69 | this.pressedTwoDirectionsStateBitmap = BitmapDrawable(res, pressedTwoDirectionsStateBitmap) | 62 | this.pressedTwoDirectionsStateBitmap = BitmapDrawable(res, pressedTwoDirectionsStateBitmap) |
| 70 | width = this.defaultStateBitmap.intrinsicWidth | 63 | width = this.defaultStateBitmap.intrinsicWidth |
| 71 | height = this.defaultStateBitmap.intrinsicHeight | 64 | height = this.defaultStateBitmap.intrinsicHeight |
| 72 | upId = buttonUp | ||
| 73 | downId = buttonDown | ||
| 74 | leftId = buttonLeft | ||
| 75 | rightId = buttonRight | ||
| 76 | trackId = -1 | 65 | trackId = -1 |
| 77 | } | 66 | } |
| 78 | 67 | ||
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 113bf7c24..4b07107fc 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 | |||
| @@ -13,7 +13,9 @@ import kotlin.math.atan2 | |||
| 13 | import kotlin.math.cos | 13 | 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.features.input.NativeInput.ButtonState |
| 17 | import org.yuzu.yuzu_emu.features.input.model.NativeAnalog | ||
| 18 | import org.yuzu.yuzu_emu.features.input.model.NativeButton | ||
| 17 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting | 19 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting |
| 18 | 20 | ||
| 19 | /** | 21 | /** |
| @@ -26,8 +28,8 @@ import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting | |||
| 26 | * @param bitmapInnerPressed [Bitmap] which represents the pressed inner movable part of the joystick. | 28 | * @param bitmapInnerPressed [Bitmap] which represents the pressed inner movable part of the joystick. |
| 27 | * @param rectOuter [Rect] which represents the outer joystick bounds. | 29 | * @param rectOuter [Rect] which represents the outer joystick bounds. |
| 28 | * @param rectInner [Rect] which represents the inner joystick bounds. | 30 | * @param rectInner [Rect] which represents the inner joystick bounds. |
| 29 | * @param joystickId The ID value what type of joystick this Drawable represents. | 31 | * @param joystick The [NativeAnalog] this Drawable represents. |
| 30 | * @param buttonId The ID value what type of button this Drawable represents. | 32 | * @param button The [NativeButton] this Drawable represents. |
| 31 | */ | 33 | */ |
| 32 | class InputOverlayDrawableJoystick( | 34 | class InputOverlayDrawableJoystick( |
| 33 | res: Resources, | 35 | res: Resources, |
| @@ -36,8 +38,8 @@ class InputOverlayDrawableJoystick( | |||
| 36 | bitmapInnerPressed: Bitmap, | 38 | bitmapInnerPressed: Bitmap, |
| 37 | rectOuter: Rect, | 39 | rectOuter: Rect, |
| 38 | rectInner: Rect, | 40 | rectInner: Rect, |
| 39 | val joystickId: Int, | 41 | val joystick: NativeAnalog, |
| 40 | val buttonId: Int, | 42 | val button: NativeButton, |
| 41 | val prefId: String | 43 | val prefId: String |
| 42 | ) { | 44 | ) { |
| 43 | // The ID value what motion event is tracking | 45 | // The ID value what motion event is tracking |
| @@ -69,8 +71,7 @@ class InputOverlayDrawableJoystick( | |||
| 69 | 71 | ||
| 70 | // TODO: Add button support | 72 | // TODO: Add button support |
| 71 | val buttonStatus: Int | 73 | val buttonStatus: Int |
| 72 | get() = | 74 | get() = ButtonState.RELEASED |
| 73 | NativeLibrary.ButtonState.RELEASED | ||
| 74 | var bounds: Rect | 75 | var bounds: Rect |
| 75 | get() = outerBitmap.bounds | 76 | get() = outerBitmap.bounds |
| 76 | set(bounds) { | 77 | set(bounds) { |
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 23ca49b53..fadb20e39 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 | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.ui | 4 | package org.yuzu.yuzu_emu.ui |
| 5 | 5 | ||
| 6 | import android.annotation.SuppressLint | ||
| 7 | import android.os.Bundle | 6 | import android.os.Bundle |
| 8 | import android.view.LayoutInflater | 7 | import android.view.LayoutInflater |
| 9 | import android.view.View | 8 | import android.view.View |
| @@ -14,19 +13,16 @@ import androidx.core.view.WindowInsetsCompat | |||
| 14 | import androidx.core.view.updatePadding | 13 | import androidx.core.view.updatePadding |
| 15 | import androidx.fragment.app.Fragment | 14 | import androidx.fragment.app.Fragment |
| 16 | import androidx.fragment.app.activityViewModels | 15 | import androidx.fragment.app.activityViewModels |
| 17 | import androidx.lifecycle.Lifecycle | ||
| 18 | import androidx.lifecycle.lifecycleScope | ||
| 19 | import androidx.lifecycle.repeatOnLifecycle | ||
| 20 | import com.google.android.material.color.MaterialColors | 16 | import com.google.android.material.color.MaterialColors |
| 21 | import kotlinx.coroutines.flow.collectLatest | ||
| 22 | import kotlinx.coroutines.launch | ||
| 23 | import org.yuzu.yuzu_emu.R | 17 | import org.yuzu.yuzu_emu.R |
| 24 | import org.yuzu.yuzu_emu.adapters.GameAdapter | 18 | import org.yuzu.yuzu_emu.adapters.GameAdapter |
| 25 | import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding | 19 | import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding |
| 26 | import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager | 20 | import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager |
| 27 | import org.yuzu.yuzu_emu.model.GamesViewModel | 21 | import org.yuzu.yuzu_emu.model.GamesViewModel |
| 28 | import org.yuzu.yuzu_emu.model.HomeViewModel | 22 | import org.yuzu.yuzu_emu.model.HomeViewModel |
| 23 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 29 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins | 24 | import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins |
| 25 | import org.yuzu.yuzu_emu.utils.collect | ||
| 30 | 26 | ||
| 31 | class GamesFragment : Fragment() { | 27 | class GamesFragment : Fragment() { |
| 32 | private var _binding: FragmentGamesBinding? = null | 28 | private var _binding: FragmentGamesBinding? = null |
| @@ -44,8 +40,6 @@ class GamesFragment : Fragment() { | |||
| 44 | return binding.root | 40 | return binding.root |
| 45 | } | 41 | } |
| 46 | 42 | ||
| 47 | // This is using the correct scope, lint is just acting up | ||
| 48 | @SuppressLint("UnsafeRepeatOnLifecycleDetector") | ||
| 49 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | 43 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| 50 | super.onViewCreated(view, savedInstanceState) | 44 | super.onViewCreated(view, savedInstanceState) |
| 51 | homeViewModel.setNavigationVisibility(visible = true, animated = true) | 45 | homeViewModel.setNavigationVisibility(visible = true, animated = true) |
| @@ -88,49 +82,28 @@ class GamesFragment : Fragment() { | |||
| 88 | } | 82 | } |
| 89 | } | 83 | } |
| 90 | 84 | ||
| 91 | viewLifecycleOwner.lifecycleScope.apply { | 85 | gamesViewModel.isReloading.collect(viewLifecycleOwner) { |
| 92 | launch { | 86 | binding.swipeRefresh.isRefreshing = it |
| 93 | repeatOnLifecycle(Lifecycle.State.RESUMED) { | 87 | binding.noticeText.setVisible( |
| 94 | gamesViewModel.isReloading.collect { | 88 | visible = gamesViewModel.games.value.isEmpty() && !it, |
| 95 | binding.swipeRefresh.isRefreshing = it | 89 | gone = false |
| 96 | if (gamesViewModel.games.value.isEmpty() && !it) { | 90 | ) |
| 97 | binding.noticeText.visibility = View.VISIBLE | 91 | } |
| 98 | } else { | 92 | gamesViewModel.games.collect(viewLifecycleOwner) { |
| 99 | binding.noticeText.visibility = View.INVISIBLE | 93 | (binding.gridGames.adapter as GameAdapter).submitList(it) |
| 100 | } | 94 | } |
| 101 | } | 95 | gamesViewModel.shouldSwapData.collect( |
| 102 | } | 96 | viewLifecycleOwner, |
| 103 | } | 97 | resetState = { gamesViewModel.setShouldSwapData(false) } |
| 104 | launch { | 98 | ) { |
| 105 | repeatOnLifecycle(Lifecycle.State.RESUMED) { | 99 | if (it) { |
| 106 | gamesViewModel.games.collectLatest { | 100 | (binding.gridGames.adapter as GameAdapter).submitList(gamesViewModel.games.value) |
| 107 | (binding.gridGames.adapter as GameAdapter).submitList(it) | ||
| 108 | } | ||
| 109 | } | ||
| 110 | } | ||
| 111 | launch { | ||
| 112 | repeatOnLifecycle(Lifecycle.State.RESUMED) { | ||
| 113 | gamesViewModel.shouldSwapData.collect { | ||
| 114 | if (it) { | ||
| 115 | (binding.gridGames.adapter as GameAdapter).submitList( | ||
| 116 | gamesViewModel.games.value | ||
| 117 | ) | ||
| 118 | gamesViewModel.setShouldSwapData(false) | ||
| 119 | } | ||
| 120 | } | ||
| 121 | } | ||
| 122 | } | ||
| 123 | launch { | ||
| 124 | repeatOnLifecycle(Lifecycle.State.RESUMED) { | ||
| 125 | gamesViewModel.shouldScrollToTop.collect { | ||
| 126 | if (it) { | ||
| 127 | scrollToTop() | ||
| 128 | gamesViewModel.setShouldScrollToTop(false) | ||
| 129 | } | ||
| 130 | } | ||
| 131 | } | ||
| 132 | } | 101 | } |
| 133 | } | 102 | } |
| 103 | gamesViewModel.shouldScrollToTop.collect( | ||
| 104 | viewLifecycleOwner, | ||
| 105 | resetState = { gamesViewModel.setShouldScrollToTop(false) } | ||
| 106 | ) { if (it) scrollToTop() } | ||
| 134 | 107 | ||
| 135 | setInsets() | 108 | setInsets() |
| 136 | } | 109 | } |
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 4df4ac4c6..757463a0b 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 | |||
| @@ -19,9 +19,6 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen | |||
| 19 | import androidx.core.view.ViewCompat | 19 | import androidx.core.view.ViewCompat |
| 20 | import androidx.core.view.WindowCompat | 20 | import androidx.core.view.WindowCompat |
| 21 | import androidx.core.view.WindowInsetsCompat | 21 | import androidx.core.view.WindowInsetsCompat |
| 22 | import androidx.lifecycle.Lifecycle | ||
| 23 | import androidx.lifecycle.lifecycleScope | ||
| 24 | import androidx.lifecycle.repeatOnLifecycle | ||
| 25 | import androidx.navigation.NavController | 22 | import androidx.navigation.NavController |
| 26 | import androidx.navigation.fragment.NavHostFragment | 23 | import androidx.navigation.fragment.NavHostFragment |
| 27 | import androidx.navigation.ui.setupWithNavController | 24 | import androidx.navigation.ui.setupWithNavController |
| @@ -30,7 +27,6 @@ import com.google.android.material.color.MaterialColors | |||
| 30 | import com.google.android.material.navigation.NavigationBarView | 27 | import com.google.android.material.navigation.NavigationBarView |
| 31 | import java.io.File | 28 | import java.io.File |
| 32 | import java.io.FilenameFilter | 29 | import java.io.FilenameFilter |
| 33 | import kotlinx.coroutines.launch | ||
| 34 | import org.yuzu.yuzu_emu.HomeNavigationDirections | 30 | import org.yuzu.yuzu_emu.HomeNavigationDirections |
| 35 | import org.yuzu.yuzu_emu.NativeLibrary | 31 | import org.yuzu.yuzu_emu.NativeLibrary |
| 36 | import org.yuzu.yuzu_emu.R | 32 | import org.yuzu.yuzu_emu.R |
| @@ -47,6 +43,7 @@ import org.yuzu.yuzu_emu.model.InstallResult | |||
| 47 | import org.yuzu.yuzu_emu.model.TaskState | 43 | import org.yuzu.yuzu_emu.model.TaskState |
| 48 | import org.yuzu.yuzu_emu.model.TaskViewModel | 44 | import org.yuzu.yuzu_emu.model.TaskViewModel |
| 49 | import org.yuzu.yuzu_emu.utils.* | 45 | import org.yuzu.yuzu_emu.utils.* |
| 46 | import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible | ||
| 50 | import java.io.BufferedInputStream | 47 | import java.io.BufferedInputStream |
| 51 | import java.io.BufferedOutputStream | 48 | import java.io.BufferedOutputStream |
| 52 | import java.util.zip.ZipEntry | 49 | import java.util.zip.ZipEntry |
| @@ -139,42 +136,23 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 139 | 136 | ||
| 140 | // Prevents navigation from being drawn for a short time on recreation if set to hidden | 137 | // Prevents navigation from being drawn for a short time on recreation if set to hidden |
| 141 | if (!homeViewModel.navigationVisible.value.first) { | 138 | if (!homeViewModel.navigationVisible.value.first) { |
| 142 | binding.navigationView.visibility = View.INVISIBLE | 139 | binding.navigationView.setVisible(visible = false, gone = false) |
| 143 | binding.statusBarShade.visibility = View.INVISIBLE | 140 | binding.statusBarShade.setVisible(visible = false, gone = false) |
| 144 | } | 141 | } |
| 145 | 142 | ||
| 146 | lifecycleScope.apply { | 143 | homeViewModel.navigationVisible.collect(this) { showNavigation(it.first, it.second) } |
| 147 | launch { | 144 | homeViewModel.statusBarShadeVisible.collect(this) { showStatusBarShade(it) } |
| 148 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 145 | homeViewModel.contentToInstall.collect( |
| 149 | homeViewModel.navigationVisible.collect { showNavigation(it.first, it.second) } | 146 | this, |
| 150 | } | 147 | resetState = { homeViewModel.setContentToInstall(null) } |
| 151 | } | 148 | ) { |
| 152 | launch { | 149 | if (it != null) { |
| 153 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 150 | installContent(it) |
| 154 | homeViewModel.statusBarShadeVisible.collect { showStatusBarShade(it) } | ||
| 155 | } | ||
| 156 | } | ||
| 157 | launch { | ||
| 158 | repeatOnLifecycle(Lifecycle.State.CREATED) { | ||
| 159 | homeViewModel.contentToInstall.collect { | ||
| 160 | if (it != null) { | ||
| 161 | installContent(it) | ||
| 162 | homeViewModel.setContentToInstall(null) | ||
| 163 | } | ||
| 164 | } | ||
| 165 | } | ||
| 166 | } | ||
| 167 | launch { | ||
| 168 | repeatOnLifecycle(Lifecycle.State.CREATED) { | ||
| 169 | homeViewModel.checkKeys.collect { | ||
| 170 | if (it) { | ||
| 171 | checkKeys() | ||
| 172 | homeViewModel.setCheckKeys(false) | ||
| 173 | } | ||
| 174 | } | ||
| 175 | } | ||
| 176 | } | 151 | } |
| 177 | } | 152 | } |
| 153 | homeViewModel.checkKeys.collect(this, resetState = { homeViewModel.setCheckKeys(false) }) { | ||
| 154 | if (it) checkKeys() | ||
| 155 | } | ||
| 178 | 156 | ||
| 179 | setInsets() | 157 | setInsets() |
| 180 | } | 158 | } |
| @@ -214,18 +192,14 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 214 | 192 | ||
| 215 | private fun showNavigation(visible: Boolean, animated: Boolean) { | 193 | private fun showNavigation(visible: Boolean, animated: Boolean) { |
| 216 | if (!animated) { | 194 | if (!animated) { |
| 217 | if (visible) { | 195 | binding.navigationView.setVisible(visible) |
| 218 | binding.navigationView.visibility = View.VISIBLE | ||
| 219 | } else { | ||
| 220 | binding.navigationView.visibility = View.INVISIBLE | ||
| 221 | } | ||
| 222 | return | 196 | return |
| 223 | } | 197 | } |
| 224 | 198 | ||
| 225 | val smallLayout = resources.getBoolean(R.bool.small_layout) | 199 | val smallLayout = resources.getBoolean(R.bool.small_layout) |
| 226 | binding.navigationView.animate().apply { | 200 | binding.navigationView.animate().apply { |
| 227 | if (visible) { | 201 | if (visible) { |
| 228 | binding.navigationView.visibility = View.VISIBLE | 202 | binding.navigationView.setVisible(true) |
| 229 | duration = 300 | 203 | duration = 300 |
| 230 | interpolator = PathInterpolator(0.05f, 0.7f, 0.1f, 1f) | 204 | interpolator = PathInterpolator(0.05f, 0.7f, 0.1f, 1f) |
| 231 | 205 | ||
| @@ -264,7 +238,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 264 | } | 238 | } |
| 265 | }.withEndAction { | 239 | }.withEndAction { |
| 266 | if (!visible) { | 240 | if (!visible) { |
| 267 | binding.navigationView.visibility = View.INVISIBLE | 241 | binding.navigationView.setVisible(visible = false, gone = false) |
| 268 | } | 242 | } |
| 269 | }.start() | 243 | }.start() |
| 270 | } | 244 | } |
| @@ -272,7 +246,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 272 | private fun showStatusBarShade(visible: Boolean) { | 246 | private fun showStatusBarShade(visible: Boolean) { |
| 273 | binding.statusBarShade.animate().apply { | 247 | binding.statusBarShade.animate().apply { |
| 274 | if (visible) { | 248 | if (visible) { |
| 275 | binding.statusBarShade.visibility = View.VISIBLE | 249 | binding.statusBarShade.setVisible(true) |
| 276 | binding.statusBarShade.translationY = binding.statusBarShade.height.toFloat() * -2 | 250 | binding.statusBarShade.translationY = binding.statusBarShade.height.toFloat() * -2 |
| 277 | duration = 300 | 251 | duration = 300 |
| 278 | translationY(0f) | 252 | translationY(0f) |
| @@ -284,7 +258,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 284 | } | 258 | } |
| 285 | }.withEndAction { | 259 | }.withEndAction { |
| 286 | if (!visible) { | 260 | if (!visible) { |
| 287 | binding.statusBarShade.visibility = View.INVISIBLE | 261 | binding.statusBarShade.setVisible(visible = false, gone = false) |
| 288 | } | 262 | } |
| 289 | }.start() | 263 | }.start() |
| 290 | } | 264 | } |
| @@ -524,7 +498,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 524 | this@MainActivity, | 498 | this@MainActivity, |
| 525 | titleId = R.string.content_install_notice, | 499 | titleId = R.string.content_install_notice, |
| 526 | descriptionId = R.string.content_install_notice_description, | 500 | descriptionId = R.string.content_install_notice_description, |
| 527 | positiveAction = { homeViewModel.setContentToInstall(documents) } | 501 | positiveAction = { homeViewModel.setContentToInstall(documents) }, |
| 502 | negativeAction = {} | ||
| 528 | ) | 503 | ) |
| 529 | } | 504 | } |
| 530 | }.show(supportFragmentManager, ProgressDialogFragment.TAG) | 505 | }.show(supportFragmentManager, ProgressDialogFragment.TAG) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt index e63382e1d..2c7356e6a 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt | |||
| @@ -6,439 +6,89 @@ package org.yuzu.yuzu_emu.utils | |||
| 6 | import android.view.InputDevice | 6 | import android.view.InputDevice |
| 7 | import android.view.KeyEvent | 7 | import android.view.KeyEvent |
| 8 | import android.view.MotionEvent | 8 | import android.view.MotionEvent |
| 9 | import kotlin.math.sqrt | 9 | import org.yuzu.yuzu_emu.features.input.NativeInput |
| 10 | import org.yuzu.yuzu_emu.NativeLibrary | 10 | import org.yuzu.yuzu_emu.features.input.YuzuInputOverlayDevice |
| 11 | import org.yuzu.yuzu_emu.features.input.YuzuPhysicalDevice | ||
| 11 | 12 | ||
| 12 | object InputHandler { | 13 | object InputHandler { |
| 13 | private var controllerIds = getGameControllerIds() | 14 | var androidControllers = mapOf<Int, YuzuPhysicalDevice>() |
| 14 | 15 | var registeredControllers = mutableListOf<ParamPackage>() | |
| 15 | fun initialize() { | ||
| 16 | // Connect first controller | ||
| 17 | NativeLibrary.onGamePadConnectEvent(getPlayerNumber(NativeLibrary.Player1Device)) | ||
| 18 | } | ||
| 19 | |||
| 20 | fun updateControllerIds() { | ||
| 21 | controllerIds = getGameControllerIds() | ||
| 22 | } | ||
| 23 | 16 | ||
| 24 | fun dispatchKeyEvent(event: KeyEvent): Boolean { | 17 | fun dispatchKeyEvent(event: KeyEvent): Boolean { |
| 25 | val button: Int = when (event.device.vendorId) { | ||
| 26 | 0x045E -> getInputXboxButtonKey(event.keyCode) | ||
| 27 | 0x054C -> getInputDS5ButtonKey(event.keyCode) | ||
| 28 | 0x057E -> getInputJoyconButtonKey(event.keyCode) | ||
| 29 | 0x1532 -> getInputRazerButtonKey(event.keyCode) | ||
| 30 | 0x3537 -> getInputRedmagicButtonKey(event.keyCode) | ||
| 31 | 0x358A -> getInputBackboneLabsButtonKey(event.keyCode) | ||
| 32 | else -> getInputGenericButtonKey(event.keyCode) | ||
| 33 | } | ||
| 34 | |||
| 35 | val action = when (event.action) { | 18 | val action = when (event.action) { |
| 36 | KeyEvent.ACTION_DOWN -> NativeLibrary.ButtonState.PRESSED | 19 | KeyEvent.ACTION_DOWN -> NativeInput.ButtonState.PRESSED |
| 37 | KeyEvent.ACTION_UP -> NativeLibrary.ButtonState.RELEASED | 20 | KeyEvent.ACTION_UP -> NativeInput.ButtonState.RELEASED |
| 38 | else -> return false | 21 | else -> return false |
| 39 | } | 22 | } |
| 40 | 23 | ||
| 41 | // Ignore invalid buttons | 24 | var controllerData = androidControllers[event.device.controllerNumber] |
| 42 | if (button < 0) { | 25 | if (controllerData == null) { |
| 43 | return false | 26 | updateControllerData() |
| 27 | controllerData = androidControllers[event.device.controllerNumber] ?: return false | ||
| 44 | } | 28 | } |
| 45 | 29 | ||
| 46 | return NativeLibrary.onGamePadButtonEvent( | 30 | NativeInput.onGamePadButtonEvent( |
| 47 | getPlayerNumber(event.device.controllerNumber, event.deviceId), | 31 | controllerData.getGUID(), |
| 48 | button, | 32 | controllerData.getPort(), |
| 33 | event.keyCode, | ||
| 49 | action | 34 | action |
| 50 | ) | 35 | ) |
| 36 | return true | ||
| 51 | } | 37 | } |
| 52 | 38 | ||
| 53 | fun dispatchGenericMotionEvent(event: MotionEvent): Boolean { | 39 | fun dispatchGenericMotionEvent(event: MotionEvent): Boolean { |
| 54 | val device = event.device | 40 | val controllerData = |
| 55 | // Check every axis input available on the controller | 41 | androidControllers[event.device.controllerNumber] ?: return false |
| 56 | for (range in device.motionRanges) { | 42 | event.device.motionRanges.forEach { |
| 57 | val axis = range.axis | 43 | NativeInput.onGamePadAxisEvent( |
| 58 | when (device.vendorId) { | 44 | controllerData.getGUID(), |
| 59 | 0x045E -> setGenericAxisInput(event, axis) | 45 | controllerData.getPort(), |
| 60 | 0x054C -> setGenericAxisInput(event, axis) | 46 | it.axis, |
| 61 | 0x057E -> setJoyconAxisInput(event, axis) | 47 | event.getAxisValue(it.axis) |
| 62 | 0x1532 -> setRazerAxisInput(event, axis) | 48 | ) |
| 63 | else -> setGenericAxisInput(event, axis) | ||
| 64 | } | ||
| 65 | } | 49 | } |
| 66 | |||
| 67 | return true | 50 | return true |
| 68 | } | 51 | } |
| 69 | 52 | ||
| 70 | private fun getPlayerNumber(index: Int, deviceId: Int = -1): Int { | 53 | fun getDevices(): Map<Int, YuzuPhysicalDevice> { |
| 71 | var deviceIndex = index | 54 | val gameControllerDeviceIds = mutableMapOf<Int, YuzuPhysicalDevice>() |
| 72 | if (deviceId != -1) { | ||
| 73 | deviceIndex = controllerIds[deviceId] ?: 0 | ||
| 74 | } | ||
| 75 | |||
| 76 | // TODO: Joycons are handled as different controllers. Find a way to merge them. | ||
| 77 | return when (deviceIndex) { | ||
| 78 | 2 -> NativeLibrary.Player2Device | ||
| 79 | 3 -> NativeLibrary.Player3Device | ||
| 80 | 4 -> NativeLibrary.Player4Device | ||
| 81 | 5 -> NativeLibrary.Player5Device | ||
| 82 | 6 -> NativeLibrary.Player6Device | ||
| 83 | 7 -> NativeLibrary.Player7Device | ||
| 84 | 8 -> NativeLibrary.Player8Device | ||
| 85 | else -> if (NativeLibrary.isHandheldOnly()) { | ||
| 86 | NativeLibrary.ConsoleDevice | ||
| 87 | } else { | ||
| 88 | NativeLibrary.Player1Device | ||
| 89 | } | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | private fun setStickState(playerNumber: Int, index: Int, xAxis: Float, yAxis: Float) { | ||
| 94 | // Calculate vector size | ||
| 95 | val r2 = xAxis * xAxis + yAxis * yAxis | ||
| 96 | var r = sqrt(r2.toDouble()).toFloat() | ||
| 97 | |||
| 98 | // Adjust range of joystick | ||
| 99 | val deadzone = 0.15f | ||
| 100 | var x = xAxis | ||
| 101 | var y = yAxis | ||
| 102 | |||
| 103 | if (r > deadzone) { | ||
| 104 | val deadzoneFactor = 1.0f / r * (r - deadzone) / (1.0f - deadzone) | ||
| 105 | x *= deadzoneFactor | ||
| 106 | y *= deadzoneFactor | ||
| 107 | r *= deadzoneFactor | ||
| 108 | } else { | ||
| 109 | x = 0.0f | ||
| 110 | y = 0.0f | ||
| 111 | } | ||
| 112 | |||
| 113 | // Normalize joystick | ||
| 114 | if (r > 1.0f) { | ||
| 115 | x /= r | ||
| 116 | y /= r | ||
| 117 | } | ||
| 118 | |||
| 119 | NativeLibrary.onGamePadJoystickEvent( | ||
| 120 | playerNumber, | ||
| 121 | index, | ||
| 122 | x, | ||
| 123 | -y | ||
| 124 | ) | ||
| 125 | } | ||
| 126 | |||
| 127 | private fun getAxisToButton(axis: Float): Int { | ||
| 128 | return if (axis > 0.5f) { | ||
| 129 | NativeLibrary.ButtonState.PRESSED | ||
| 130 | } else { | ||
| 131 | NativeLibrary.ButtonState.RELEASED | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | private fun setAxisDpadState(playerNumber: Int, xAxis: Float, yAxis: Float) { | ||
| 136 | NativeLibrary.onGamePadButtonEvent( | ||
| 137 | playerNumber, | ||
| 138 | NativeLibrary.ButtonType.DPAD_UP, | ||
| 139 | getAxisToButton(-yAxis) | ||
| 140 | ) | ||
| 141 | NativeLibrary.onGamePadButtonEvent( | ||
| 142 | playerNumber, | ||
| 143 | NativeLibrary.ButtonType.DPAD_DOWN, | ||
| 144 | getAxisToButton(yAxis) | ||
| 145 | ) | ||
| 146 | NativeLibrary.onGamePadButtonEvent( | ||
| 147 | playerNumber, | ||
| 148 | NativeLibrary.ButtonType.DPAD_LEFT, | ||
| 149 | getAxisToButton(-xAxis) | ||
| 150 | ) | ||
| 151 | NativeLibrary.onGamePadButtonEvent( | ||
| 152 | playerNumber, | ||
| 153 | NativeLibrary.ButtonType.DPAD_RIGHT, | ||
| 154 | getAxisToButton(xAxis) | ||
| 155 | ) | ||
| 156 | } | ||
| 157 | |||
| 158 | private fun getInputDS5ButtonKey(key: Int): Int { | ||
| 159 | // The missing ds5 buttons are axis | ||
| 160 | return when (key) { | ||
| 161 | KeyEvent.KEYCODE_BUTTON_A -> NativeLibrary.ButtonType.BUTTON_B | ||
| 162 | KeyEvent.KEYCODE_BUTTON_B -> NativeLibrary.ButtonType.BUTTON_A | ||
| 163 | KeyEvent.KEYCODE_BUTTON_X -> NativeLibrary.ButtonType.BUTTON_Y | ||
| 164 | KeyEvent.KEYCODE_BUTTON_Y -> NativeLibrary.ButtonType.BUTTON_X | ||
| 165 | KeyEvent.KEYCODE_BUTTON_L1 -> NativeLibrary.ButtonType.TRIGGER_L | ||
| 166 | KeyEvent.KEYCODE_BUTTON_R1 -> NativeLibrary.ButtonType.TRIGGER_R | ||
| 167 | KeyEvent.KEYCODE_BUTTON_THUMBL -> NativeLibrary.ButtonType.STICK_L | ||
| 168 | KeyEvent.KEYCODE_BUTTON_THUMBR -> NativeLibrary.ButtonType.STICK_R | ||
| 169 | KeyEvent.KEYCODE_BUTTON_START -> NativeLibrary.ButtonType.BUTTON_PLUS | ||
| 170 | KeyEvent.KEYCODE_BUTTON_SELECT -> NativeLibrary.ButtonType.BUTTON_MINUS | ||
| 171 | else -> -1 | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | private fun getInputJoyconButtonKey(key: Int): Int { | ||
| 176 | // Joycon support is half dead. A lot of buttons can't be mapped | ||
| 177 | return when (key) { | ||
| 178 | KeyEvent.KEYCODE_BUTTON_A -> NativeLibrary.ButtonType.BUTTON_B | ||
| 179 | KeyEvent.KEYCODE_BUTTON_B -> NativeLibrary.ButtonType.BUTTON_A | ||
| 180 | KeyEvent.KEYCODE_BUTTON_X -> NativeLibrary.ButtonType.BUTTON_X | ||
| 181 | KeyEvent.KEYCODE_BUTTON_Y -> NativeLibrary.ButtonType.BUTTON_Y | ||
| 182 | KeyEvent.KEYCODE_DPAD_UP -> NativeLibrary.ButtonType.DPAD_UP | ||
| 183 | KeyEvent.KEYCODE_DPAD_DOWN -> NativeLibrary.ButtonType.DPAD_DOWN | ||
| 184 | KeyEvent.KEYCODE_DPAD_LEFT -> NativeLibrary.ButtonType.DPAD_LEFT | ||
| 185 | KeyEvent.KEYCODE_DPAD_RIGHT -> NativeLibrary.ButtonType.DPAD_RIGHT | ||
| 186 | KeyEvent.KEYCODE_BUTTON_L1 -> NativeLibrary.ButtonType.TRIGGER_L | ||
| 187 | KeyEvent.KEYCODE_BUTTON_R1 -> NativeLibrary.ButtonType.TRIGGER_R | ||
| 188 | KeyEvent.KEYCODE_BUTTON_L2 -> NativeLibrary.ButtonType.TRIGGER_ZL | ||
| 189 | KeyEvent.KEYCODE_BUTTON_R2 -> NativeLibrary.ButtonType.TRIGGER_ZR | ||
| 190 | KeyEvent.KEYCODE_BUTTON_THUMBL -> NativeLibrary.ButtonType.STICK_L | ||
| 191 | KeyEvent.KEYCODE_BUTTON_THUMBR -> NativeLibrary.ButtonType.STICK_R | ||
| 192 | KeyEvent.KEYCODE_BUTTON_START -> NativeLibrary.ButtonType.BUTTON_PLUS | ||
| 193 | KeyEvent.KEYCODE_BUTTON_SELECT -> NativeLibrary.ButtonType.BUTTON_MINUS | ||
| 194 | else -> -1 | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | private fun getInputXboxButtonKey(key: Int): Int { | ||
| 199 | // The missing xbox buttons are axis | ||
| 200 | return when (key) { | ||
| 201 | KeyEvent.KEYCODE_BUTTON_A -> NativeLibrary.ButtonType.BUTTON_A | ||
| 202 | KeyEvent.KEYCODE_BUTTON_B -> NativeLibrary.ButtonType.BUTTON_B | ||
| 203 | KeyEvent.KEYCODE_BUTTON_X -> NativeLibrary.ButtonType.BUTTON_X | ||
| 204 | KeyEvent.KEYCODE_BUTTON_Y -> NativeLibrary.ButtonType.BUTTON_Y | ||
| 205 | KeyEvent.KEYCODE_BUTTON_L1 -> NativeLibrary.ButtonType.TRIGGER_L | ||
| 206 | KeyEvent.KEYCODE_BUTTON_R1 -> NativeLibrary.ButtonType.TRIGGER_R | ||
| 207 | KeyEvent.KEYCODE_BUTTON_THUMBL -> NativeLibrary.ButtonType.STICK_L | ||
| 208 | KeyEvent.KEYCODE_BUTTON_THUMBR -> NativeLibrary.ButtonType.STICK_R | ||
| 209 | KeyEvent.KEYCODE_BUTTON_START -> NativeLibrary.ButtonType.BUTTON_PLUS | ||
| 210 | KeyEvent.KEYCODE_BUTTON_SELECT -> NativeLibrary.ButtonType.BUTTON_MINUS | ||
| 211 | else -> -1 | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | private fun getInputRazerButtonKey(key: Int): Int { | ||
| 216 | // The missing xbox buttons are axis | ||
| 217 | return when (key) { | ||
| 218 | KeyEvent.KEYCODE_BUTTON_A -> NativeLibrary.ButtonType.BUTTON_B | ||
| 219 | KeyEvent.KEYCODE_BUTTON_B -> NativeLibrary.ButtonType.BUTTON_A | ||
| 220 | KeyEvent.KEYCODE_BUTTON_X -> NativeLibrary.ButtonType.BUTTON_Y | ||
| 221 | KeyEvent.KEYCODE_BUTTON_Y -> NativeLibrary.ButtonType.BUTTON_X | ||
| 222 | KeyEvent.KEYCODE_BUTTON_L1 -> NativeLibrary.ButtonType.TRIGGER_L | ||
| 223 | KeyEvent.KEYCODE_BUTTON_R1 -> NativeLibrary.ButtonType.TRIGGER_R | ||
| 224 | KeyEvent.KEYCODE_BUTTON_THUMBL -> NativeLibrary.ButtonType.STICK_L | ||
| 225 | KeyEvent.KEYCODE_BUTTON_THUMBR -> NativeLibrary.ButtonType.STICK_R | ||
| 226 | KeyEvent.KEYCODE_BUTTON_START -> NativeLibrary.ButtonType.BUTTON_PLUS | ||
| 227 | KeyEvent.KEYCODE_BUTTON_SELECT -> NativeLibrary.ButtonType.BUTTON_MINUS | ||
| 228 | else -> -1 | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | private fun getInputRedmagicButtonKey(key: Int): Int { | ||
| 233 | return when (key) { | ||
| 234 | KeyEvent.KEYCODE_BUTTON_A -> NativeLibrary.ButtonType.BUTTON_B | ||
| 235 | KeyEvent.KEYCODE_BUTTON_B -> NativeLibrary.ButtonType.BUTTON_A | ||
| 236 | KeyEvent.KEYCODE_BUTTON_X -> NativeLibrary.ButtonType.BUTTON_Y | ||
| 237 | KeyEvent.KEYCODE_BUTTON_Y -> NativeLibrary.ButtonType.BUTTON_X | ||
| 238 | KeyEvent.KEYCODE_BUTTON_L1 -> NativeLibrary.ButtonType.TRIGGER_L | ||
| 239 | KeyEvent.KEYCODE_BUTTON_R1 -> NativeLibrary.ButtonType.TRIGGER_R | ||
| 240 | KeyEvent.KEYCODE_BUTTON_L2 -> NativeLibrary.ButtonType.TRIGGER_ZL | ||
| 241 | KeyEvent.KEYCODE_BUTTON_R2 -> NativeLibrary.ButtonType.TRIGGER_ZR | ||
| 242 | KeyEvent.KEYCODE_BUTTON_THUMBL -> NativeLibrary.ButtonType.STICK_L | ||
| 243 | KeyEvent.KEYCODE_BUTTON_THUMBR -> NativeLibrary.ButtonType.STICK_R | ||
| 244 | KeyEvent.KEYCODE_BUTTON_START -> NativeLibrary.ButtonType.BUTTON_PLUS | ||
| 245 | KeyEvent.KEYCODE_BUTTON_SELECT -> NativeLibrary.ButtonType.BUTTON_MINUS | ||
| 246 | else -> -1 | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | private fun getInputBackboneLabsButtonKey(key: Int): Int { | ||
| 251 | return when (key) { | ||
| 252 | KeyEvent.KEYCODE_BUTTON_A -> NativeLibrary.ButtonType.BUTTON_B | ||
| 253 | KeyEvent.KEYCODE_BUTTON_B -> NativeLibrary.ButtonType.BUTTON_A | ||
| 254 | KeyEvent.KEYCODE_BUTTON_X -> NativeLibrary.ButtonType.BUTTON_Y | ||
| 255 | KeyEvent.KEYCODE_BUTTON_Y -> NativeLibrary.ButtonType.BUTTON_X | ||
| 256 | KeyEvent.KEYCODE_BUTTON_L1 -> NativeLibrary.ButtonType.TRIGGER_L | ||
| 257 | KeyEvent.KEYCODE_BUTTON_R1 -> NativeLibrary.ButtonType.TRIGGER_R | ||
| 258 | KeyEvent.KEYCODE_BUTTON_L2 -> NativeLibrary.ButtonType.TRIGGER_ZL | ||
| 259 | KeyEvent.KEYCODE_BUTTON_R2 -> NativeLibrary.ButtonType.TRIGGER_ZR | ||
| 260 | KeyEvent.KEYCODE_BUTTON_THUMBL -> NativeLibrary.ButtonType.STICK_L | ||
| 261 | KeyEvent.KEYCODE_BUTTON_THUMBR -> NativeLibrary.ButtonType.STICK_R | ||
| 262 | KeyEvent.KEYCODE_BUTTON_START -> NativeLibrary.ButtonType.BUTTON_PLUS | ||
| 263 | KeyEvent.KEYCODE_BUTTON_SELECT -> NativeLibrary.ButtonType.BUTTON_MINUS | ||
| 264 | else -> -1 | ||
| 265 | } | ||
| 266 | } | ||
| 267 | |||
| 268 | private fun getInputGenericButtonKey(key: Int): Int { | ||
| 269 | return when (key) { | ||
| 270 | KeyEvent.KEYCODE_BUTTON_A -> NativeLibrary.ButtonType.BUTTON_A | ||
| 271 | KeyEvent.KEYCODE_BUTTON_B -> NativeLibrary.ButtonType.BUTTON_B | ||
| 272 | KeyEvent.KEYCODE_BUTTON_X -> NativeLibrary.ButtonType.BUTTON_X | ||
| 273 | KeyEvent.KEYCODE_BUTTON_Y -> NativeLibrary.ButtonType.BUTTON_Y | ||
| 274 | KeyEvent.KEYCODE_DPAD_UP -> NativeLibrary.ButtonType.DPAD_UP | ||
| 275 | KeyEvent.KEYCODE_DPAD_DOWN -> NativeLibrary.ButtonType.DPAD_DOWN | ||
| 276 | KeyEvent.KEYCODE_DPAD_LEFT -> NativeLibrary.ButtonType.DPAD_LEFT | ||
| 277 | KeyEvent.KEYCODE_DPAD_RIGHT -> NativeLibrary.ButtonType.DPAD_RIGHT | ||
| 278 | KeyEvent.KEYCODE_BUTTON_L1 -> NativeLibrary.ButtonType.TRIGGER_L | ||
| 279 | KeyEvent.KEYCODE_BUTTON_R1 -> NativeLibrary.ButtonType.TRIGGER_R | ||
| 280 | KeyEvent.KEYCODE_BUTTON_L2 -> NativeLibrary.ButtonType.TRIGGER_ZL | ||
| 281 | KeyEvent.KEYCODE_BUTTON_R2 -> NativeLibrary.ButtonType.TRIGGER_ZR | ||
| 282 | KeyEvent.KEYCODE_BUTTON_THUMBL -> NativeLibrary.ButtonType.STICK_L | ||
| 283 | KeyEvent.KEYCODE_BUTTON_THUMBR -> NativeLibrary.ButtonType.STICK_R | ||
| 284 | KeyEvent.KEYCODE_BUTTON_START -> NativeLibrary.ButtonType.BUTTON_PLUS | ||
| 285 | KeyEvent.KEYCODE_BUTTON_SELECT -> NativeLibrary.ButtonType.BUTTON_MINUS | ||
| 286 | else -> -1 | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | private fun setGenericAxisInput(event: MotionEvent, axis: Int) { | ||
| 291 | val playerNumber = getPlayerNumber(event.device.controllerNumber, event.deviceId) | ||
| 292 | |||
| 293 | when (axis) { | ||
| 294 | MotionEvent.AXIS_X, MotionEvent.AXIS_Y -> | ||
| 295 | setStickState( | ||
| 296 | playerNumber, | ||
| 297 | NativeLibrary.StickType.STICK_L, | ||
| 298 | event.getAxisValue(MotionEvent.AXIS_X), | ||
| 299 | event.getAxisValue(MotionEvent.AXIS_Y) | ||
| 300 | ) | ||
| 301 | MotionEvent.AXIS_RX, MotionEvent.AXIS_RY -> | ||
| 302 | setStickState( | ||
| 303 | playerNumber, | ||
| 304 | NativeLibrary.StickType.STICK_R, | ||
| 305 | event.getAxisValue(MotionEvent.AXIS_RX), | ||
| 306 | event.getAxisValue(MotionEvent.AXIS_RY) | ||
| 307 | ) | ||
| 308 | MotionEvent.AXIS_Z, MotionEvent.AXIS_RZ -> | ||
| 309 | setStickState( | ||
| 310 | playerNumber, | ||
| 311 | NativeLibrary.StickType.STICK_R, | ||
| 312 | event.getAxisValue(MotionEvent.AXIS_Z), | ||
| 313 | event.getAxisValue(MotionEvent.AXIS_RZ) | ||
| 314 | ) | ||
| 315 | MotionEvent.AXIS_LTRIGGER -> | ||
| 316 | NativeLibrary.onGamePadButtonEvent( | ||
| 317 | playerNumber, | ||
| 318 | NativeLibrary.ButtonType.TRIGGER_ZL, | ||
| 319 | getAxisToButton(event.getAxisValue(MotionEvent.AXIS_LTRIGGER)) | ||
| 320 | ) | ||
| 321 | MotionEvent.AXIS_BRAKE -> | ||
| 322 | NativeLibrary.onGamePadButtonEvent( | ||
| 323 | playerNumber, | ||
| 324 | NativeLibrary.ButtonType.TRIGGER_ZL, | ||
| 325 | getAxisToButton(event.getAxisValue(MotionEvent.AXIS_BRAKE)) | ||
| 326 | ) | ||
| 327 | MotionEvent.AXIS_RTRIGGER -> | ||
| 328 | NativeLibrary.onGamePadButtonEvent( | ||
| 329 | playerNumber, | ||
| 330 | NativeLibrary.ButtonType.TRIGGER_ZR, | ||
| 331 | getAxisToButton(event.getAxisValue(MotionEvent.AXIS_RTRIGGER)) | ||
| 332 | ) | ||
| 333 | MotionEvent.AXIS_GAS -> | ||
| 334 | NativeLibrary.onGamePadButtonEvent( | ||
| 335 | playerNumber, | ||
| 336 | NativeLibrary.ButtonType.TRIGGER_ZR, | ||
| 337 | getAxisToButton(event.getAxisValue(MotionEvent.AXIS_GAS)) | ||
| 338 | ) | ||
| 339 | MotionEvent.AXIS_HAT_X, MotionEvent.AXIS_HAT_Y -> | ||
| 340 | setAxisDpadState( | ||
| 341 | playerNumber, | ||
| 342 | event.getAxisValue(MotionEvent.AXIS_HAT_X), | ||
| 343 | event.getAxisValue(MotionEvent.AXIS_HAT_Y) | ||
| 344 | ) | ||
| 345 | } | ||
| 346 | } | ||
| 347 | |||
| 348 | private fun setJoyconAxisInput(event: MotionEvent, axis: Int) { | ||
| 349 | // Joycon support is half dead. Right joystick doesn't work | ||
| 350 | val playerNumber = getPlayerNumber(event.device.controllerNumber, event.deviceId) | ||
| 351 | |||
| 352 | when (axis) { | ||
| 353 | MotionEvent.AXIS_X, MotionEvent.AXIS_Y -> | ||
| 354 | setStickState( | ||
| 355 | playerNumber, | ||
| 356 | NativeLibrary.StickType.STICK_L, | ||
| 357 | event.getAxisValue(MotionEvent.AXIS_X), | ||
| 358 | event.getAxisValue(MotionEvent.AXIS_Y) | ||
| 359 | ) | ||
| 360 | MotionEvent.AXIS_Z, MotionEvent.AXIS_RZ -> | ||
| 361 | setStickState( | ||
| 362 | playerNumber, | ||
| 363 | NativeLibrary.StickType.STICK_R, | ||
| 364 | event.getAxisValue(MotionEvent.AXIS_Z), | ||
| 365 | event.getAxisValue(MotionEvent.AXIS_RZ) | ||
| 366 | ) | ||
| 367 | MotionEvent.AXIS_RX, MotionEvent.AXIS_RY -> | ||
| 368 | setStickState( | ||
| 369 | playerNumber, | ||
| 370 | NativeLibrary.StickType.STICK_R, | ||
| 371 | event.getAxisValue(MotionEvent.AXIS_RX), | ||
| 372 | event.getAxisValue(MotionEvent.AXIS_RY) | ||
| 373 | ) | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
| 377 | private fun setRazerAxisInput(event: MotionEvent, axis: Int) { | ||
| 378 | val playerNumber = getPlayerNumber(event.device.controllerNumber, event.deviceId) | ||
| 379 | |||
| 380 | when (axis) { | ||
| 381 | MotionEvent.AXIS_X, MotionEvent.AXIS_Y -> | ||
| 382 | setStickState( | ||
| 383 | playerNumber, | ||
| 384 | NativeLibrary.StickType.STICK_L, | ||
| 385 | event.getAxisValue(MotionEvent.AXIS_X), | ||
| 386 | event.getAxisValue(MotionEvent.AXIS_Y) | ||
| 387 | ) | ||
| 388 | MotionEvent.AXIS_Z, MotionEvent.AXIS_RZ -> | ||
| 389 | setStickState( | ||
| 390 | playerNumber, | ||
| 391 | NativeLibrary.StickType.STICK_R, | ||
| 392 | event.getAxisValue(MotionEvent.AXIS_Z), | ||
| 393 | event.getAxisValue(MotionEvent.AXIS_RZ) | ||
| 394 | ) | ||
| 395 | MotionEvent.AXIS_BRAKE -> | ||
| 396 | NativeLibrary.onGamePadButtonEvent( | ||
| 397 | playerNumber, | ||
| 398 | NativeLibrary.ButtonType.TRIGGER_ZL, | ||
| 399 | getAxisToButton(event.getAxisValue(MotionEvent.AXIS_BRAKE)) | ||
| 400 | ) | ||
| 401 | MotionEvent.AXIS_GAS -> | ||
| 402 | NativeLibrary.onGamePadButtonEvent( | ||
| 403 | playerNumber, | ||
| 404 | NativeLibrary.ButtonType.TRIGGER_ZR, | ||
| 405 | getAxisToButton(event.getAxisValue(MotionEvent.AXIS_GAS)) | ||
| 406 | ) | ||
| 407 | MotionEvent.AXIS_HAT_X, MotionEvent.AXIS_HAT_Y -> | ||
| 408 | setAxisDpadState( | ||
| 409 | playerNumber, | ||
| 410 | event.getAxisValue(MotionEvent.AXIS_HAT_X), | ||
| 411 | event.getAxisValue(MotionEvent.AXIS_HAT_Y) | ||
| 412 | ) | ||
| 413 | } | ||
| 414 | } | ||
| 415 | |||
| 416 | fun getGameControllerIds(): Map<Int, Int> { | ||
| 417 | val gameControllerDeviceIds = mutableMapOf<Int, Int>() | ||
| 418 | val deviceIds = InputDevice.getDeviceIds() | 55 | val deviceIds = InputDevice.getDeviceIds() |
| 419 | var controllerSlot = 1 | 56 | var port = 0 |
| 57 | val inputSettings = NativeConfig.getInputSettings(true) | ||
| 420 | deviceIds.forEach { deviceId -> | 58 | deviceIds.forEach { deviceId -> |
| 421 | InputDevice.getDevice(deviceId)?.apply { | 59 | InputDevice.getDevice(deviceId)?.apply { |
| 422 | // Don't over-assign controllers | ||
| 423 | if (controllerSlot >= 8) { | ||
| 424 | return gameControllerDeviceIds | ||
| 425 | } | ||
| 426 | |||
| 427 | // Verify that the device has gamepad buttons, control sticks, or both. | 60 | // Verify that the device has gamepad buttons, control sticks, or both. |
| 428 | if (sources and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD || | 61 | if (sources and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD || |
| 429 | sources and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK | 62 | sources and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK |
| 430 | ) { | 63 | ) { |
| 431 | // This device is a game controller. Store its device ID. | 64 | if (!gameControllerDeviceIds.contains(controllerNumber)) { |
| 432 | if (deviceId and id and vendorId and productId != 0) { | 65 | gameControllerDeviceIds[controllerNumber] = YuzuPhysicalDevice( |
| 433 | // Additionally filter out devices that have no ID | 66 | this, |
| 434 | gameControllerDeviceIds | 67 | port, |
| 435 | .takeIf { !it.contains(deviceId) } | 68 | inputSettings[port].useSystemVibrator |
| 436 | ?.put(deviceId, controllerSlot) | 69 | ) |
| 437 | controllerSlot++ | ||
| 438 | } | 70 | } |
| 71 | port++ | ||
| 439 | } | 72 | } |
| 440 | } | 73 | } |
| 441 | } | 74 | } |
| 442 | return gameControllerDeviceIds | 75 | return gameControllerDeviceIds |
| 443 | } | 76 | } |
| 77 | |||
| 78 | fun updateControllerData() { | ||
| 79 | androidControllers = getDevices() | ||
| 80 | androidControllers.forEach { | ||
| 81 | NativeInput.registerController(it.value) | ||
| 82 | } | ||
| 83 | |||
| 84 | // Register the input overlay on a dedicated port for all player 1 vibrations | ||
| 85 | NativeInput.registerController(YuzuInputOverlayDevice(androidControllers.isEmpty(), 100)) | ||
| 86 | registeredControllers.clear() | ||
| 87 | NativeInput.getInputDevices().forEach { | ||
| 88 | registeredControllers.add(ParamPackage(it)) | ||
| 89 | } | ||
| 90 | registeredControllers.sortBy { it.get("port", 0) } | ||
| 91 | } | ||
| 92 | |||
| 93 | fun InputDevice.getGUID(): String = String.format("%016x%016x", productId, vendorId) | ||
| 444 | } | 94 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/LifecycleUtils.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/LifecycleUtils.kt new file mode 100644 index 000000000..d5c19c681 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/LifecycleUtils.kt | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.utils | ||
| 5 | |||
| 6 | import androidx.lifecycle.Lifecycle | ||
| 7 | import androidx.lifecycle.LifecycleOwner | ||
| 8 | import androidx.lifecycle.lifecycleScope | ||
| 9 | import androidx.lifecycle.repeatOnLifecycle | ||
| 10 | import kotlinx.coroutines.flow.Flow | ||
| 11 | import kotlinx.coroutines.flow.MutableStateFlow | ||
| 12 | import kotlinx.coroutines.launch | ||
| 13 | |||
| 14 | /** | ||
| 15 | * Collects this [Flow] with a given [LifecycleOwner]. | ||
| 16 | * @param scope [LifecycleOwner] that this [Flow] will be collected with. | ||
| 17 | * @param repeatState When to repeat collection on this [Flow]. | ||
| 18 | * @param resetState Optional lambda to reset state of an underlying [MutableStateFlow] after | ||
| 19 | * [stateCollector] has been run. | ||
| 20 | * @param stateCollector Lambda that receives new state. | ||
| 21 | */ | ||
| 22 | inline fun <reified T> Flow<T>.collect( | ||
| 23 | scope: LifecycleOwner, | ||
| 24 | repeatState: Lifecycle.State = Lifecycle.State.CREATED, | ||
| 25 | crossinline resetState: () -> Unit = {}, | ||
| 26 | crossinline stateCollector: (state: T) -> Unit | ||
| 27 | ) { | ||
| 28 | scope.apply { | ||
| 29 | lifecycleScope.launch { | ||
| 30 | repeatOnLifecycle(repeatState) { | ||
| 31 | this@collect.collect { | ||
| 32 | stateCollector(it) | ||
| 33 | resetState() | ||
| 34 | } | ||
| 35 | } | ||
| 36 | } | ||
| 37 | } | ||
| 38 | } | ||
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 a4c14b3a7..7228f25d2 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 | |||
| @@ -6,6 +6,8 @@ package org.yuzu.yuzu_emu.utils | |||
| 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 | import org.yuzu.yuzu_emu.overlay.model.OverlayControlData |
| 8 | 8 | ||
| 9 | import org.yuzu.yuzu_emu.features.input.model.PlayerInput | ||
| 10 | |||
| 9 | object NativeConfig { | 11 | object NativeConfig { |
| 10 | /** | 12 | /** |
| 11 | * Loads global config. | 13 | * Loads global config. |
| @@ -168,4 +170,17 @@ object NativeConfig { | |||
| 168 | */ | 170 | */ |
| 169 | @Synchronized | 171 | @Synchronized |
| 170 | external fun setOverlayControlData(overlayControlData: Array<OverlayControlData>) | 172 | external fun setOverlayControlData(overlayControlData: Array<OverlayControlData>) |
| 173 | |||
| 174 | @Synchronized | ||
| 175 | external fun getInputSettings(global: Boolean): Array<PlayerInput> | ||
| 176 | |||
| 177 | @Synchronized | ||
| 178 | external fun setInputSettings(value: Array<PlayerInput>, global: Boolean) | ||
| 179 | |||
| 180 | /** | ||
| 181 | * Saves control values for a specific player | ||
| 182 | * Must be used when per game config is loaded | ||
| 183 | */ | ||
| 184 | @Synchronized | ||
| 185 | external fun saveControlPlayerValues() | ||
| 171 | } | 186 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NfcReader.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NfcReader.kt index 68ed66565..331b7ddca 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NfcReader.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NfcReader.kt | |||
| @@ -14,7 +14,7 @@ import android.os.Build | |||
| 14 | import android.os.Handler | 14 | import android.os.Handler |
| 15 | import android.os.Looper | 15 | import android.os.Looper |
| 16 | import java.io.IOException | 16 | import java.io.IOException |
| 17 | import org.yuzu.yuzu_emu.NativeLibrary | 17 | import org.yuzu.yuzu_emu.features.input.NativeInput |
| 18 | 18 | ||
| 19 | class NfcReader(private val activity: Activity) { | 19 | class NfcReader(private val activity: Activity) { |
| 20 | private var nfcAdapter: NfcAdapter? = null | 20 | private var nfcAdapter: NfcAdapter? = null |
| @@ -76,12 +76,12 @@ class NfcReader(private val activity: Activity) { | |||
| 76 | amiibo.connect() | 76 | amiibo.connect() |
| 77 | 77 | ||
| 78 | val tagData = ntag215ReadAll(amiibo) ?: return | 78 | val tagData = ntag215ReadAll(amiibo) ?: return |
| 79 | NativeLibrary.onReadNfcTag(tagData) | 79 | NativeInput.onReadNfcTag(tagData) |
| 80 | 80 | ||
| 81 | nfcAdapter?.ignore( | 81 | nfcAdapter?.ignore( |
| 82 | tag, | 82 | tag, |
| 83 | 1000, | 83 | 1000, |
| 84 | { NativeLibrary.onRemoveNfcTag() }, | 84 | { NativeInput.onRemoveNfcTag() }, |
| 85 | Handler(Looper.getMainLooper()) | 85 | Handler(Looper.getMainLooper()) |
| 86 | ) | 86 | ) |
| 87 | } | 87 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ParamPackage.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ParamPackage.kt new file mode 100644 index 000000000..83fc7da3c --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ParamPackage.kt | |||
| @@ -0,0 +1,141 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.utils | ||
| 5 | |||
| 6 | // Kotlin version of src/common/param_package.h | ||
| 7 | class ParamPackage(serialized: String = "") { | ||
| 8 | private val KEY_VALUE_SEPARATOR = ":" | ||
| 9 | private val PARAM_SEPARATOR = "," | ||
| 10 | |||
| 11 | private val ESCAPE_CHARACTER = "$" | ||
| 12 | private val KEY_VALUE_SEPARATOR_ESCAPE = "$0" | ||
| 13 | private val PARAM_SEPARATOR_ESCAPE = "$1" | ||
| 14 | private val ESCAPE_CHARACTER_ESCAPE = "$2" | ||
| 15 | |||
| 16 | private val EMPTY_PLACEHOLDER = "[empty]" | ||
| 17 | |||
| 18 | val data = mutableMapOf<String, String>() | ||
| 19 | |||
| 20 | init { | ||
| 21 | val pairs = serialized.split(PARAM_SEPARATOR) | ||
| 22 | for (pair in pairs) { | ||
| 23 | val keyValue = pair.split(KEY_VALUE_SEPARATOR).toMutableList() | ||
| 24 | if (keyValue.size != 2) { | ||
| 25 | Log.error("[ParamPackage] Invalid key pair $keyValue") | ||
| 26 | continue | ||
| 27 | } | ||
| 28 | |||
| 29 | keyValue.forEachIndexed { i: Int, _: String -> | ||
| 30 | keyValue[i] = keyValue[i].replace(KEY_VALUE_SEPARATOR_ESCAPE, KEY_VALUE_SEPARATOR) | ||
| 31 | keyValue[i] = keyValue[i].replace(PARAM_SEPARATOR_ESCAPE, PARAM_SEPARATOR) | ||
| 32 | keyValue[i] = keyValue[i].replace(ESCAPE_CHARACTER_ESCAPE, ESCAPE_CHARACTER) | ||
| 33 | } | ||
| 34 | |||
| 35 | set(keyValue[0], keyValue[1]) | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | constructor(params: List<Pair<String, String>>) : this() { | ||
| 40 | params.forEach { | ||
| 41 | data[it.first] = it.second | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | fun serialize(): String { | ||
| 46 | if (data.isEmpty()) { | ||
| 47 | return EMPTY_PLACEHOLDER | ||
| 48 | } | ||
| 49 | |||
| 50 | val result = StringBuilder() | ||
| 51 | data.forEach { | ||
| 52 | val keyValue = mutableListOf(it.key, it.value) | ||
| 53 | keyValue.forEachIndexed { i, _ -> | ||
| 54 | keyValue[i] = keyValue[i].replace(ESCAPE_CHARACTER, ESCAPE_CHARACTER_ESCAPE) | ||
| 55 | keyValue[i] = keyValue[i].replace(PARAM_SEPARATOR, PARAM_SEPARATOR_ESCAPE) | ||
| 56 | keyValue[i] = keyValue[i].replace(KEY_VALUE_SEPARATOR, KEY_VALUE_SEPARATOR_ESCAPE) | ||
| 57 | } | ||
| 58 | result.append("${keyValue[0]}$KEY_VALUE_SEPARATOR${keyValue[1]}$PARAM_SEPARATOR") | ||
| 59 | } | ||
| 60 | return result.removeSuffix(PARAM_SEPARATOR).toString() | ||
| 61 | } | ||
| 62 | |||
| 63 | fun get(key: String, defaultValue: String): String = | ||
| 64 | if (has(key)) { | ||
| 65 | data[key]!! | ||
| 66 | } else { | ||
| 67 | Log.debug("[ParamPackage] key $key not found") | ||
| 68 | defaultValue | ||
| 69 | } | ||
| 70 | |||
| 71 | fun get(key: String, defaultValue: Int): Int = | ||
| 72 | if (has(key)) { | ||
| 73 | try { | ||
| 74 | data[key]!!.toInt() | ||
| 75 | } catch (e: NumberFormatException) { | ||
| 76 | Log.debug("[ParamPackage] failed to convert ${data[key]!!} to int") | ||
| 77 | defaultValue | ||
| 78 | } | ||
| 79 | } else { | ||
| 80 | Log.debug("[ParamPackage] key $key not found") | ||
| 81 | defaultValue | ||
| 82 | } | ||
| 83 | |||
| 84 | private fun Int.toBoolean(): Boolean = | ||
| 85 | if (this == 1) { | ||
| 86 | true | ||
| 87 | } else if (this == 0) { | ||
| 88 | false | ||
| 89 | } else { | ||
| 90 | throw Exception("Tried to convert a value to a boolean that was not 0 or 1!") | ||
| 91 | } | ||
| 92 | |||
| 93 | fun get(key: String, defaultValue: Boolean): Boolean = | ||
| 94 | if (has(key)) { | ||
| 95 | try { | ||
| 96 | get(key, if (defaultValue) 1 else 0).toBoolean() | ||
| 97 | } catch (e: Exception) { | ||
| 98 | Log.debug("[ParamPackage] failed to convert ${data[key]!!} to boolean") | ||
| 99 | defaultValue | ||
| 100 | } | ||
| 101 | } else { | ||
| 102 | Log.debug("[ParamPackage] key $key not found") | ||
| 103 | defaultValue | ||
| 104 | } | ||
| 105 | |||
| 106 | fun get(key: String, defaultValue: Float): Float = | ||
| 107 | if (has(key)) { | ||
| 108 | try { | ||
| 109 | data[key]!!.toFloat() | ||
| 110 | } catch (e: NumberFormatException) { | ||
| 111 | Log.debug("[ParamPackage] failed to convert ${data[key]!!} to float") | ||
| 112 | defaultValue | ||
| 113 | } | ||
| 114 | } else { | ||
| 115 | Log.debug("[ParamPackage] key $key not found") | ||
| 116 | defaultValue | ||
| 117 | } | ||
| 118 | |||
| 119 | fun set(key: String, value: String) { | ||
| 120 | data[key] = value | ||
| 121 | } | ||
| 122 | |||
| 123 | fun set(key: String, value: Int) { | ||
| 124 | data[key] = value.toString() | ||
| 125 | } | ||
| 126 | |||
| 127 | fun Boolean.toInt(): Int = if (this) 1 else 0 | ||
| 128 | fun set(key: String, value: Boolean) { | ||
| 129 | data[key] = value.toInt().toString() | ||
| 130 | } | ||
| 131 | |||
| 132 | fun set(key: String, value: Float) { | ||
| 133 | data[key] = value.toString() | ||
| 134 | } | ||
| 135 | |||
| 136 | fun has(key: String): Boolean = data.containsKey(key) | ||
| 137 | |||
| 138 | fun erase(key: String) = data.remove(key) | ||
| 139 | |||
| 140 | fun clear() = data.clear() | ||
| 141 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ViewUtils.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ViewUtils.kt index ffbfa9337..244091aec 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ViewUtils.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ViewUtils.kt | |||
| @@ -3,8 +3,10 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.utils | 4 | package org.yuzu.yuzu_emu.utils |
| 5 | 5 | ||
| 6 | import android.text.TextUtils | ||
| 6 | import android.view.View | 7 | import android.view.View |
| 7 | import android.view.ViewGroup | 8 | import android.view.ViewGroup |
| 9 | import android.widget.TextView | ||
| 8 | 10 | ||
| 9 | object ViewUtils { | 11 | object ViewUtils { |
| 10 | fun showView(view: View, length: Long = 300) { | 12 | fun showView(view: View, length: Long = 300) { |
| @@ -57,4 +59,35 @@ object ViewUtils { | |||
| 57 | } | 59 | } |
| 58 | this.layoutParams = layoutParams | 60 | this.layoutParams = layoutParams |
| 59 | } | 61 | } |
| 62 | |||
| 63 | /** | ||
| 64 | * Shows or hides a view. | ||
| 65 | * @param visible Whether a view will be made View.VISIBLE or View.INVISIBLE/GONE. | ||
| 66 | * @param gone Optional parameter for hiding a view. Uses View.GONE if true and View.INVISIBLE otherwise. | ||
| 67 | */ | ||
| 68 | fun View.setVisible(visible: Boolean, gone: Boolean = true) { | ||
| 69 | visibility = if (visible) { | ||
| 70 | View.VISIBLE | ||
| 71 | } else { | ||
| 72 | if (gone) { | ||
| 73 | View.GONE | ||
| 74 | } else { | ||
| 75 | View.INVISIBLE | ||
| 76 | } | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | /** | ||
| 81 | * Starts a marquee on some text. | ||
| 82 | * @param delay Optional parameter for changing the start delay. 3 seconds of delay by default. | ||
| 83 | */ | ||
| 84 | fun TextView.marquee(delay: Long = 3000) { | ||
| 85 | ellipsize = null | ||
| 86 | marqueeRepeatLimit = -1 | ||
| 87 | isSingleLine = true | ||
| 88 | postDelayed({ | ||
| 89 | ellipsize = TextUtils.TruncateAt.MARQUEE | ||
| 90 | isSelected = true | ||
| 91 | }, delay) | ||
| 92 | } | ||
| 60 | } | 93 | } |
diff --git a/src/android/app/src/main/jni/CMakeLists.txt b/src/android/app/src/main/jni/CMakeLists.txt index 20b319c12..ec8ae5c57 100644 --- a/src/android/app/src/main/jni/CMakeLists.txt +++ b/src/android/app/src/main/jni/CMakeLists.txt | |||
| @@ -12,6 +12,7 @@ add_library(yuzu-android SHARED | |||
| 12 | native_log.cpp | 12 | native_log.cpp |
| 13 | android_config.cpp | 13 | android_config.cpp |
| 14 | android_config.h | 14 | android_config.h |
| 15 | native_input.cpp | ||
| 15 | ) | 16 | ) |
| 16 | 17 | ||
| 17 | set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR}) | 18 | set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR}) |
diff --git a/src/android/app/src/main/jni/android_config.cpp b/src/android/app/src/main/jni/android_config.cpp index e147560c3..a79a64afb 100644 --- a/src/android/app/src/main/jni/android_config.cpp +++ b/src/android/app/src/main/jni/android_config.cpp | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <common/logging/log.h> | ||
| 5 | #include <input_common/main.h> | ||
| 4 | #include "android_config.h" | 6 | #include "android_config.h" |
| 5 | #include "android_settings.h" | 7 | #include "android_settings.h" |
| 6 | #include "common/settings_setting.h" | 8 | #include "common/settings_setting.h" |
| @@ -32,6 +34,7 @@ void AndroidConfig::ReadAndroidValues() { | |||
| 32 | ReadOverlayValues(); | 34 | ReadOverlayValues(); |
| 33 | } | 35 | } |
| 34 | ReadDriverValues(); | 36 | ReadDriverValues(); |
| 37 | ReadAndroidControlValues(); | ||
| 35 | } | 38 | } |
| 36 | 39 | ||
| 37 | void AndroidConfig::ReadAndroidUIValues() { | 40 | void AndroidConfig::ReadAndroidUIValues() { |
| @@ -107,6 +110,76 @@ void AndroidConfig::ReadOverlayValues() { | |||
| 107 | EndGroup(); | 110 | EndGroup(); |
| 108 | } | 111 | } |
| 109 | 112 | ||
| 113 | void AndroidConfig::ReadAndroidPlayerValues(std::size_t player_index) { | ||
| 114 | std::string player_prefix; | ||
| 115 | if (type != ConfigType::InputProfile) { | ||
| 116 | player_prefix.append("player_").append(ToString(player_index)).append("_"); | ||
| 117 | } | ||
| 118 | |||
| 119 | auto& player = Settings::values.players.GetValue()[player_index]; | ||
| 120 | if (IsCustomConfig()) { | ||
| 121 | const auto profile_name = | ||
| 122 | ReadStringSetting(std::string(player_prefix).append("profile_name")); | ||
| 123 | if (profile_name.empty()) { | ||
| 124 | // Use the global input config | ||
| 125 | player = Settings::values.players.GetValue(true)[player_index]; | ||
| 126 | player.profile_name = ""; | ||
| 127 | return; | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | // Android doesn't have default options for controllers. We have the input overlay for that. | ||
| 132 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 133 | const std::string default_param; | ||
| 134 | auto& player_buttons = player.buttons[i]; | ||
| 135 | |||
| 136 | player_buttons = ReadStringSetting( | ||
| 137 | std::string(player_prefix).append(Settings::NativeButton::mapping[i]), default_param); | ||
| 138 | if (player_buttons.empty()) { | ||
| 139 | player_buttons = default_param; | ||
| 140 | } | ||
| 141 | } | ||
| 142 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 143 | const std::string default_param; | ||
| 144 | auto& player_analogs = player.analogs[i]; | ||
| 145 | |||
| 146 | player_analogs = ReadStringSetting( | ||
| 147 | std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), default_param); | ||
| 148 | if (player_analogs.empty()) { | ||
| 149 | player_analogs = default_param; | ||
| 150 | } | ||
| 151 | } | ||
| 152 | for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { | ||
| 153 | const std::string default_param; | ||
| 154 | auto& player_motions = player.motions[i]; | ||
| 155 | |||
| 156 | player_motions = ReadStringSetting( | ||
| 157 | std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), default_param); | ||
| 158 | if (player_motions.empty()) { | ||
| 159 | player_motions = default_param; | ||
| 160 | } | ||
| 161 | } | ||
| 162 | player.use_system_vibrator = ReadBooleanSetting( | ||
| 163 | std::string(player_prefix).append("use_system_vibrator"), player_index == 0); | ||
| 164 | } | ||
| 165 | |||
| 166 | void AndroidConfig::ReadAndroidControlValues() { | ||
| 167 | BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); | ||
| 168 | |||
| 169 | Settings::values.players.SetGlobal(!IsCustomConfig()); | ||
| 170 | for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { | ||
| 171 | ReadAndroidPlayerValues(p); | ||
| 172 | } | ||
| 173 | if (IsCustomConfig()) { | ||
| 174 | EndGroup(); | ||
| 175 | return; | ||
| 176 | } | ||
| 177 | // ReadDebugControlValues(); | ||
| 178 | // ReadHidbusValues(); | ||
| 179 | |||
| 180 | EndGroup(); | ||
| 181 | } | ||
| 182 | |||
| 110 | void AndroidConfig::SaveAndroidValues() { | 183 | void AndroidConfig::SaveAndroidValues() { |
| 111 | if (global) { | 184 | if (global) { |
| 112 | SaveAndroidUIValues(); | 185 | SaveAndroidUIValues(); |
| @@ -114,6 +187,7 @@ void AndroidConfig::SaveAndroidValues() { | |||
| 114 | SaveOverlayValues(); | 187 | SaveOverlayValues(); |
| 115 | } | 188 | } |
| 116 | SaveDriverValues(); | 189 | SaveDriverValues(); |
| 190 | SaveAndroidControlValues(); | ||
| 117 | 191 | ||
| 118 | WriteToIni(); | 192 | WriteToIni(); |
| 119 | } | 193 | } |
| @@ -187,6 +261,52 @@ void AndroidConfig::SaveOverlayValues() { | |||
| 187 | EndGroup(); | 261 | EndGroup(); |
| 188 | } | 262 | } |
| 189 | 263 | ||
| 264 | void AndroidConfig::SaveAndroidPlayerValues(std::size_t player_index) { | ||
| 265 | std::string player_prefix; | ||
| 266 | if (type != ConfigType::InputProfile) { | ||
| 267 | player_prefix = std::string("player_").append(ToString(player_index)).append("_"); | ||
| 268 | } | ||
| 269 | |||
| 270 | const auto& player = Settings::values.players.GetValue()[player_index]; | ||
| 271 | if (IsCustomConfig() && player.profile_name.empty()) { | ||
| 272 | // No custom profile selected | ||
| 273 | return; | ||
| 274 | } | ||
| 275 | |||
| 276 | const std::string default_param; | ||
| 277 | for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { | ||
| 278 | WriteStringSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]), | ||
| 279 | player.buttons[i], std::make_optional(default_param)); | ||
| 280 | } | ||
| 281 | for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { | ||
| 282 | WriteStringSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), | ||
| 283 | player.analogs[i], std::make_optional(default_param)); | ||
| 284 | } | ||
| 285 | for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { | ||
| 286 | WriteStringSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), | ||
| 287 | player.motions[i], std::make_optional(default_param)); | ||
| 288 | } | ||
| 289 | WriteBooleanSetting(std::string(player_prefix).append("use_system_vibrator"), | ||
| 290 | player.use_system_vibrator, std::make_optional(player_index == 0)); | ||
| 291 | } | ||
| 292 | |||
| 293 | void AndroidConfig::SaveAndroidControlValues() { | ||
| 294 | BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); | ||
| 295 | |||
| 296 | Settings::values.players.SetGlobal(!IsCustomConfig()); | ||
| 297 | for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { | ||
| 298 | SaveAndroidPlayerValues(p); | ||
| 299 | } | ||
| 300 | if (IsCustomConfig()) { | ||
| 301 | EndGroup(); | ||
| 302 | return; | ||
| 303 | } | ||
| 304 | // SaveDebugControlValues(); | ||
| 305 | // SaveHidbusValues(); | ||
| 306 | |||
| 307 | EndGroup(); | ||
| 308 | } | ||
| 309 | |||
| 190 | std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) { | 310 | std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) { |
| 191 | auto& map = Settings::values.linkage.by_category; | 311 | auto& map = Settings::values.linkage.by_category; |
| 192 | if (map.contains(category)) { | 312 | if (map.contains(category)) { |
| @@ -194,3 +314,24 @@ std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings:: | |||
| 194 | } | 314 | } |
| 195 | return AndroidSettings::values.linkage.by_category[category]; | 315 | return AndroidSettings::values.linkage.by_category[category]; |
| 196 | } | 316 | } |
| 317 | |||
| 318 | void AndroidConfig::ReadAndroidControlPlayerValues(std::size_t player_index) { | ||
| 319 | BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); | ||
| 320 | |||
| 321 | ReadPlayerValues(player_index); | ||
| 322 | ReadAndroidPlayerValues(player_index); | ||
| 323 | |||
| 324 | EndGroup(); | ||
| 325 | } | ||
| 326 | |||
| 327 | void AndroidConfig::SaveAndroidControlPlayerValues(std::size_t player_index) { | ||
| 328 | BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); | ||
| 329 | |||
| 330 | LOG_DEBUG(Config, "Saving players control configuration values"); | ||
| 331 | SavePlayerValues(player_index); | ||
| 332 | SaveAndroidPlayerValues(player_index); | ||
| 333 | |||
| 334 | EndGroup(); | ||
| 335 | |||
| 336 | WriteToIni(); | ||
| 337 | } | ||
diff --git a/src/android/app/src/main/jni/android_config.h b/src/android/app/src/main/jni/android_config.h index 693e1e3f0..28ef5d0a8 100644 --- a/src/android/app/src/main/jni/android_config.h +++ b/src/android/app/src/main/jni/android_config.h | |||
| @@ -13,7 +13,12 @@ public: | |||
| 13 | void ReloadAllValues() override; | 13 | void ReloadAllValues() override; |
| 14 | void SaveAllValues() override; | 14 | void SaveAllValues() override; |
| 15 | 15 | ||
| 16 | void ReadAndroidControlPlayerValues(std::size_t player_index); | ||
| 17 | void SaveAndroidControlPlayerValues(std::size_t player_index); | ||
| 18 | |||
| 16 | protected: | 19 | protected: |
| 20 | void ReadAndroidPlayerValues(std::size_t player_index); | ||
| 21 | void ReadAndroidControlValues(); | ||
| 17 | void ReadAndroidValues(); | 22 | void ReadAndroidValues(); |
| 18 | void ReadAndroidUIValues(); | 23 | void ReadAndroidUIValues(); |
| 19 | void ReadDriverValues(); | 24 | void ReadDriverValues(); |
| @@ -27,6 +32,8 @@ protected: | |||
| 27 | void ReadUILayoutValues() override {} | 32 | void ReadUILayoutValues() override {} |
| 28 | void ReadMultiplayerValues() override {} | 33 | void ReadMultiplayerValues() override {} |
| 29 | 34 | ||
| 35 | void SaveAndroidPlayerValues(std::size_t player_index); | ||
| 36 | void SaveAndroidControlValues(); | ||
| 30 | void SaveAndroidValues(); | 37 | void SaveAndroidValues(); |
| 31 | void SaveAndroidUIValues(); | 38 | void SaveAndroidUIValues(); |
| 32 | void SaveDriverValues(); | 39 | void SaveDriverValues(); |
diff --git a/src/android/app/src/main/jni/emu_window/emu_window.cpp b/src/android/app/src/main/jni/emu_window/emu_window.cpp index c927cddda..06db55369 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.cpp +++ b/src/android/app/src/main/jni/emu_window/emu_window.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include "common/android/id_cache.h" | 6 | #include "common/android/id_cache.h" |
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "input_common/drivers/android.h" | ||
| 8 | #include "input_common/drivers/touch_screen.h" | 9 | #include "input_common/drivers/touch_screen.h" |
| 9 | #include "input_common/drivers/virtual_amiibo.h" | 10 | #include "input_common/drivers/virtual_amiibo.h" |
| 10 | #include "input_common/drivers/virtual_gamepad.h" | 11 | #include "input_common/drivers/virtual_gamepad.h" |
| @@ -24,39 +25,18 @@ void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { | |||
| 24 | 25 | ||
| 25 | void EmuWindow_Android::OnTouchPressed(int id, float x, float y) { | 26 | void EmuWindow_Android::OnTouchPressed(int id, float x, float y) { |
| 26 | const auto [touch_x, touch_y] = MapToTouchScreen(x, y); | 27 | const auto [touch_x, touch_y] = MapToTouchScreen(x, y); |
| 27 | m_input_subsystem->GetTouchScreen()->TouchPressed(touch_x, touch_y, id); | 28 | EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchPressed(touch_x, |
| 29 | touch_y, id); | ||
| 28 | } | 30 | } |
| 29 | 31 | ||
| 30 | void EmuWindow_Android::OnTouchMoved(int id, float x, float y) { | 32 | void EmuWindow_Android::OnTouchMoved(int id, float x, float y) { |
| 31 | const auto [touch_x, touch_y] = MapToTouchScreen(x, y); | 33 | const auto [touch_x, touch_y] = MapToTouchScreen(x, y); |
| 32 | m_input_subsystem->GetTouchScreen()->TouchMoved(touch_x, touch_y, id); | 34 | EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchMoved(touch_x, |
| 35 | touch_y, id); | ||
| 33 | } | 36 | } |
| 34 | 37 | ||
| 35 | void EmuWindow_Android::OnTouchReleased(int id) { | 38 | void EmuWindow_Android::OnTouchReleased(int id) { |
| 36 | m_input_subsystem->GetTouchScreen()->TouchReleased(id); | 39 | EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchReleased(id); |
| 37 | } | ||
| 38 | |||
| 39 | void EmuWindow_Android::OnGamepadButtonEvent(int player_index, int button_id, bool pressed) { | ||
| 40 | m_input_subsystem->GetVirtualGamepad()->SetButtonState(player_index, button_id, pressed); | ||
| 41 | } | ||
| 42 | |||
| 43 | void EmuWindow_Android::OnGamepadJoystickEvent(int player_index, int stick_id, float x, float y) { | ||
| 44 | m_input_subsystem->GetVirtualGamepad()->SetStickPosition(player_index, stick_id, x, y); | ||
| 45 | } | ||
| 46 | |||
| 47 | void EmuWindow_Android::OnGamepadMotionEvent(int player_index, u64 delta_timestamp, float gyro_x, | ||
| 48 | float gyro_y, float gyro_z, float accel_x, | ||
| 49 | float accel_y, float accel_z) { | ||
| 50 | m_input_subsystem->GetVirtualGamepad()->SetMotionState( | ||
| 51 | player_index, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z); | ||
| 52 | } | ||
| 53 | |||
| 54 | void EmuWindow_Android::OnReadNfcTag(std::span<u8> data) { | ||
| 55 | m_input_subsystem->GetVirtualAmiibo()->LoadAmiibo(data); | ||
| 56 | } | ||
| 57 | |||
| 58 | void EmuWindow_Android::OnRemoveNfcTag() { | ||
| 59 | m_input_subsystem->GetVirtualAmiibo()->CloseAmiibo(); | ||
| 60 | } | 40 | } |
| 61 | 41 | ||
| 62 | void EmuWindow_Android::OnFrameDisplayed() { | 42 | void EmuWindow_Android::OnFrameDisplayed() { |
| @@ -67,10 +47,9 @@ void EmuWindow_Android::OnFrameDisplayed() { | |||
| 67 | } | 47 | } |
| 68 | } | 48 | } |
| 69 | 49 | ||
| 70 | EmuWindow_Android::EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem, | 50 | EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface, |
| 71 | ANativeWindow* surface, | ||
| 72 | std::shared_ptr<Common::DynamicLibrary> driver_library) | 51 | std::shared_ptr<Common::DynamicLibrary> driver_library) |
| 73 | : m_input_subsystem{input_subsystem}, m_driver_library{driver_library} { | 52 | : m_driver_library{driver_library} { |
| 74 | LOG_INFO(Frontend, "initializing"); | 53 | LOG_INFO(Frontend, "initializing"); |
| 75 | 54 | ||
| 76 | if (!surface) { | 55 | if (!surface) { |
| @@ -80,10 +59,4 @@ EmuWindow_Android::EmuWindow_Android(InputCommon::InputSubsystem* input_subsyste | |||
| 80 | 59 | ||
| 81 | OnSurfaceChanged(surface); | 60 | OnSurfaceChanged(surface); |
| 82 | window_info.type = Core::Frontend::WindowSystemType::Android; | 61 | window_info.type = Core::Frontend::WindowSystemType::Android; |
| 83 | |||
| 84 | m_input_subsystem->Initialize(); | ||
| 85 | } | ||
| 86 | |||
| 87 | EmuWindow_Android::~EmuWindow_Android() { | ||
| 88 | m_input_subsystem->Shutdown(); | ||
| 89 | } | 62 | } |
diff --git a/src/android/app/src/main/jni/emu_window/emu_window.h b/src/android/app/src/main/jni/emu_window/emu_window.h index a34a0e479..d7b5fc6da 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.h +++ b/src/android/app/src/main/jni/emu_window/emu_window.h | |||
| @@ -30,22 +30,17 @@ private: | |||
| 30 | class EmuWindow_Android final : public Core::Frontend::EmuWindow { | 30 | class EmuWindow_Android final : public Core::Frontend::EmuWindow { |
| 31 | 31 | ||
| 32 | public: | 32 | public: |
| 33 | EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem, ANativeWindow* surface, | 33 | EmuWindow_Android(ANativeWindow* surface, |
| 34 | std::shared_ptr<Common::DynamicLibrary> driver_library); | 34 | std::shared_ptr<Common::DynamicLibrary> driver_library); |
| 35 | 35 | ||
| 36 | ~EmuWindow_Android(); | 36 | ~EmuWindow_Android() = default; |
| 37 | 37 | ||
| 38 | void OnSurfaceChanged(ANativeWindow* surface); | 38 | void OnSurfaceChanged(ANativeWindow* surface); |
| 39 | void OnFrameDisplayed() override; | ||
| 40 | |||
| 39 | void OnTouchPressed(int id, float x, float y); | 41 | void OnTouchPressed(int id, float x, float y); |
| 40 | void OnTouchMoved(int id, float x, float y); | 42 | void OnTouchMoved(int id, float x, float y); |
| 41 | void OnTouchReleased(int id); | 43 | void OnTouchReleased(int id); |
| 42 | void OnGamepadButtonEvent(int player_index, int button_id, bool pressed); | ||
| 43 | void OnGamepadJoystickEvent(int player_index, int stick_id, float x, float y); | ||
| 44 | void OnGamepadMotionEvent(int player_index, u64 delta_timestamp, float gyro_x, float gyro_y, | ||
| 45 | float gyro_z, float accel_x, float accel_y, float accel_z); | ||
| 46 | void OnReadNfcTag(std::span<u8> data); | ||
| 47 | void OnRemoveNfcTag(); | ||
| 48 | void OnFrameDisplayed() override; | ||
| 49 | 44 | ||
| 50 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override { | 45 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override { |
| 51 | return {std::make_unique<GraphicsContext_Android>(m_driver_library)}; | 46 | return {std::make_unique<GraphicsContext_Android>(m_driver_library)}; |
| @@ -55,8 +50,6 @@ public: | |||
| 55 | }; | 50 | }; |
| 56 | 51 | ||
| 57 | private: | 52 | private: |
| 58 | InputCommon::InputSubsystem* m_input_subsystem{}; | ||
| 59 | |||
| 60 | float m_window_width{}; | 53 | float m_window_width{}; |
| 61 | float m_window_height{}; | 54 | float m_window_height{}; |
| 62 | 55 | ||
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index a4d8454e8..4ea82e217 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp | |||
| @@ -88,6 +88,10 @@ FileSys::ManualContentProvider* EmulationSession::GetContentProvider() { | |||
| 88 | return m_manual_provider.get(); | 88 | return m_manual_provider.get(); |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | InputCommon::InputSubsystem& EmulationSession::GetInputSubsystem() { | ||
| 92 | return m_input_subsystem; | ||
| 93 | } | ||
| 94 | |||
| 91 | const EmuWindow_Android& EmulationSession::Window() const { | 95 | const EmuWindow_Android& EmulationSession::Window() const { |
| 92 | return *m_window; | 96 | return *m_window; |
| 93 | } | 97 | } |
| @@ -198,6 +202,8 @@ void EmulationSession::InitializeSystem(bool reload) { | |||
| 198 | Common::Log::Initialize(); | 202 | Common::Log::Initialize(); |
| 199 | Common::Log::SetColorConsoleBackendEnabled(true); | 203 | Common::Log::SetColorConsoleBackendEnabled(true); |
| 200 | Common::Log::Start(); | 204 | Common::Log::Start(); |
| 205 | |||
| 206 | m_input_subsystem.Initialize(); | ||
| 201 | } | 207 | } |
| 202 | 208 | ||
| 203 | // Initialize filesystem. | 209 | // Initialize filesystem. |
| @@ -222,8 +228,7 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string | |||
| 222 | std::scoped_lock lock(m_mutex); | 228 | std::scoped_lock lock(m_mutex); |
| 223 | 229 | ||
| 224 | // Create the render window. | 230 | // Create the render window. |
| 225 | m_window = | 231 | m_window = std::make_unique<EmuWindow_Android>(m_native_window, m_vulkan_library); |
| 226 | std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window, m_vulkan_library); | ||
| 227 | 232 | ||
| 228 | // Initialize system. | 233 | // Initialize system. |
| 229 | jauto android_keyboard = std::make_unique<Common::Android::SoftwareKeyboard::AndroidKeyboard>(); | 234 | jauto android_keyboard = std::make_unique<Common::Android::SoftwareKeyboard::AndroidKeyboard>(); |
| @@ -355,60 +360,6 @@ void EmulationSession::RunEmulation() { | |||
| 355 | m_applet_id = static_cast<int>(Service::AM::AppletId::Application); | 360 | m_applet_id = static_cast<int>(Service::AM::AppletId::Application); |
| 356 | } | 361 | } |
| 357 | 362 | ||
| 358 | bool EmulationSession::IsHandheldOnly() { | ||
| 359 | jconst npad_style_set = m_system.HIDCore().GetSupportedStyleTag(); | ||
| 360 | |||
| 361 | if (npad_style_set.fullkey == 1) { | ||
| 362 | return false; | ||
| 363 | } | ||
| 364 | |||
| 365 | if (npad_style_set.handheld == 0) { | ||
| 366 | return false; | ||
| 367 | } | ||
| 368 | |||
| 369 | return !Settings::IsDockedMode(); | ||
| 370 | } | ||
| 371 | |||
| 372 | void EmulationSession::SetDeviceType([[maybe_unused]] int index, int type) { | ||
| 373 | jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); | ||
| 374 | controller->SetNpadStyleIndex(static_cast<Core::HID::NpadStyleIndex>(type)); | ||
| 375 | } | ||
| 376 | |||
| 377 | void EmulationSession::OnGamepadConnectEvent([[maybe_unused]] int index) { | ||
| 378 | jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); | ||
| 379 | |||
| 380 | // Ensure that player1 is configured correctly and handheld disconnected | ||
| 381 | if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) { | ||
| 382 | jauto handheld = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); | ||
| 383 | |||
| 384 | if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) { | ||
| 385 | handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey); | ||
| 386 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey); | ||
| 387 | handheld->Disconnect(); | ||
| 388 | } | ||
| 389 | } | ||
| 390 | |||
| 391 | // Ensure that handheld is configured correctly and player 1 disconnected | ||
| 392 | if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) { | ||
| 393 | jauto player1 = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); | ||
| 394 | |||
| 395 | if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) { | ||
| 396 | player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); | ||
| 397 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); | ||
| 398 | player1->Disconnect(); | ||
| 399 | } | ||
| 400 | } | ||
| 401 | |||
| 402 | if (!controller->IsConnected()) { | ||
| 403 | controller->Connect(); | ||
| 404 | } | ||
| 405 | } | ||
| 406 | |||
| 407 | void EmulationSession::OnGamepadDisconnectEvent([[maybe_unused]] int index) { | ||
| 408 | jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); | ||
| 409 | controller->Disconnect(); | ||
| 410 | } | ||
| 411 | |||
| 412 | Common::Android::SoftwareKeyboard::AndroidKeyboard* EmulationSession::SoftwareKeyboard() { | 363 | Common::Android::SoftwareKeyboard::AndroidKeyboard* EmulationSession::SoftwareKeyboard() { |
| 413 | return m_software_keyboard; | 364 | return m_software_keyboard; |
| 414 | } | 365 | } |
| @@ -453,7 +404,9 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath, | |||
| 453 | const size_t program_index, | 404 | const size_t program_index, |
| 454 | const bool frontend_initiated) { | 405 | const bool frontend_initiated) { |
| 455 | MicroProfileOnThreadCreate("EmuThread"); | 406 | MicroProfileOnThreadCreate("EmuThread"); |
| 456 | SCOPE_EXIT({ MicroProfileShutdown(); }); | 407 | SCOPE_EXIT { |
| 408 | MicroProfileShutdown(); | ||
| 409 | }; | ||
| 457 | 410 | ||
| 458 | LOG_INFO(Frontend, "starting"); | 411 | LOG_INFO(Frontend, "starting"); |
| 459 | 412 | ||
| @@ -462,7 +415,9 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath, | |||
| 462 | return Core::SystemResultStatus::ErrorLoader; | 415 | return Core::SystemResultStatus::ErrorLoader; |
| 463 | } | 416 | } |
| 464 | 417 | ||
| 465 | SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); }); | 418 | SCOPE_EXIT { |
| 419 | EmulationSession::GetInstance().ShutdownEmulation(); | ||
| 420 | }; | ||
| 466 | 421 | ||
| 467 | jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index, | 422 | jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index, |
| 468 | frontend_initiated); | 423 | frontend_initiated); |
| @@ -574,14 +529,14 @@ jobjectArray Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_getSystemDriverInfo( | |||
| 574 | nullptr, nullptr, file_redirect_dir_, nullptr); | 529 | nullptr, nullptr, file_redirect_dir_, nullptr); |
| 575 | auto driver_library = std::make_shared<Common::DynamicLibrary>(handle); | 530 | auto driver_library = std::make_shared<Common::DynamicLibrary>(handle); |
| 576 | InputCommon::InputSubsystem input_subsystem; | 531 | InputCommon::InputSubsystem input_subsystem; |
| 577 | auto m_window = std::make_unique<EmuWindow_Android>( | 532 | auto window = |
| 578 | &input_subsystem, ANativeWindow_fromSurface(env, j_surf), driver_library); | 533 | std::make_unique<EmuWindow_Android>(ANativeWindow_fromSurface(env, j_surf), driver_library); |
| 579 | 534 | ||
| 580 | Vulkan::vk::InstanceDispatch dld; | 535 | Vulkan::vk::InstanceDispatch dld; |
| 581 | Vulkan::vk::Instance vk_instance = Vulkan::CreateInstance( | 536 | Vulkan::vk::Instance vk_instance = Vulkan::CreateInstance( |
| 582 | *driver_library, dld, VK_API_VERSION_1_1, Core::Frontend::WindowSystemType::Android); | 537 | *driver_library, dld, VK_API_VERSION_1_1, Core::Frontend::WindowSystemType::Android); |
| 583 | 538 | ||
| 584 | auto surface = Vulkan::CreateSurface(vk_instance, m_window->GetWindowInfo()); | 539 | auto surface = Vulkan::CreateSurface(vk_instance, window->GetWindowInfo()); |
| 585 | 540 | ||
| 586 | auto device = Vulkan::CreateDevice(vk_instance, dld, *surface); | 541 | auto device = Vulkan::CreateDevice(vk_instance, dld, *surface); |
| 587 | 542 | ||
| @@ -622,103 +577,6 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isPaused(JNIEnv* env, jclass claz | |||
| 622 | return static_cast<jboolean>(EmulationSession::GetInstance().IsPaused()); | 577 | return static_cast<jboolean>(EmulationSession::GetInstance().IsPaused()); |
| 623 | } | 578 | } |
| 624 | 579 | ||
| 625 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHandheldOnly(JNIEnv* env, jclass clazz) { | ||
| 626 | return EmulationSession::GetInstance().IsHandheldOnly(); | ||
| 627 | } | ||
| 628 | |||
| 629 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_setDeviceType(JNIEnv* env, jclass clazz, | ||
| 630 | jint j_device, jint j_type) { | ||
| 631 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 632 | EmulationSession::GetInstance().SetDeviceType(j_device, j_type); | ||
| 633 | } | ||
| 634 | return static_cast<jboolean>(true); | ||
| 635 | } | ||
| 636 | |||
| 637 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadConnectEvent(JNIEnv* env, jclass clazz, | ||
| 638 | jint j_device) { | ||
| 639 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 640 | EmulationSession::GetInstance().OnGamepadConnectEvent(j_device); | ||
| 641 | } | ||
| 642 | return static_cast<jboolean>(true); | ||
| 643 | } | ||
| 644 | |||
| 645 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent(JNIEnv* env, jclass clazz, | ||
| 646 | jint j_device) { | ||
| 647 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 648 | EmulationSession::GetInstance().OnGamepadDisconnectEvent(j_device); | ||
| 649 | } | ||
| 650 | return static_cast<jboolean>(true); | ||
| 651 | } | ||
| 652 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent(JNIEnv* env, jclass clazz, | ||
| 653 | jint j_device, jint j_button, | ||
| 654 | jint action) { | ||
| 655 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 656 | // Ensure gamepad is connected | ||
| 657 | EmulationSession::GetInstance().OnGamepadConnectEvent(j_device); | ||
| 658 | EmulationSession::GetInstance().Window().OnGamepadButtonEvent(j_device, j_button, | ||
| 659 | action != 0); | ||
| 660 | } | ||
| 661 | return static_cast<jboolean>(true); | ||
| 662 | } | ||
| 663 | |||
| 664 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadJoystickEvent(JNIEnv* env, jclass clazz, | ||
| 665 | jint j_device, jint stick_id, | ||
| 666 | jfloat x, jfloat y) { | ||
| 667 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 668 | EmulationSession::GetInstance().Window().OnGamepadJoystickEvent(j_device, stick_id, x, y); | ||
| 669 | } | ||
| 670 | return static_cast<jboolean>(true); | ||
| 671 | } | ||
| 672 | |||
| 673 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent( | ||
| 674 | JNIEnv* env, jclass clazz, jint j_device, jlong delta_timestamp, jfloat gyro_x, jfloat gyro_y, | ||
| 675 | jfloat gyro_z, jfloat accel_x, jfloat accel_y, jfloat accel_z) { | ||
| 676 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 677 | EmulationSession::GetInstance().Window().OnGamepadMotionEvent( | ||
| 678 | j_device, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z); | ||
| 679 | } | ||
| 680 | return static_cast<jboolean>(true); | ||
| 681 | } | ||
| 682 | |||
| 683 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag(JNIEnv* env, jclass clazz, | ||
| 684 | jbyteArray j_data) { | ||
| 685 | jboolean isCopy{false}; | ||
| 686 | std::span<u8> data(reinterpret_cast<u8*>(env->GetByteArrayElements(j_data, &isCopy)), | ||
| 687 | static_cast<size_t>(env->GetArrayLength(j_data))); | ||
| 688 | |||
| 689 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 690 | EmulationSession::GetInstance().Window().OnReadNfcTag(data); | ||
| 691 | } | ||
| 692 | return static_cast<jboolean>(true); | ||
| 693 | } | ||
| 694 | |||
| 695 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onRemoveNfcTag(JNIEnv* env, jclass clazz) { | ||
| 696 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 697 | EmulationSession::GetInstance().Window().OnRemoveNfcTag(); | ||
| 698 | } | ||
| 699 | return static_cast<jboolean>(true); | ||
| 700 | } | ||
| 701 | |||
| 702 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchPressed(JNIEnv* env, jclass clazz, jint id, | ||
| 703 | jfloat x, jfloat y) { | ||
| 704 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 705 | EmulationSession::GetInstance().Window().OnTouchPressed(id, x, y); | ||
| 706 | } | ||
| 707 | } | ||
| 708 | |||
| 709 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved(JNIEnv* env, jclass clazz, jint id, | ||
| 710 | jfloat x, jfloat y) { | ||
| 711 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 712 | EmulationSession::GetInstance().Window().OnTouchMoved(id, x, y); | ||
| 713 | } | ||
| 714 | } | ||
| 715 | |||
| 716 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased(JNIEnv* env, jclass clazz, jint id) { | ||
| 717 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 718 | EmulationSession::GetInstance().Window().OnTouchReleased(id); | ||
| 719 | } | ||
| 720 | } | ||
| 721 | |||
| 722 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz, | 580 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz, |
| 723 | jboolean reload) { | 581 | jboolean reload) { |
| 724 | // Initialize the emulated system. | 582 | // Initialize the emulated system. |
| @@ -759,6 +617,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGpuDriver(JNIEnv* env, jobject | |||
| 759 | 617 | ||
| 760 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_applySettings(JNIEnv* env, jobject jobj) { | 618 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_applySettings(JNIEnv* env, jobject jobj) { |
| 761 | EmulationSession::GetInstance().System().ApplySettings(); | 619 | EmulationSession::GetInstance().System().ApplySettings(); |
| 620 | EmulationSession::GetInstance().System().HIDCore().ReloadInputDevices(); | ||
| 762 | } | 621 | } |
| 763 | 622 | ||
| 764 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_logSettings(JNIEnv* env, jobject jobj) { | 623 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_logSettings(JNIEnv* env, jobject jobj) { |
diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h index 47936e305..6a4551ada 100644 --- a/src/android/app/src/main/jni/native.h +++ b/src/android/app/src/main/jni/native.h | |||
| @@ -23,6 +23,7 @@ public: | |||
| 23 | const Core::System& System() const; | 23 | const Core::System& System() const; |
| 24 | Core::System& System(); | 24 | Core::System& System(); |
| 25 | FileSys::ManualContentProvider* GetContentProvider(); | 25 | FileSys::ManualContentProvider* GetContentProvider(); |
| 26 | InputCommon::InputSubsystem& GetInputSubsystem(); | ||
| 26 | 27 | ||
| 27 | const EmuWindow_Android& Window() const; | 28 | const EmuWindow_Android& Window() const; |
| 28 | EmuWindow_Android& Window(); | 29 | EmuWindow_Android& Window(); |
| @@ -50,10 +51,6 @@ public: | |||
| 50 | const std::size_t program_index, | 51 | const std::size_t program_index, |
| 51 | const bool frontend_initiated); | 52 | const bool frontend_initiated); |
| 52 | 53 | ||
| 53 | bool IsHandheldOnly(); | ||
| 54 | void SetDeviceType([[maybe_unused]] int index, int type); | ||
| 55 | void OnGamepadConnectEvent([[maybe_unused]] int index); | ||
| 56 | void OnGamepadDisconnectEvent([[maybe_unused]] int index); | ||
| 57 | Common::Android::SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard(); | 54 | Common::Android::SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard(); |
| 58 | 55 | ||
| 59 | static void OnEmulationStarted(); | 56 | static void OnEmulationStarted(); |
diff --git a/src/android/app/src/main/jni/native_config.cpp b/src/android/app/src/main/jni/native_config.cpp index 8ae10fbc7..0b26280c6 100644 --- a/src/android/app/src/main/jni/native_config.cpp +++ b/src/android/app/src/main/jni/native_config.cpp | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | #include <string> | 4 | #include <string> |
| 5 | 5 | ||
| 6 | #include <common/fs/fs_util.h> | ||
| 7 | #include <jni.h> | 6 | #include <jni.h> |
| 8 | 7 | ||
| 9 | #include "android_config.h" | 8 | #include "android_config.h" |
| @@ -425,4 +424,120 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setOverlayControlData( | |||
| 425 | } | 424 | } |
| 426 | } | 425 | } |
| 427 | 426 | ||
| 427 | jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getInputSettings(JNIEnv* env, jobject obj, | ||
| 428 | jboolean j_global) { | ||
| 429 | Settings::values.players.SetGlobal(static_cast<bool>(j_global)); | ||
| 430 | auto& players = Settings::values.players.GetValue(); | ||
| 431 | jobjectArray j_input_settings = | ||
| 432 | env->NewObjectArray(players.size(), Common::Android::GetPlayerInputClass(), nullptr); | ||
| 433 | for (size_t i = 0; i < players.size(); ++i) { | ||
| 434 | auto j_connected = static_cast<jboolean>(players[i].connected); | ||
| 435 | |||
| 436 | jobjectArray j_buttons = env->NewObjectArray( | ||
| 437 | players[i].buttons.size(), Common::Android::GetStringClass(), env->NewStringUTF("")); | ||
| 438 | for (size_t j = 0; j < players[i].buttons.size(); ++j) { | ||
| 439 | env->SetObjectArrayElement(j_buttons, j, | ||
| 440 | Common::Android::ToJString(env, players[i].buttons[j])); | ||
| 441 | } | ||
| 442 | jobjectArray j_analogs = env->NewObjectArray( | ||
| 443 | players[i].analogs.size(), Common::Android::GetStringClass(), env->NewStringUTF("")); | ||
| 444 | for (size_t j = 0; j < players[i].analogs.size(); ++j) { | ||
| 445 | env->SetObjectArrayElement(j_analogs, j, | ||
| 446 | Common::Android::ToJString(env, players[i].analogs[j])); | ||
| 447 | } | ||
| 448 | jobjectArray j_motions = env->NewObjectArray( | ||
| 449 | players[i].motions.size(), Common::Android::GetStringClass(), env->NewStringUTF("")); | ||
| 450 | for (size_t j = 0; j < players[i].motions.size(); ++j) { | ||
| 451 | env->SetObjectArrayElement(j_motions, j, | ||
| 452 | Common::Android::ToJString(env, players[i].motions[j])); | ||
| 453 | } | ||
| 454 | |||
| 455 | auto j_vibration_enabled = static_cast<jboolean>(players[i].vibration_enabled); | ||
| 456 | auto j_vibration_strength = static_cast<jint>(players[i].vibration_strength); | ||
| 457 | |||
| 458 | auto j_body_color_left = static_cast<jlong>(players[i].body_color_left); | ||
| 459 | auto j_body_color_right = static_cast<jlong>(players[i].body_color_right); | ||
| 460 | auto j_button_color_left = static_cast<jlong>(players[i].button_color_left); | ||
| 461 | auto j_button_color_right = static_cast<jlong>(players[i].button_color_right); | ||
| 462 | |||
| 463 | auto j_profile_name = Common::Android::ToJString(env, players[i].profile_name); | ||
| 464 | |||
| 465 | auto j_use_system_vibrator = players[i].use_system_vibrator; | ||
| 466 | |||
| 467 | jobject playerInput = env->NewObject( | ||
| 468 | Common::Android::GetPlayerInputClass(), Common::Android::GetPlayerInputConstructor(), | ||
| 469 | j_connected, j_buttons, j_analogs, j_motions, j_vibration_enabled, j_vibration_strength, | ||
| 470 | j_body_color_left, j_body_color_right, j_button_color_left, j_button_color_right, | ||
| 471 | j_profile_name, j_use_system_vibrator); | ||
| 472 | env->SetObjectArrayElement(j_input_settings, i, playerInput); | ||
| 473 | } | ||
| 474 | return j_input_settings; | ||
| 475 | } | ||
| 476 | |||
| 477 | void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setInputSettings(JNIEnv* env, jobject obj, | ||
| 478 | jobjectArray j_value, | ||
| 479 | jboolean j_global) { | ||
| 480 | auto& players = Settings::values.players.GetValue(static_cast<bool>(j_global)); | ||
| 481 | int playersSize = env->GetArrayLength(j_value); | ||
| 482 | for (int i = 0; i < playersSize; ++i) { | ||
| 483 | jobject jplayer = env->GetObjectArrayElement(j_value, i); | ||
| 484 | |||
| 485 | players[i].connected = static_cast<bool>( | ||
| 486 | env->GetBooleanField(jplayer, Common::Android::GetPlayerInputConnectedField())); | ||
| 487 | |||
| 488 | auto j_buttons_array = static_cast<jobjectArray>( | ||
| 489 | env->GetObjectField(jplayer, Common::Android::GetPlayerInputButtonsField())); | ||
| 490 | int buttons_size = env->GetArrayLength(j_buttons_array); | ||
| 491 | for (int j = 0; j < buttons_size; ++j) { | ||
| 492 | auto button = static_cast<jstring>(env->GetObjectArrayElement(j_buttons_array, j)); | ||
| 493 | players[i].buttons[j] = Common::Android::GetJString(env, button); | ||
| 494 | } | ||
| 495 | auto j_analogs_array = static_cast<jobjectArray>( | ||
| 496 | env->GetObjectField(jplayer, Common::Android::GetPlayerInputAnalogsField())); | ||
| 497 | int analogs_size = env->GetArrayLength(j_analogs_array); | ||
| 498 | for (int j = 0; j < analogs_size; ++j) { | ||
| 499 | auto analog = static_cast<jstring>(env->GetObjectArrayElement(j_analogs_array, j)); | ||
| 500 | players[i].analogs[j] = Common::Android::GetJString(env, analog); | ||
| 501 | } | ||
| 502 | auto j_motions_array = static_cast<jobjectArray>( | ||
| 503 | env->GetObjectField(jplayer, Common::Android::GetPlayerInputMotionsField())); | ||
| 504 | int motions_size = env->GetArrayLength(j_motions_array); | ||
| 505 | for (int j = 0; j < motions_size; ++j) { | ||
| 506 | auto motion = static_cast<jstring>(env->GetObjectArrayElement(j_motions_array, j)); | ||
| 507 | players[i].motions[j] = Common::Android::GetJString(env, motion); | ||
| 508 | } | ||
| 509 | |||
| 510 | players[i].vibration_enabled = static_cast<bool>( | ||
| 511 | env->GetBooleanField(jplayer, Common::Android::GetPlayerInputVibrationEnabledField())); | ||
| 512 | players[i].vibration_strength = static_cast<int>( | ||
| 513 | env->GetIntField(jplayer, Common::Android::GetPlayerInputVibrationStrengthField())); | ||
| 514 | |||
| 515 | players[i].body_color_left = static_cast<u32>( | ||
| 516 | env->GetLongField(jplayer, Common::Android::GetPlayerInputBodyColorLeftField())); | ||
| 517 | players[i].body_color_right = static_cast<u32>( | ||
| 518 | env->GetLongField(jplayer, Common::Android::GetPlayerInputBodyColorRightField())); | ||
| 519 | players[i].button_color_left = static_cast<u32>( | ||
| 520 | env->GetLongField(jplayer, Common::Android::GetPlayerInputButtonColorLeftField())); | ||
| 521 | players[i].button_color_right = static_cast<u32>( | ||
| 522 | env->GetLongField(jplayer, Common::Android::GetPlayerInputButtonColorRightField())); | ||
| 523 | |||
| 524 | auto profileName = static_cast<jstring>( | ||
| 525 | env->GetObjectField(jplayer, Common::Android::GetPlayerInputProfileNameField())); | ||
| 526 | players[i].profile_name = Common::Android::GetJString(env, profileName); | ||
| 527 | |||
| 528 | players[i].use_system_vibrator = | ||
| 529 | env->GetBooleanField(jplayer, Common::Android::GetPlayerInputUseSystemVibratorField()); | ||
| 530 | } | ||
| 531 | } | ||
| 532 | |||
| 533 | void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_saveControlPlayerValues(JNIEnv* env, jobject obj) { | ||
| 534 | Settings::values.players.SetGlobal(false); | ||
| 535 | |||
| 536 | // Clear all controls from the config in case the user reverted back to globals | ||
| 537 | per_game_config->ClearControlPlayerValues(); | ||
| 538 | for (size_t index = 0; index < Settings::values.players.GetValue().size(); ++index) { | ||
| 539 | per_game_config->SaveAndroidControlPlayerValues(index); | ||
| 540 | } | ||
| 541 | } | ||
| 542 | |||
| 428 | } // extern "C" | 543 | } // extern "C" |
diff --git a/src/android/app/src/main/jni/native_input.cpp b/src/android/app/src/main/jni/native_input.cpp new file mode 100644 index 000000000..37a65f2b8 --- /dev/null +++ b/src/android/app/src/main/jni/native_input.cpp | |||
| @@ -0,0 +1,629 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <common/fs/fs.h> | ||
| 5 | #include <common/fs/path_util.h> | ||
| 6 | #include <common/settings.h> | ||
| 7 | #include <hid_core/hid_types.h> | ||
| 8 | #include <jni.h> | ||
| 9 | |||
| 10 | #include "android_config.h" | ||
| 11 | #include "common/android/android_common.h" | ||
| 12 | #include "common/android/id_cache.h" | ||
| 13 | #include "hid_core/frontend/emulated_controller.h" | ||
| 14 | #include "hid_core/hid_core.h" | ||
| 15 | #include "input_common/drivers/android.h" | ||
| 16 | #include "input_common/drivers/touch_screen.h" | ||
| 17 | #include "input_common/drivers/virtual_amiibo.h" | ||
| 18 | #include "input_common/drivers/virtual_gamepad.h" | ||
| 19 | #include "native.h" | ||
| 20 | |||
| 21 | std::unordered_map<std::string, std::unique_ptr<AndroidConfig>> map_profiles; | ||
| 22 | |||
| 23 | bool IsHandheldOnly() { | ||
| 24 | const auto npad_style_set = | ||
| 25 | EmulationSession::GetInstance().System().HIDCore().GetSupportedStyleTag(); | ||
| 26 | |||
| 27 | if (npad_style_set.fullkey == 1) { | ||
| 28 | return false; | ||
| 29 | } | ||
| 30 | |||
| 31 | if (npad_style_set.handheld == 0) { | ||
| 32 | return false; | ||
| 33 | } | ||
| 34 | |||
| 35 | return !Settings::IsDockedMode(); | ||
| 36 | } | ||
| 37 | |||
| 38 | std::filesystem::path GetNameWithoutExtension(std::filesystem::path filename) { | ||
| 39 | return filename.replace_extension(); | ||
| 40 | } | ||
| 41 | |||
| 42 | bool IsProfileNameValid(std::string_view profile_name) { | ||
| 43 | return profile_name.find_first_of("<>:;\"/\\|,.!?*") == std::string::npos; | ||
| 44 | } | ||
| 45 | |||
| 46 | bool ProfileExistsInFilesystem(std::string_view profile_name) { | ||
| 47 | return Common::FS::Exists(Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "input" / | ||
| 48 | fmt::format("{}.ini", profile_name)); | ||
| 49 | } | ||
| 50 | |||
| 51 | bool ProfileExistsInMap(const std::string& profile_name) { | ||
| 52 | return map_profiles.find(profile_name) != map_profiles.end(); | ||
| 53 | } | ||
| 54 | |||
| 55 | bool SaveProfile(const std::string& profile_name, std::size_t player_index) { | ||
| 56 | if (!ProfileExistsInMap(profile_name)) { | ||
| 57 | return false; | ||
| 58 | } | ||
| 59 | |||
| 60 | Settings::values.players.GetValue()[player_index].profile_name = profile_name; | ||
| 61 | map_profiles[profile_name]->SaveAndroidControlPlayerValues(player_index); | ||
| 62 | return true; | ||
| 63 | } | ||
| 64 | |||
| 65 | bool LoadProfile(std::string& profile_name, std::size_t player_index) { | ||
| 66 | if (!ProfileExistsInMap(profile_name)) { | ||
| 67 | return false; | ||
| 68 | } | ||
| 69 | |||
| 70 | if (!ProfileExistsInFilesystem(profile_name)) { | ||
| 71 | map_profiles.erase(profile_name); | ||
| 72 | return false; | ||
| 73 | } | ||
| 74 | |||
| 75 | LOG_INFO(Config, "Loading input profile `{}`", profile_name); | ||
| 76 | |||
| 77 | Settings::values.players.GetValue()[player_index].profile_name = profile_name; | ||
| 78 | map_profiles[profile_name]->ReadAndroidControlPlayerValues(player_index); | ||
| 79 | return true; | ||
| 80 | } | ||
| 81 | |||
| 82 | void ApplyControllerConfig(size_t player_index, | ||
| 83 | const std::function<void(Core::HID::EmulatedController*)>& apply) { | ||
| 84 | auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); | ||
| 85 | if (player_index == 0) { | ||
| 86 | auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); | ||
| 87 | auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); | ||
| 88 | handheld->EnableConfiguration(); | ||
| 89 | player_one->EnableConfiguration(); | ||
| 90 | apply(handheld); | ||
| 91 | apply(player_one); | ||
| 92 | handheld->DisableConfiguration(); | ||
| 93 | player_one->DisableConfiguration(); | ||
| 94 | handheld->SaveCurrentConfig(); | ||
| 95 | player_one->SaveCurrentConfig(); | ||
| 96 | } else { | ||
| 97 | auto* controller = hid_core.GetEmulatedControllerByIndex(player_index); | ||
| 98 | controller->EnableConfiguration(); | ||
| 99 | apply(controller); | ||
| 100 | controller->DisableConfiguration(); | ||
| 101 | controller->SaveCurrentConfig(); | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | void ConnectController(size_t player_index, bool connected) { | ||
| 106 | auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); | ||
| 107 | if (player_index == 0) { | ||
| 108 | auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); | ||
| 109 | auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); | ||
| 110 | handheld->EnableConfiguration(); | ||
| 111 | player_one->EnableConfiguration(); | ||
| 112 | if (player_one->GetNpadStyleIndex(true) == Core::HID::NpadStyleIndex::Handheld) { | ||
| 113 | if (connected) { | ||
| 114 | handheld->Connect(); | ||
| 115 | } else { | ||
| 116 | handheld->Disconnect(); | ||
| 117 | } | ||
| 118 | player_one->Disconnect(); | ||
| 119 | } else { | ||
| 120 | if (connected) { | ||
| 121 | player_one->Connect(); | ||
| 122 | } else { | ||
| 123 | player_one->Disconnect(); | ||
| 124 | } | ||
| 125 | handheld->Disconnect(); | ||
| 126 | } | ||
| 127 | handheld->DisableConfiguration(); | ||
| 128 | player_one->DisableConfiguration(); | ||
| 129 | handheld->SaveCurrentConfig(); | ||
| 130 | player_one->SaveCurrentConfig(); | ||
| 131 | } else { | ||
| 132 | auto* controller = hid_core.GetEmulatedControllerByIndex(player_index); | ||
| 133 | controller->EnableConfiguration(); | ||
| 134 | if (connected) { | ||
| 135 | controller->Connect(); | ||
| 136 | } else { | ||
| 137 | controller->Disconnect(); | ||
| 138 | } | ||
| 139 | controller->DisableConfiguration(); | ||
| 140 | controller->SaveCurrentConfig(); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | extern "C" { | ||
| 145 | |||
| 146 | jboolean Java_org_yuzu_yuzu_1emu_features_input_NativeInput_isHandheldOnly(JNIEnv* env, | ||
| 147 | jobject j_obj) { | ||
| 148 | return IsHandheldOnly(); | ||
| 149 | } | ||
| 150 | |||
| 151 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onGamePadButtonEvent( | ||
| 152 | JNIEnv* env, jobject j_obj, jstring j_guid, jint j_port, jint j_button_id, jint j_action) { | ||
| 153 | EmulationSession::GetInstance().GetInputSubsystem().GetAndroid()->SetButtonState( | ||
| 154 | Common::Android::GetJString(env, j_guid), j_port, j_button_id, j_action != 0); | ||
| 155 | } | ||
| 156 | |||
| 157 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onGamePadAxisEvent( | ||
| 158 | JNIEnv* env, jobject j_obj, jstring j_guid, jint j_port, jint j_stick_id, jfloat j_value) { | ||
| 159 | EmulationSession::GetInstance().GetInputSubsystem().GetAndroid()->SetAxisPosition( | ||
| 160 | Common::Android::GetJString(env, j_guid), j_port, j_stick_id, j_value); | ||
| 161 | } | ||
| 162 | |||
| 163 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onGamePadMotionEvent( | ||
| 164 | JNIEnv* env, jobject j_obj, jstring j_guid, jint j_port, jlong j_delta_timestamp, | ||
| 165 | jfloat j_x_gyro, jfloat j_y_gyro, jfloat j_z_gyro, jfloat j_x_accel, jfloat j_y_accel, | ||
| 166 | jfloat j_z_accel) { | ||
| 167 | EmulationSession::GetInstance().GetInputSubsystem().GetAndroid()->SetMotionState( | ||
| 168 | Common::Android::GetJString(env, j_guid), j_port, j_delta_timestamp, j_x_gyro, j_y_gyro, | ||
| 169 | j_z_gyro, j_x_accel, j_y_accel, j_z_accel); | ||
| 170 | } | ||
| 171 | |||
| 172 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onReadNfcTag(JNIEnv* env, jobject j_obj, | ||
| 173 | jbyteArray j_data) { | ||
| 174 | jboolean isCopy{false}; | ||
| 175 | std::span<u8> data(reinterpret_cast<u8*>(env->GetByteArrayElements(j_data, &isCopy)), | ||
| 176 | static_cast<size_t>(env->GetArrayLength(j_data))); | ||
| 177 | |||
| 178 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 179 | EmulationSession::GetInstance().GetInputSubsystem().GetVirtualAmiibo()->LoadAmiibo(data); | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onRemoveNfcTag(JNIEnv* env, jobject j_obj) { | ||
| 184 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 185 | EmulationSession::GetInstance().GetInputSubsystem().GetVirtualAmiibo()->CloseAmiibo(); | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onTouchPressed(JNIEnv* env, jobject j_obj, | ||
| 190 | jint j_id, jfloat j_x_axis, | ||
| 191 | jfloat j_y_axis) { | ||
| 192 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 193 | EmulationSession::GetInstance().Window().OnTouchPressed(j_id, j_x_axis, j_y_axis); | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onTouchMoved(JNIEnv* env, jobject j_obj, | ||
| 198 | jint j_id, jfloat j_x_axis, | ||
| 199 | jfloat j_y_axis) { | ||
| 200 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 201 | EmulationSession::GetInstance().Window().OnTouchMoved(j_id, j_x_axis, j_y_axis); | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onTouchReleased(JNIEnv* env, jobject j_obj, | ||
| 206 | jint j_id) { | ||
| 207 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 208 | EmulationSession::GetInstance().Window().OnTouchReleased(j_id); | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onOverlayButtonEventImpl( | ||
| 213 | JNIEnv* env, jobject j_obj, jint j_port, jint j_button_id, jint j_action) { | ||
| 214 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 215 | EmulationSession::GetInstance().GetInputSubsystem().GetVirtualGamepad()->SetButtonState( | ||
| 216 | j_port, j_button_id, j_action == 1); | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onOverlayJoystickEventImpl( | ||
| 221 | JNIEnv* env, jobject j_obj, jint j_port, jint j_stick_id, jfloat j_x_axis, jfloat j_y_axis) { | ||
| 222 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 223 | EmulationSession::GetInstance().GetInputSubsystem().GetVirtualGamepad()->SetStickPosition( | ||
| 224 | j_port, j_stick_id, j_x_axis, j_y_axis); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 228 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onDeviceMotionEvent( | ||
| 229 | JNIEnv* env, jobject j_obj, jint j_port, jlong j_delta_timestamp, jfloat j_x_gyro, | ||
| 230 | jfloat j_y_gyro, jfloat j_z_gyro, jfloat j_x_accel, jfloat j_y_accel, jfloat j_z_accel) { | ||
| 231 | if (EmulationSession::GetInstance().IsRunning()) { | ||
| 232 | EmulationSession::GetInstance().GetInputSubsystem().GetVirtualGamepad()->SetMotionState( | ||
| 233 | j_port, j_delta_timestamp, j_x_gyro, j_y_gyro, j_z_gyro, j_x_accel, j_y_accel, | ||
| 234 | j_z_accel); | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_reloadInputDevices(JNIEnv* env, | ||
| 239 | jobject j_obj) { | ||
| 240 | EmulationSession::GetInstance().System().HIDCore().ReloadInputDevices(); | ||
| 241 | } | ||
| 242 | |||
| 243 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_registerController(JNIEnv* env, | ||
| 244 | jobject j_obj, | ||
| 245 | jobject j_device) { | ||
| 246 | EmulationSession::GetInstance().GetInputSubsystem().GetAndroid()->RegisterController(j_device); | ||
| 247 | } | ||
| 248 | |||
| 249 | jobjectArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getInputDevices(JNIEnv* env, | ||
| 250 | jobject j_obj) { | ||
| 251 | auto devices = EmulationSession::GetInstance().GetInputSubsystem().GetInputDevices(); | ||
| 252 | jobjectArray jdevices = env->NewObjectArray(devices.size(), Common::Android::GetStringClass(), | ||
| 253 | Common::Android::ToJString(env, "")); | ||
| 254 | for (size_t i = 0; i < devices.size(); ++i) { | ||
| 255 | env->SetObjectArrayElement(jdevices, i, | ||
| 256 | Common::Android::ToJString(env, devices[i].Serialize())); | ||
| 257 | } | ||
| 258 | return jdevices; | ||
| 259 | } | ||
| 260 | |||
| 261 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_loadInputProfiles(JNIEnv* env, | ||
| 262 | jobject j_obj) { | ||
| 263 | map_profiles.clear(); | ||
| 264 | const auto input_profile_loc = | ||
| 265 | Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "input"; | ||
| 266 | |||
| 267 | if (Common::FS::IsDir(input_profile_loc)) { | ||
| 268 | Common::FS::IterateDirEntries( | ||
| 269 | input_profile_loc, | ||
| 270 | [&](const std::filesystem::path& full_path) { | ||
| 271 | const auto filename = full_path.filename(); | ||
| 272 | const auto name_without_ext = | ||
| 273 | Common::FS::PathToUTF8String(GetNameWithoutExtension(filename)); | ||
| 274 | |||
| 275 | if (filename.extension() == ".ini" && IsProfileNameValid(name_without_ext)) { | ||
| 276 | map_profiles.insert_or_assign( | ||
| 277 | name_without_ext, std::make_unique<AndroidConfig>( | ||
| 278 | name_without_ext, Config::ConfigType::InputProfile)); | ||
| 279 | } | ||
| 280 | |||
| 281 | return true; | ||
| 282 | }, | ||
| 283 | Common::FS::DirEntryFilter::File); | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | jobjectArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getInputProfileNames( | ||
| 288 | JNIEnv* env, jobject j_obj) { | ||
| 289 | std::vector<std::string> profile_names; | ||
| 290 | profile_names.reserve(map_profiles.size()); | ||
| 291 | |||
| 292 | auto it = map_profiles.cbegin(); | ||
| 293 | while (it != map_profiles.cend()) { | ||
| 294 | const auto& [profile_name, config] = *it; | ||
| 295 | if (!ProfileExistsInFilesystem(profile_name)) { | ||
| 296 | it = map_profiles.erase(it); | ||
| 297 | continue; | ||
| 298 | } | ||
| 299 | |||
| 300 | profile_names.push_back(profile_name); | ||
| 301 | ++it; | ||
| 302 | } | ||
| 303 | |||
| 304 | std::stable_sort(profile_names.begin(), profile_names.end()); | ||
| 305 | |||
| 306 | jobjectArray j_profile_names = | ||
| 307 | env->NewObjectArray(profile_names.size(), Common::Android::GetStringClass(), | ||
| 308 | Common::Android::ToJString(env, "")); | ||
| 309 | for (size_t i = 0; i < profile_names.size(); ++i) { | ||
| 310 | env->SetObjectArrayElement(j_profile_names, i, | ||
| 311 | Common::Android::ToJString(env, profile_names[i])); | ||
| 312 | } | ||
| 313 | |||
| 314 | return j_profile_names; | ||
| 315 | } | ||
| 316 | |||
| 317 | jboolean Java_org_yuzu_yuzu_1emu_features_input_NativeInput_isProfileNameValid(JNIEnv* env, | ||
| 318 | jobject j_obj, | ||
| 319 | jstring j_name) { | ||
| 320 | return Common::Android::GetJString(env, j_name).find_first_of("<>:;\"/\\|,.!?*") == | ||
| 321 | std::string::npos; | ||
| 322 | } | ||
| 323 | |||
| 324 | jboolean Java_org_yuzu_yuzu_1emu_features_input_NativeInput_createProfile(JNIEnv* env, | ||
| 325 | jobject j_obj, | ||
| 326 | jstring j_name, | ||
| 327 | jint j_player_index) { | ||
| 328 | auto profile_name = Common::Android::GetJString(env, j_name); | ||
| 329 | if (ProfileExistsInMap(profile_name)) { | ||
| 330 | return false; | ||
| 331 | } | ||
| 332 | |||
| 333 | map_profiles.insert_or_assign( | ||
| 334 | profile_name, | ||
| 335 | std::make_unique<AndroidConfig>(profile_name, Config::ConfigType::InputProfile)); | ||
| 336 | |||
| 337 | return SaveProfile(profile_name, j_player_index); | ||
| 338 | } | ||
| 339 | |||
| 340 | jboolean Java_org_yuzu_yuzu_1emu_features_input_NativeInput_deleteProfile(JNIEnv* env, | ||
| 341 | jobject j_obj, | ||
| 342 | jstring j_name, | ||
| 343 | jint j_player_index) { | ||
| 344 | auto profile_name = Common::Android::GetJString(env, j_name); | ||
| 345 | if (!ProfileExistsInMap(profile_name)) { | ||
| 346 | return false; | ||
| 347 | } | ||
| 348 | |||
| 349 | if (!ProfileExistsInFilesystem(profile_name) || | ||
| 350 | Common::FS::RemoveFile(map_profiles[profile_name]->GetConfigFilePath())) { | ||
| 351 | map_profiles.erase(profile_name); | ||
| 352 | } | ||
| 353 | |||
| 354 | Settings::values.players.GetValue()[j_player_index].profile_name = ""; | ||
| 355 | return !ProfileExistsInMap(profile_name) && !ProfileExistsInFilesystem(profile_name); | ||
| 356 | } | ||
| 357 | |||
| 358 | jboolean Java_org_yuzu_yuzu_1emu_features_input_NativeInput_loadProfile(JNIEnv* env, jobject j_obj, | ||
| 359 | jstring j_name, | ||
| 360 | jint j_player_index) { | ||
| 361 | auto profile_name = Common::Android::GetJString(env, j_name); | ||
| 362 | return LoadProfile(profile_name, j_player_index); | ||
| 363 | } | ||
| 364 | |||
| 365 | jboolean Java_org_yuzu_yuzu_1emu_features_input_NativeInput_saveProfile(JNIEnv* env, jobject j_obj, | ||
| 366 | jstring j_name, | ||
| 367 | jint j_player_index) { | ||
| 368 | auto profile_name = Common::Android::GetJString(env, j_name); | ||
| 369 | return SaveProfile(profile_name, j_player_index); | ||
| 370 | } | ||
| 371 | |||
| 372 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_loadPerGameConfiguration( | ||
| 373 | JNIEnv* env, jobject j_obj, jint j_player_index, jint j_selected_index, | ||
| 374 | jstring j_selected_profile_name) { | ||
| 375 | static constexpr size_t HANDHELD_INDEX = 8; | ||
| 376 | |||
| 377 | auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); | ||
| 378 | Settings::values.players.SetGlobal(false); | ||
| 379 | |||
| 380 | auto profile_name = Common::Android::GetJString(env, j_selected_profile_name); | ||
| 381 | auto* emulated_controller = hid_core.GetEmulatedControllerByIndex(j_player_index); | ||
| 382 | |||
| 383 | if (j_selected_index == 0) { | ||
| 384 | Settings::values.players.GetValue()[j_player_index].profile_name = ""; | ||
| 385 | if (j_player_index == 0) { | ||
| 386 | Settings::values.players.GetValue()[HANDHELD_INDEX] = {}; | ||
| 387 | } | ||
| 388 | Settings::values.players.SetGlobal(true); | ||
| 389 | emulated_controller->ReloadFromSettings(); | ||
| 390 | return; | ||
| 391 | } | ||
| 392 | if (profile_name.empty()) { | ||
| 393 | return; | ||
| 394 | } | ||
| 395 | auto& player = Settings::values.players.GetValue()[j_player_index]; | ||
| 396 | auto& global_player = Settings::values.players.GetValue(true)[j_player_index]; | ||
| 397 | player.profile_name = profile_name; | ||
| 398 | global_player.profile_name = profile_name; | ||
| 399 | // Read from the profile into the custom player settings | ||
| 400 | LoadProfile(profile_name, j_player_index); | ||
| 401 | // Make sure the controller is connected | ||
| 402 | player.connected = true; | ||
| 403 | |||
| 404 | emulated_controller->ReloadFromSettings(); | ||
| 405 | |||
| 406 | if (j_player_index > 0) { | ||
| 407 | return; | ||
| 408 | } | ||
| 409 | // Handle Handheld cases | ||
| 410 | auto& handheld_player = Settings::values.players.GetValue()[HANDHELD_INDEX]; | ||
| 411 | auto* handheld_controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); | ||
| 412 | if (player.controller_type == Settings::ControllerType::Handheld) { | ||
| 413 | handheld_player = player; | ||
| 414 | } else { | ||
| 415 | handheld_player = {}; | ||
| 416 | } | ||
| 417 | handheld_controller->ReloadFromSettings(); | ||
| 418 | } | ||
| 419 | |||
| 420 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_beginMapping(JNIEnv* env, jobject j_obj, | ||
| 421 | jint jtype) { | ||
| 422 | EmulationSession::GetInstance().GetInputSubsystem().BeginMapping( | ||
| 423 | static_cast<InputCommon::Polling::InputType>(jtype)); | ||
| 424 | } | ||
| 425 | |||
| 426 | jstring Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getNextInput(JNIEnv* env, | ||
| 427 | jobject j_obj) { | ||
| 428 | return Common::Android::ToJString( | ||
| 429 | env, EmulationSession::GetInstance().GetInputSubsystem().GetNextInput().Serialize()); | ||
| 430 | } | ||
| 431 | |||
| 432 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_stopMapping(JNIEnv* env, jobject j_obj) { | ||
| 433 | EmulationSession::GetInstance().GetInputSubsystem().StopMapping(); | ||
| 434 | } | ||
| 435 | |||
| 436 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_updateMappingsWithDefaultImpl( | ||
| 437 | JNIEnv* env, jobject j_obj, jint j_player_index, jstring j_device_params, | ||
| 438 | jstring j_display_name) { | ||
| 439 | auto& input_subsystem = EmulationSession::GetInstance().GetInputSubsystem(); | ||
| 440 | |||
| 441 | // Clear all previous mappings | ||
| 442 | for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { | ||
| 443 | ApplyControllerConfig(j_player_index, [&](Core::HID::EmulatedController* controller) { | ||
| 444 | controller->SetButtonParam(button_id, {}); | ||
| 445 | }); | ||
| 446 | } | ||
| 447 | for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { | ||
| 448 | ApplyControllerConfig(j_player_index, [&](Core::HID::EmulatedController* controller) { | ||
| 449 | controller->SetStickParam(analog_id, {}); | ||
| 450 | }); | ||
| 451 | } | ||
| 452 | |||
| 453 | // Apply new mappings | ||
| 454 | auto device = Common::ParamPackage(Common::Android::GetJString(env, j_device_params)); | ||
| 455 | auto button_mappings = input_subsystem.GetButtonMappingForDevice(device); | ||
| 456 | auto analog_mappings = input_subsystem.GetAnalogMappingForDevice(device); | ||
| 457 | auto display_name = Common::Android::GetJString(env, j_display_name); | ||
| 458 | for (const auto& button_mapping : button_mappings) { | ||
| 459 | const std::size_t index = button_mapping.first; | ||
| 460 | auto named_mapping = button_mapping.second; | ||
| 461 | named_mapping.Set("display", display_name); | ||
| 462 | ApplyControllerConfig(j_player_index, [&](Core::HID::EmulatedController* controller) { | ||
| 463 | controller->SetButtonParam(index, named_mapping); | ||
| 464 | }); | ||
| 465 | } | ||
| 466 | for (const auto& analog_mapping : analog_mappings) { | ||
| 467 | const std::size_t index = analog_mapping.first; | ||
| 468 | auto named_mapping = analog_mapping.second; | ||
| 469 | named_mapping.Set("display", display_name); | ||
| 470 | ApplyControllerConfig(j_player_index, [&](Core::HID::EmulatedController* controller) { | ||
| 471 | controller->SetStickParam(index, named_mapping); | ||
| 472 | }); | ||
| 473 | } | ||
| 474 | } | ||
| 475 | |||
| 476 | jstring Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getButtonParamImpl(JNIEnv* env, | ||
| 477 | jobject j_obj, | ||
| 478 | jint j_player_index, | ||
| 479 | jint j_button) { | ||
| 480 | return Common::Android::ToJString(env, EmulationSession::GetInstance() | ||
| 481 | .System() | ||
| 482 | .HIDCore() | ||
| 483 | .GetEmulatedControllerByIndex(j_player_index) | ||
| 484 | ->GetButtonParam(j_button) | ||
| 485 | .Serialize()); | ||
| 486 | } | ||
| 487 | |||
| 488 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_setButtonParamImpl( | ||
| 489 | JNIEnv* env, jobject j_obj, jint j_player_index, jint j_button_id, jstring j_param) { | ||
| 490 | ApplyControllerConfig(j_player_index, [&](Core::HID::EmulatedController* controller) { | ||
| 491 | controller->SetButtonParam(j_button_id, | ||
| 492 | Common::ParamPackage(Common::Android::GetJString(env, j_param))); | ||
| 493 | }); | ||
| 494 | } | ||
| 495 | |||
| 496 | jstring Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getStickParamImpl(JNIEnv* env, | ||
| 497 | jobject j_obj, | ||
| 498 | jint j_player_index, | ||
| 499 | jint j_stick) { | ||
| 500 | return Common::Android::ToJString(env, EmulationSession::GetInstance() | ||
| 501 | .System() | ||
| 502 | .HIDCore() | ||
| 503 | .GetEmulatedControllerByIndex(j_player_index) | ||
| 504 | ->GetStickParam(j_stick) | ||
| 505 | .Serialize()); | ||
| 506 | } | ||
| 507 | |||
| 508 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_setStickParamImpl( | ||
| 509 | JNIEnv* env, jobject j_obj, jint j_player_index, jint j_stick_id, jstring j_param) { | ||
| 510 | ApplyControllerConfig(j_player_index, [&](Core::HID::EmulatedController* controller) { | ||
| 511 | controller->SetStickParam(j_stick_id, | ||
| 512 | Common::ParamPackage(Common::Android::GetJString(env, j_param))); | ||
| 513 | }); | ||
| 514 | } | ||
| 515 | |||
| 516 | jint Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getButtonNameImpl(JNIEnv* env, | ||
| 517 | jobject j_obj, | ||
| 518 | jstring j_param) { | ||
| 519 | return static_cast<jint>(EmulationSession::GetInstance().GetInputSubsystem().GetButtonName( | ||
| 520 | Common::ParamPackage(Common::Android::GetJString(env, j_param)))); | ||
| 521 | } | ||
| 522 | |||
| 523 | jintArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getSupportedStyleTagsImpl( | ||
| 524 | JNIEnv* env, jobject j_obj, jint j_player_index) { | ||
| 525 | auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); | ||
| 526 | const auto npad_style_set = hid_core.GetSupportedStyleTag(); | ||
| 527 | std::vector<s32> supported_indexes; | ||
| 528 | if (npad_style_set.fullkey == 1) { | ||
| 529 | supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Fullkey)); | ||
| 530 | } | ||
| 531 | |||
| 532 | if (npad_style_set.joycon_dual == 1) { | ||
| 533 | supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconDual)); | ||
| 534 | } | ||
| 535 | |||
| 536 | if (npad_style_set.joycon_left == 1) { | ||
| 537 | supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconLeft)); | ||
| 538 | } | ||
| 539 | |||
| 540 | if (npad_style_set.joycon_right == 1) { | ||
| 541 | supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconRight)); | ||
| 542 | } | ||
| 543 | |||
| 544 | if (j_player_index == 0 && npad_style_set.handheld == 1) { | ||
| 545 | supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Handheld)); | ||
| 546 | } | ||
| 547 | |||
| 548 | if (npad_style_set.gamecube == 1) { | ||
| 549 | supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::GameCube)); | ||
| 550 | } | ||
| 551 | |||
| 552 | jintArray j_supported_indexes = env->NewIntArray(supported_indexes.size()); | ||
| 553 | env->SetIntArrayRegion(j_supported_indexes, 0, supported_indexes.size(), | ||
| 554 | supported_indexes.data()); | ||
| 555 | return j_supported_indexes; | ||
| 556 | } | ||
| 557 | |||
| 558 | jint Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getStyleIndexImpl(JNIEnv* env, | ||
| 559 | jobject j_obj, | ||
| 560 | jint j_player_index) { | ||
| 561 | return static_cast<s32>(EmulationSession::GetInstance() | ||
| 562 | .System() | ||
| 563 | .HIDCore() | ||
| 564 | .GetEmulatedControllerByIndex(j_player_index) | ||
| 565 | ->GetNpadStyleIndex(true)); | ||
| 566 | } | ||
| 567 | |||
| 568 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_setStyleIndexImpl(JNIEnv* env, | ||
| 569 | jobject j_obj, | ||
| 570 | jint j_player_index, | ||
| 571 | jint j_style_index) { | ||
| 572 | auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); | ||
| 573 | auto type = static_cast<Core::HID::NpadStyleIndex>(j_style_index); | ||
| 574 | ApplyControllerConfig(j_player_index, [&](Core::HID::EmulatedController* controller) { | ||
| 575 | controller->SetNpadStyleIndex(type); | ||
| 576 | }); | ||
| 577 | if (j_player_index == 0) { | ||
| 578 | auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); | ||
| 579 | auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); | ||
| 580 | ConnectController(j_player_index, | ||
| 581 | player_one->IsConnected(true) || handheld->IsConnected(true)); | ||
| 582 | } | ||
| 583 | } | ||
| 584 | |||
| 585 | jboolean Java_org_yuzu_yuzu_1emu_features_input_NativeInput_isControllerImpl(JNIEnv* env, | ||
| 586 | jobject j_obj, | ||
| 587 | jstring jparams) { | ||
| 588 | return static_cast<jint>(EmulationSession::GetInstance().GetInputSubsystem().IsController( | ||
| 589 | Common::ParamPackage(Common::Android::GetJString(env, jparams)))); | ||
| 590 | } | ||
| 591 | |||
| 592 | jboolean Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getIsConnected(JNIEnv* env, | ||
| 593 | jobject j_obj, | ||
| 594 | jint j_player_index) { | ||
| 595 | auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); | ||
| 596 | auto* controller = hid_core.GetEmulatedControllerByIndex(static_cast<size_t>(j_player_index)); | ||
| 597 | if (j_player_index == 0 && | ||
| 598 | controller->GetNpadStyleIndex(true) == Core::HID::NpadStyleIndex::Handheld) { | ||
| 599 | return hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld)->IsConnected(true); | ||
| 600 | } | ||
| 601 | return controller->IsConnected(true); | ||
| 602 | } | ||
| 603 | |||
| 604 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_connectControllersImpl( | ||
| 605 | JNIEnv* env, jobject j_obj, jbooleanArray j_connected) { | ||
| 606 | jboolean isCopy = false; | ||
| 607 | auto j_connected_array_size = env->GetArrayLength(j_connected); | ||
| 608 | jboolean* j_connected_array = env->GetBooleanArrayElements(j_connected, &isCopy); | ||
| 609 | for (int i = 0; i < j_connected_array_size; ++i) { | ||
| 610 | ConnectController(i, j_connected_array[i]); | ||
| 611 | } | ||
| 612 | } | ||
| 613 | |||
| 614 | void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_resetControllerMappings( | ||
| 615 | JNIEnv* env, jobject j_obj, jint j_player_index) { | ||
| 616 | // Clear all previous mappings | ||
| 617 | for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { | ||
| 618 | ApplyControllerConfig(j_player_index, [&](Core::HID::EmulatedController* controller) { | ||
| 619 | controller->SetButtonParam(button_id, {}); | ||
| 620 | }); | ||
| 621 | } | ||
| 622 | for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { | ||
| 623 | ApplyControllerConfig(j_player_index, [&](Core::HID::EmulatedController* controller) { | ||
| 624 | controller->SetStickParam(analog_id, {}); | ||
| 625 | }); | ||
| 626 | } | ||
| 627 | } | ||
| 628 | |||
| 629 | } // extern "C" | ||
diff --git a/src/android/app/src/main/res/drawable/button_anim.xml b/src/android/app/src/main/res/drawable/button_anim.xml new file mode 100644 index 000000000..ccdc5ca6a --- /dev/null +++ b/src/android/app/src/main/res/drawable/button_anim.xml | |||
| @@ -0,0 +1,142 @@ | |||
| 1 | <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 2 | xmlns:aapt="http://schemas.android.com/aapt"> | ||
| 3 | <aapt:attr name="android:drawable"> | ||
| 4 | <vector | ||
| 5 | android:width="1000dp" | ||
| 6 | android:height="1000dp" | ||
| 7 | android:viewportWidth="1000" | ||
| 8 | android:viewportHeight="1000"> | ||
| 9 | <group android:name="_R_G"> | ||
| 10 | <group | ||
| 11 | android:name="_R_G_L_0_G" | ||
| 12 | android:pivotX="100" | ||
| 13 | android:pivotY="100" | ||
| 14 | android:scaleX="4.5" | ||
| 15 | android:scaleY="4.5" | ||
| 16 | android:translateX="400" | ||
| 17 | android:translateY="400"> | ||
| 18 | <path | ||
| 19 | android:name="_R_G_L_0_G_D_0_P_0" | ||
| 20 | android:fillAlpha="1" | ||
| 21 | android:fillColor="?attr/colorSecondaryContainer" | ||
| 22 | android:fillType="nonZero" | ||
| 23 | android:pathData=" M198.56 100 C198.56,154.43 154.43,198.56 100,198.56 C45.57,198.56 1.44,154.43 1.44,100 C1.44,45.57 45.57,1.44 100,1.44 C154.43,1.44 198.56,45.57 198.56,100c " /> | ||
| 24 | <path | ||
| 25 | android:name="_R_G_L_0_G_D_2_P_0" | ||
| 26 | android:fillAlpha="0.8" | ||
| 27 | android:fillColor="?attr/colorOnSecondaryContainer" | ||
| 28 | android:fillType="nonZero" | ||
| 29 | android:pathData=" M50.14 151.21 C50.53,150.18 89.6,49.87 90.1,48.63 C90.1,48.63 90.67,47.2 90.67,47.2 C90.67,47.2 101.67,47.2 101.67,47.2 C101.67,47.2 112.67,47.2 112.67,47.2 C112.67,47.2 133.47,99.12 133.47,99.12 C144.91,127.68 154.32,151.17 154.38,151.33 C154.47,151.56 152.2,151.6 143.14,151.55 C143.14,151.55 131.79,151.48 131.79,151.48 C131.79,151.48 127.22,139.57 127.22,139.57 C127.22,139.57 122.65,127.66 122.65,127.66 C122.65,127.66 101.68,127.73 101.68,127.73 C101.68,127.73 80.71,127.8 80.71,127.8 C80.71,127.8 76.38,139.71 76.38,139.71 C76.38,139.71 72.06,151.62 72.06,151.62 C72.06,151.62 61.02,151.62 61.02,151.62 C50.61,151.62 50,151.55 50.14,151.22 C50.14,151.22 50.14,151.21 50.14,151.21c M115.86 110.06 C115.8,109.91 112.55,101.13 108.62,90.56 C104.7,80 101.42,71.43 101.34,71.53 C101.22,71.66 92.84,94.61 87.25,110.06 C87.17,110.29 90.13,110.34 101.56,110.34 C113,110.34 115.95,110.28 115.86,110.06c " /> | ||
| 30 | </group> | ||
| 31 | </group> | ||
| 32 | <group android:name="time_group" /> | ||
| 33 | </vector> | ||
| 34 | </aapt:attr> | ||
| 35 | <target android:name="_R_G_L_0_G"> | ||
| 36 | <aapt:attr name="android:animation"> | ||
| 37 | <set android:ordering="together"> | ||
| 38 | <objectAnimator | ||
| 39 | android:duration="100" | ||
| 40 | android:propertyName="scaleX" | ||
| 41 | android:startOffset="0" | ||
| 42 | android:valueFrom="4.5" | ||
| 43 | android:valueTo="3.75" | ||
| 44 | android:valueType="floatType"> | ||
| 45 | <aapt:attr name="android:interpolator"> | ||
| 46 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> | ||
| 47 | </aapt:attr> | ||
| 48 | </objectAnimator> | ||
| 49 | <objectAnimator | ||
| 50 | android:duration="100" | ||
| 51 | android:propertyName="scaleY" | ||
| 52 | android:startOffset="0" | ||
| 53 | android:valueFrom="4.5" | ||
| 54 | android:valueTo="3.75" | ||
| 55 | android:valueType="floatType"> | ||
| 56 | <aapt:attr name="android:interpolator"> | ||
| 57 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> | ||
| 58 | </aapt:attr> | ||
| 59 | </objectAnimator> | ||
| 60 | <objectAnimator | ||
| 61 | android:duration="234" | ||
| 62 | android:propertyName="scaleX" | ||
| 63 | android:startOffset="100" | ||
| 64 | android:valueFrom="3.75" | ||
| 65 | android:valueTo="3.75" | ||
| 66 | android:valueType="floatType"> | ||
| 67 | <aapt:attr name="android:interpolator"> | ||
| 68 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> | ||
| 69 | </aapt:attr> | ||
| 70 | </objectAnimator> | ||
| 71 | <objectAnimator | ||
| 72 | android:duration="234" | ||
| 73 | android:propertyName="scaleY" | ||
| 74 | android:startOffset="100" | ||
| 75 | android:valueFrom="3.75" | ||
| 76 | android:valueTo="3.75" | ||
| 77 | android:valueType="floatType"> | ||
| 78 | <aapt:attr name="android:interpolator"> | ||
| 79 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> | ||
| 80 | </aapt:attr> | ||
| 81 | </objectAnimator> | ||
| 82 | <objectAnimator | ||
| 83 | android:duration="167" | ||
| 84 | android:propertyName="scaleX" | ||
| 85 | android:startOffset="334" | ||
| 86 | android:valueFrom="3.75" | ||
| 87 | android:valueTo="4.75" | ||
| 88 | android:valueType="floatType"> | ||
| 89 | <aapt:attr name="android:interpolator"> | ||
| 90 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> | ||
| 91 | </aapt:attr> | ||
| 92 | </objectAnimator> | ||
| 93 | <objectAnimator | ||
| 94 | android:duration="167" | ||
| 95 | android:propertyName="scaleY" | ||
| 96 | android:startOffset="334" | ||
| 97 | android:valueFrom="3.75" | ||
| 98 | android:valueTo="4.75" | ||
| 99 | android:valueType="floatType"> | ||
| 100 | <aapt:attr name="android:interpolator"> | ||
| 101 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> | ||
| 102 | </aapt:attr> | ||
| 103 | </objectAnimator> | ||
| 104 | <objectAnimator | ||
| 105 | android:duration="67" | ||
| 106 | android:propertyName="scaleX" | ||
| 107 | android:startOffset="501" | ||
| 108 | android:valueFrom="4.75" | ||
| 109 | android:valueTo="4.5" | ||
| 110 | android:valueType="floatType"> | ||
| 111 | <aapt:attr name="android:interpolator"> | ||
| 112 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> | ||
| 113 | </aapt:attr> | ||
| 114 | </objectAnimator> | ||
| 115 | <objectAnimator | ||
| 116 | android:duration="67" | ||
| 117 | android:propertyName="scaleY" | ||
| 118 | android:startOffset="501" | ||
| 119 | android:valueFrom="4.75" | ||
| 120 | android:valueTo="4.5" | ||
| 121 | android:valueType="floatType"> | ||
| 122 | <aapt:attr name="android:interpolator"> | ||
| 123 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> | ||
| 124 | </aapt:attr> | ||
| 125 | </objectAnimator> | ||
| 126 | </set> | ||
| 127 | </aapt:attr> | ||
| 128 | </target> | ||
| 129 | <target android:name="time_group"> | ||
| 130 | <aapt:attr name="android:animation"> | ||
| 131 | <set android:ordering="together"> | ||
| 132 | <objectAnimator | ||
| 133 | android:duration="1034" | ||
| 134 | android:propertyName="translateX" | ||
| 135 | android:startOffset="0" | ||
| 136 | android:valueFrom="0" | ||
| 137 | android:valueTo="1" | ||
| 138 | android:valueType="floatType" /> | ||
| 139 | </set> | ||
| 140 | </aapt:attr> | ||
| 141 | </target> | ||
| 142 | </animated-vector> | ||
diff --git a/src/android/app/src/main/res/drawable/ic_controller_disconnected.xml b/src/android/app/src/main/res/drawable/ic_controller_disconnected.xml new file mode 100644 index 000000000..8e3c66f74 --- /dev/null +++ b/src/android/app/src/main/res/drawable/ic_controller_disconnected.xml | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 2 | android:width="24dp" | ||
| 3 | android:height="24dp" | ||
| 4 | android:viewportWidth="960" | ||
| 5 | android:viewportHeight="960"> | ||
| 6 | <path | ||
| 7 | android:fillColor="?attr/colorControlNormal" | ||
| 8 | android:pathData="M700,480q-25,0 -42.5,-17.5T640,420q0,-25 17.5,-42.5T700,360q25,0 42.5,17.5T760,420q0,25 -17.5,42.5T700,480ZM366,480ZM280,600v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80ZM160,720q-33,0 -56.5,-23.5T80,640v-320q0,-34 24,-57.5t58,-23.5h77l81,81L160,320v320h366L55,169l57,-57 736,736 -57,57 -185,-185L160,720ZM880,640q0,26 -14,46t-37,29l-29,-29v-366L434,320l-80,-80h446q33,0 56.5,23.5T880,320v320ZM617,503Z" /> | ||
| 9 | </vector> | ||
diff --git a/src/android/app/src/main/res/drawable/ic_more_vert.xml b/src/android/app/src/main/res/drawable/ic_more_vert.xml new file mode 100644 index 000000000..9f62ac595 --- /dev/null +++ b/src/android/app/src/main/res/drawable/ic_more_vert.xml | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 2 | android:height="24dp" | ||
| 3 | android:viewportHeight="24" | ||
| 4 | android:viewportWidth="24" | ||
| 5 | android:width="24dp"> | ||
| 6 | <path | ||
| 7 | android:fillColor="?attr/colorControlNormal" | ||
| 8 | android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z" /> | ||
| 9 | </vector> | ||
diff --git a/src/android/app/src/main/res/drawable/ic_new_label.xml b/src/android/app/src/main/res/drawable/ic_new_label.xml new file mode 100644 index 000000000..fac562c26 --- /dev/null +++ b/src/android/app/src/main/res/drawable/ic_new_label.xml | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 2 | android:width="24dp" | ||
| 3 | android:height="24dp" | ||
| 4 | android:viewportWidth="24" | ||
| 5 | android:viewportHeight="24"> | ||
| 6 | <path | ||
| 7 | android:fillColor="?attr/colorControlNormal" | ||
| 8 | android:pathData="M21,12l-4.37,6.16C16.26,18.68 15.65,19 15,19h-3l0,-6H9v-3H3V7c0,-1.1 0.9,-2 2,-2h10c0.65,0 1.26,0.31 1.63,0.84L21,12zM10,15H7v-3H5v3H2v2h3v3h2v-3h3V15z" /> | ||
| 9 | </vector> | ||
diff --git a/src/android/app/src/main/res/drawable/ic_overlay.xml b/src/android/app/src/main/res/drawable/ic_overlay.xml new file mode 100644 index 000000000..c7986c5a2 --- /dev/null +++ b/src/android/app/src/main/res/drawable/ic_overlay.xml | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 2 | android:width="24dp" | ||
| 3 | android:height="24dp" | ||
| 4 | android:viewportWidth="24" | ||
| 5 | android:viewportHeight="24"> | ||
| 6 | <path | ||
| 7 | android:fillColor="?attr/colorControlNormal" | ||
| 8 | android:pathData="M21,5H3C1.9,5 1,5.9 1,7v10c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2V7C23,5.9 22.1,5 21,5zM18,17H6V7h12V17z" /> | ||
| 9 | <path | ||
| 10 | android:fillColor="?attr/colorControlNormal" | ||
| 11 | android:pathData="M15,11.25h1.5v1.5h-1.5z" /> | ||
| 12 | <path | ||
| 13 | android:fillColor="?attr/colorControlNormal" | ||
| 14 | android:pathData="M12.5,11.25h1.5v1.5h-1.5z" /> | ||
| 15 | <path | ||
| 16 | android:fillColor="?attr/colorControlNormal" | ||
| 17 | android:pathData="M10,11.25h1.5v1.5h-1.5z" /> | ||
| 18 | <path | ||
| 19 | android:fillColor="?attr/colorControlNormal" | ||
| 20 | android:pathData="M7.5,11.25h1.5v1.5h-1.5z" /> | ||
| 21 | </vector> | ||
diff --git a/src/android/app/src/main/res/drawable/ic_share.xml b/src/android/app/src/main/res/drawable/ic_share.xml new file mode 100644 index 000000000..3fc2f3c99 --- /dev/null +++ b/src/android/app/src/main/res/drawable/ic_share.xml | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 2 | android:width="24dp" | ||
| 3 | android:height="24dp" | ||
| 4 | android:viewportWidth="24" | ||
| 5 | android:viewportHeight="24"> | ||
| 6 | <path | ||
| 7 | android:fillColor="?attr/colorControlNormal" | ||
| 8 | android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z" /> | ||
| 9 | </vector> | ||
diff --git a/src/android/app/src/main/res/drawable/stick_one_direction_anim.xml b/src/android/app/src/main/res/drawable/stick_one_direction_anim.xml new file mode 100644 index 000000000..a1da1316f --- /dev/null +++ b/src/android/app/src/main/res/drawable/stick_one_direction_anim.xml | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 2 | xmlns:aapt="http://schemas.android.com/aapt"> | ||
| 3 | <aapt:attr name="android:drawable"> | ||
| 4 | <vector | ||
| 5 | android:width="1000dp" | ||
| 6 | android:height="1000dp" | ||
| 7 | android:viewportWidth="1000" | ||
| 8 | android:viewportHeight="1000"> | ||
| 9 | <group android:name="_R_G"> | ||
| 10 | <group | ||
| 11 | android:name="_R_G_L_1_G" | ||
| 12 | android:pivotX="100" | ||
| 13 | android:pivotY="100" | ||
| 14 | android:scaleX="5" | ||
| 15 | android:scaleY="5" | ||
| 16 | android:translateX="400" | ||
| 17 | android:translateY="400"> | ||
| 18 | <path | ||
| 19 | android:name="_R_G_L_1_G_D_0_P_0" | ||
| 20 | android:pathData=" M100 199.39 C59.8,199.39 23.56,175.17 8.18,138.04 C-7.2,100.9 1.3,58.15 29.73,29.72 C58.15,1.3 100.9,-7.21 138.04,8.18 C175.18,23.56 199.39,59.8 199.39,100 C199.33,154.87 154.87,199.33 100,199.39c " | ||
| 21 | android:strokeWidth="1" | ||
| 22 | android:strokeAlpha="0.6" | ||
| 23 | android:strokeColor="?attr/colorOutline" | ||
| 24 | android:strokeLineCap="round" | ||
| 25 | android:strokeLineJoin="round" /> | ||
| 26 | </group> | ||
| 27 | <group | ||
| 28 | android:name="_R_G_L_0_G_T_1" | ||
| 29 | android:scaleX="5" | ||
| 30 | android:scaleY="5" | ||
| 31 | android:translateX="500" | ||
| 32 | android:translateY="500"> | ||
| 33 | <group | ||
| 34 | android:name="_R_G_L_0_G" | ||
| 35 | android:translateX="-100" | ||
| 36 | android:translateY="-100"> | ||
| 37 | <path | ||
| 38 | android:name="_R_G_L_0_G_D_0_P_0" | ||
| 39 | android:fillAlpha="1" | ||
| 40 | android:fillColor="?attr/colorSecondaryContainer" | ||
| 41 | android:fillType="nonZero" | ||
| 42 | android:pathData=" M100.45 28.02 C140.63,28.02 173.2,60.59 173.2,100.77 C173.2,140.95 140.63,173.52 100.45,173.52 C60.27,173.52 27.7,140.95 27.7,100.77 C27.7,60.59 60.27,28.02 100.45,28.02c " /> | ||
| 43 | <path | ||
| 44 | android:name="_R_G_L_0_G_D_2_P_0" | ||
| 45 | android:fillAlpha="0.8" | ||
| 46 | android:fillColor="?attr/colorOnSecondaryContainer" | ||
| 47 | android:fillType="nonZero" | ||
| 48 | android:pathData=" M100.45 50.26 C128.62,50.26 151.46,73.1 151.46,101.28 C151.46,129.45 128.62,152.29 100.45,152.29 C72.27,152.29 49.43,129.45 49.43,101.28 C49.43,73.1 72.27,50.26 100.45,50.26c " /> | ||
| 49 | </group> | ||
| 50 | </group> | ||
| 51 | </group> | ||
| 52 | <group android:name="time_group" /> | ||
| 53 | </vector> | ||
| 54 | </aapt:attr> | ||
| 55 | <target android:name="_R_G_L_0_G_T_1"> | ||
| 56 | <aapt:attr name="android:animation"> | ||
| 57 | <set android:ordering="together"> | ||
| 58 | <objectAnimator | ||
| 59 | android:duration="267" | ||
| 60 | android:pathData="M 500,500C 500,500 364,500 364,500" | ||
| 61 | android:propertyName="translateXY" | ||
| 62 | android:propertyXName="translateX" | ||
| 63 | android:propertyYName="translateY" | ||
| 64 | android:startOffset="0"> | ||
| 65 | <aapt:attr name="android:interpolator"> | ||
| 66 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> | ||
| 67 | </aapt:attr> | ||
| 68 | </objectAnimator> | ||
| 69 | <objectAnimator | ||
| 70 | android:duration="234" | ||
| 71 | android:pathData="M 364,500C 364,500 364,500 364,500" | ||
| 72 | android:propertyName="translateXY" | ||
| 73 | android:propertyXName="translateX" | ||
| 74 | android:propertyYName="translateY" | ||
| 75 | android:startOffset="267"> | ||
| 76 | <aapt:attr name="android:interpolator"> | ||
| 77 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0.333 0.667,0.667 1.0,1.0" /> | ||
| 78 | </aapt:attr> | ||
| 79 | </objectAnimator> | ||
| 80 | <objectAnimator | ||
| 81 | android:duration="133" | ||
| 82 | android:pathData="M 364,500C 364,500 525,500 525,500" | ||
| 83 | android:propertyName="translateXY" | ||
| 84 | android:propertyXName="translateX" | ||
| 85 | android:propertyYName="translateY" | ||
| 86 | android:startOffset="501"> | ||
| 87 | <aapt:attr name="android:interpolator"> | ||
| 88 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> | ||
| 89 | </aapt:attr> | ||
| 90 | </objectAnimator> | ||
| 91 | <objectAnimator | ||
| 92 | android:duration="100" | ||
| 93 | android:pathData="M 525,500C 525,500 500,500 500,500" | ||
| 94 | android:propertyName="translateXY" | ||
| 95 | android:propertyXName="translateX" | ||
| 96 | android:propertyYName="translateY" | ||
| 97 | android:startOffset="634"> | ||
| 98 | <aapt:attr name="android:interpolator"> | ||
| 99 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> | ||
| 100 | </aapt:attr> | ||
| 101 | </objectAnimator> | ||
| 102 | </set> | ||
| 103 | </aapt:attr> | ||
| 104 | </target> | ||
| 105 | <target android:name="time_group"> | ||
| 106 | <aapt:attr name="android:animation"> | ||
| 107 | <set android:ordering="together"> | ||
| 108 | <objectAnimator | ||
| 109 | android:duration="968" | ||
| 110 | android:propertyName="translateX" | ||
| 111 | android:startOffset="0" | ||
| 112 | android:valueFrom="0" | ||
| 113 | android:valueTo="1" | ||
| 114 | android:valueType="floatType" /> | ||
| 115 | </set> | ||
| 116 | </aapt:attr> | ||
| 117 | </target> | ||
| 118 | </animated-vector> | ||
diff --git a/src/android/app/src/main/res/drawable/stick_two_direction_anim.xml b/src/android/app/src/main/res/drawable/stick_two_direction_anim.xml new file mode 100644 index 000000000..bc71adcbd --- /dev/null +++ b/src/android/app/src/main/res/drawable/stick_two_direction_anim.xml | |||
| @@ -0,0 +1,173 @@ | |||
| 1 | <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 2 | xmlns:aapt="http://schemas.android.com/aapt"> | ||
| 3 | <aapt:attr name="android:drawable"> | ||
| 4 | <vector | ||
| 5 | android:width="1000dp" | ||
| 6 | android:height="1000dp" | ||
| 7 | android:viewportWidth="1000" | ||
| 8 | android:viewportHeight="1000"> | ||
| 9 | <group android:name="_R_G"> | ||
| 10 | <group | ||
| 11 | android:name="_R_G_L_1_G" | ||
| 12 | android:pivotX="100" | ||
| 13 | android:pivotY="100" | ||
| 14 | android:scaleX="5" | ||
| 15 | android:scaleY="5" | ||
| 16 | android:translateX="400" | ||
| 17 | android:translateY="400"> | ||
| 18 | <path | ||
| 19 | android:name="_R_G_L_1_G_D_0_P_0" | ||
| 20 | android:pathData=" M100 199.39 C59.8,199.39 23.56,175.17 8.18,138.04 C-7.2,100.9 1.3,58.15 29.73,29.72 C58.15,1.3 100.9,-7.21 138.04,8.18 C175.18,23.56 199.39,59.8 199.39,100 C199.33,154.87 154.87,199.33 100,199.39c " | ||
| 21 | android:strokeWidth="1" | ||
| 22 | android:strokeAlpha="0.6" | ||
| 23 | android:strokeColor="?attr/colorOutline" | ||
| 24 | android:strokeLineCap="round" | ||
| 25 | android:strokeLineJoin="round" /> | ||
| 26 | </group> | ||
| 27 | <group | ||
| 28 | android:name="_R_G_L_0_G_T_1" | ||
| 29 | android:scaleX="5" | ||
| 30 | android:scaleY="5" | ||
| 31 | android:translateX="500" | ||
| 32 | android:translateY="500"> | ||
| 33 | <group | ||
| 34 | android:name="_R_G_L_0_G" | ||
| 35 | android:translateX="-100" | ||
| 36 | android:translateY="-100"> | ||
| 37 | <path | ||
| 38 | android:name="_R_G_L_0_G_D_0_P_0" | ||
| 39 | android:fillAlpha="1" | ||
| 40 | android:fillColor="?attr/colorSecondaryContainer" | ||
| 41 | android:fillType="nonZero" | ||
| 42 | android:pathData=" M100.45 28.02 C140.63,28.02 173.2,60.59 173.2,100.77 C173.2,140.95 140.63,173.52 100.45,173.52 C60.27,173.52 27.7,140.95 27.7,100.77 C27.7,60.59 60.27,28.02 100.45,28.02c " /> | ||
| 43 | <path | ||
| 44 | android:name="_R_G_L_0_G_D_2_P_0" | ||
| 45 | android:fillAlpha="0.8" | ||
| 46 | android:fillColor="?attr/colorOnSecondaryContainer" | ||
| 47 | android:fillType="nonZero" | ||
| 48 | android:pathData=" M100.45 50.26 C128.62,50.26 151.46,73.1 151.46,101.28 C151.46,129.45 128.62,152.29 100.45,152.29 C72.27,152.29 49.43,129.45 49.43,101.28 C49.43,73.1 72.27,50.26 100.45,50.26c " /> | ||
| 49 | </group> | ||
| 50 | </group> | ||
| 51 | </group> | ||
| 52 | <group android:name="time_group" /> | ||
| 53 | </vector> | ||
| 54 | </aapt:attr> | ||
| 55 | <target android:name="_R_G_L_0_G_T_1"> | ||
| 56 | <aapt:attr name="android:animation"> | ||
| 57 | <set android:ordering="together"> | ||
| 58 | <objectAnimator | ||
| 59 | android:duration="267" | ||
| 60 | android:pathData="M 500,500C 500,500 364,500 364,500" | ||
| 61 | android:propertyName="translateXY" | ||
| 62 | android:propertyXName="translateX" | ||
| 63 | android:propertyYName="translateY" | ||
| 64 | android:startOffset="0"> | ||
| 65 | <aapt:attr name="android:interpolator"> | ||
| 66 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> | ||
| 67 | </aapt:attr> | ||
| 68 | </objectAnimator> | ||
| 69 | <objectAnimator | ||
| 70 | android:duration="234" | ||
| 71 | android:pathData="M 364,500C 364,500 364,500 364,500" | ||
| 72 | android:propertyName="translateXY" | ||
| 73 | android:propertyXName="translateX" | ||
| 74 | android:propertyYName="translateY" | ||
| 75 | android:startOffset="267"> | ||
| 76 | <aapt:attr name="android:interpolator"> | ||
| 77 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0.333 0.667,0.667 1.0,1.0" /> | ||
| 78 | </aapt:attr> | ||
| 79 | </objectAnimator> | ||
| 80 | <objectAnimator | ||
| 81 | android:duration="133" | ||
| 82 | android:pathData="M 364,500C 364,500 525,500 525,500" | ||
| 83 | android:propertyName="translateXY" | ||
| 84 | android:propertyXName="translateX" | ||
| 85 | android:propertyYName="translateY" | ||
| 86 | android:startOffset="501"> | ||
| 87 | <aapt:attr name="android:interpolator"> | ||
| 88 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> | ||
| 89 | </aapt:attr> | ||
| 90 | </objectAnimator> | ||
| 91 | <objectAnimator | ||
| 92 | android:duration="100" | ||
| 93 | android:pathData="M 525,500C 525,500 500,500 500,500" | ||
| 94 | android:propertyName="translateXY" | ||
| 95 | android:propertyXName="translateX" | ||
| 96 | android:propertyYName="translateY" | ||
| 97 | android:startOffset="634"> | ||
| 98 | <aapt:attr name="android:interpolator"> | ||
| 99 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> | ||
| 100 | </aapt:attr> | ||
| 101 | </objectAnimator> | ||
| 102 | <objectAnimator | ||
| 103 | android:duration="400" | ||
| 104 | android:pathData="M 500,500C 500,500 500,500 500,500" | ||
| 105 | android:propertyName="translateXY" | ||
| 106 | android:propertyXName="translateX" | ||
| 107 | android:propertyYName="translateY" | ||
| 108 | android:startOffset="734"> | ||
| 109 | <aapt:attr name="android:interpolator"> | ||
| 110 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0.333 0.667,0.667 1.0,1.0" /> | ||
| 111 | </aapt:attr> | ||
| 112 | </objectAnimator> | ||
| 113 | <objectAnimator | ||
| 114 | android:duration="267" | ||
| 115 | android:pathData="M 500,500C 500,500 500,364 500,364" | ||
| 116 | android:propertyName="translateXY" | ||
| 117 | android:propertyXName="translateX" | ||
| 118 | android:propertyYName="translateY" | ||
| 119 | android:startOffset="1134"> | ||
| 120 | <aapt:attr name="android:interpolator"> | ||
| 121 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> | ||
| 122 | </aapt:attr> | ||
| 123 | </objectAnimator> | ||
| 124 | <objectAnimator | ||
| 125 | android:duration="234" | ||
| 126 | android:pathData="M 500,364C 500,364 500,364 500,364" | ||
| 127 | android:propertyName="translateXY" | ||
| 128 | android:propertyXName="translateX" | ||
| 129 | android:propertyYName="translateY" | ||
| 130 | android:startOffset="1401"> | ||
| 131 | <aapt:attr name="android:interpolator"> | ||
| 132 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0.333 0.667,0.667 1.0,1.0" /> | ||
| 133 | </aapt:attr> | ||
| 134 | </objectAnimator> | ||
| 135 | <objectAnimator | ||
| 136 | android:duration="133" | ||
| 137 | android:pathData="M 500,364C 500,364 500,535 500,535" | ||
| 138 | android:propertyName="translateXY" | ||
| 139 | android:propertyXName="translateX" | ||
| 140 | android:propertyYName="translateY" | ||
| 141 | android:startOffset="1635"> | ||
| 142 | <aapt:attr name="android:interpolator"> | ||
| 143 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> | ||
| 144 | </aapt:attr> | ||
| 145 | </objectAnimator> | ||
| 146 | <objectAnimator | ||
| 147 | android:duration="100" | ||
| 148 | android:pathData="M 500,535C 500,535 500,500 500,500" | ||
| 149 | android:propertyName="translateXY" | ||
| 150 | android:propertyXName="translateX" | ||
| 151 | android:propertyYName="translateY" | ||
| 152 | android:startOffset="1768"> | ||
| 153 | <aapt:attr name="android:interpolator"> | ||
| 154 | <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.667,1 1.0,1.0" /> | ||
| 155 | </aapt:attr> | ||
| 156 | </objectAnimator> | ||
| 157 | </set> | ||
| 158 | </aapt:attr> | ||
| 159 | </target> | ||
| 160 | <target android:name="time_group"> | ||
| 161 | <aapt:attr name="android:animation"> | ||
| 162 | <set android:ordering="together"> | ||
| 163 | <objectAnimator | ||
| 164 | android:duration="2269" | ||
| 165 | android:propertyName="translateX" | ||
| 166 | android:startOffset="0" | ||
| 167 | android:valueFrom="0" | ||
| 168 | android:valueTo="1" | ||
| 169 | android:valueType="floatType" /> | ||
| 170 | </set> | ||
| 171 | </aapt:attr> | ||
| 172 | </target> | ||
| 173 | </animated-vector> | ||
diff --git a/src/android/app/src/main/res/layout-ldrtl/list_item_setting_input.xml b/src/android/app/src/main/res/layout-ldrtl/list_item_setting_input.xml new file mode 100644 index 000000000..583620dc6 --- /dev/null +++ b/src/android/app/src/main/res/layout-ldrtl/list_item_setting_input.xml | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 3 | xmlns:app="http://schemas.android.com/apk/res-auto" | ||
| 4 | xmlns:tools="http://schemas.android.com/tools" | ||
| 5 | android:id="@+id/setting_body" | ||
| 6 | android:layout_width="match_parent" | ||
| 7 | android:layout_height="wrap_content" | ||
| 8 | android:background="?android:attr/selectableItemBackground" | ||
| 9 | android:clickable="true" | ||
| 10 | android:focusable="true" | ||
| 11 | android:gravity="center_vertical" | ||
| 12 | android:minHeight="72dp" | ||
| 13 | android:padding="16dp" | ||
| 14 | android:nextFocusLeft="@id/button_options"> | ||
| 15 | |||
| 16 | <LinearLayout | ||
| 17 | android:layout_width="match_parent" | ||
| 18 | android:layout_height="wrap_content" | ||
| 19 | android:gravity="center_vertical" | ||
| 20 | android:orientation="horizontal"> | ||
| 21 | |||
| 22 | <LinearLayout | ||
| 23 | android:layout_width="0dp" | ||
| 24 | android:layout_height="wrap_content" | ||
| 25 | android:orientation="vertical" | ||
| 26 | android:layout_weight="1"> | ||
| 27 | |||
| 28 | <com.google.android.material.textview.MaterialTextView | ||
| 29 | android:id="@+id/text_setting_name" | ||
| 30 | style="@style/TextAppearance.Material3.HeadlineMedium" | ||
| 31 | android:layout_width="match_parent" | ||
| 32 | android:layout_height="wrap_content" | ||
| 33 | android:textAlignment="viewStart" | ||
| 34 | android:textSize="17sp" | ||
| 35 | app:lineHeight="22dp" | ||
| 36 | tools:text="Setting Name" /> | ||
| 37 | |||
| 38 | <com.google.android.material.textview.MaterialTextView | ||
| 39 | android:id="@+id/text_setting_value" | ||
| 40 | style="@style/TextAppearance.Material3.LabelMedium" | ||
| 41 | android:layout_width="match_parent" | ||
| 42 | android:layout_height="wrap_content" | ||
| 43 | android:layout_marginTop="@dimen/spacing_small" | ||
| 44 | android:textAlignment="viewStart" | ||
| 45 | android:textStyle="bold" | ||
| 46 | android:textSize="13sp" | ||
| 47 | tools:text="1x" /> | ||
| 48 | |||
| 49 | </LinearLayout> | ||
| 50 | |||
| 51 | <Button | ||
| 52 | android:id="@+id/button_options" | ||
| 53 | style="?attr/materialIconButtonStyle" | ||
| 54 | android:layout_width="wrap_content" | ||
| 55 | android:layout_height="wrap_content" | ||
| 56 | android:nextFocusRight="@id/setting_body" | ||
| 57 | app:icon="@drawable/ic_more_vert" | ||
| 58 | app:iconSize="24dp" | ||
| 59 | app:iconTint="?attr/colorOnSurface" /> | ||
| 60 | |||
| 61 | </LinearLayout> | ||
| 62 | |||
| 63 | </RelativeLayout> | ||
diff --git a/src/android/app/src/main/res/layout/card_driver_option.xml b/src/android/app/src/main/res/layout/card_driver_option.xml index bda524f0f..09e26990b 100644 --- a/src/android/app/src/main/res/layout/card_driver_option.xml +++ b/src/android/app/src/main/res/layout/card_driver_option.xml | |||
| @@ -39,10 +39,7 @@ | |||
| 39 | style="@style/TextAppearance.Material3.TitleMedium" | 39 | style="@style/TextAppearance.Material3.TitleMedium" |
| 40 | android:layout_width="match_parent" | 40 | android:layout_width="match_parent" |
| 41 | android:layout_height="wrap_content" | 41 | android:layout_height="wrap_content" |
| 42 | android:ellipsize="none" | ||
| 43 | android:marqueeRepeatLimit="marquee_forever" | ||
| 44 | android:requiresFadingEdge="horizontal" | 42 | android:requiresFadingEdge="horizontal" |
| 45 | android:singleLine="true" | ||
| 46 | android:textAlignment="viewStart" | 43 | android:textAlignment="viewStart" |
| 47 | tools:text="@string/select_gpu_driver_default" /> | 44 | tools:text="@string/select_gpu_driver_default" /> |
| 48 | 45 | ||
| @@ -52,10 +49,7 @@ | |||
| 52 | android:layout_width="match_parent" | 49 | android:layout_width="match_parent" |
| 53 | android:layout_height="wrap_content" | 50 | android:layout_height="wrap_content" |
| 54 | android:layout_marginTop="6dp" | 51 | android:layout_marginTop="6dp" |
| 55 | android:ellipsize="none" | ||
| 56 | android:marqueeRepeatLimit="marquee_forever" | ||
| 57 | android:requiresFadingEdge="horizontal" | 52 | android:requiresFadingEdge="horizontal" |
| 58 | android:singleLine="true" | ||
| 59 | android:textAlignment="viewStart" | 53 | android:textAlignment="viewStart" |
| 60 | tools:text="@string/install_gpu_driver_description" /> | 54 | tools:text="@string/install_gpu_driver_description" /> |
| 61 | 55 | ||
| @@ -65,10 +59,7 @@ | |||
| 65 | android:layout_width="match_parent" | 59 | android:layout_width="match_parent" |
| 66 | android:layout_height="wrap_content" | 60 | android:layout_height="wrap_content" |
| 67 | android:layout_marginTop="6dp" | 61 | android:layout_marginTop="6dp" |
| 68 | android:ellipsize="none" | ||
| 69 | android:marqueeRepeatLimit="marquee_forever" | ||
| 70 | android:requiresFadingEdge="horizontal" | 62 | android:requiresFadingEdge="horizontal" |
| 71 | android:singleLine="true" | ||
| 72 | android:textAlignment="viewStart" | 63 | android:textAlignment="viewStart" |
| 73 | tools:text="@string/install_gpu_driver_description" /> | 64 | tools:text="@string/install_gpu_driver_description" /> |
| 74 | 65 | ||
diff --git a/src/android/app/src/main/res/layout/card_folder.xml b/src/android/app/src/main/res/layout/card_folder.xml index ed4a7ca8f..e3a5f1a86 100644 --- a/src/android/app/src/main/res/layout/card_folder.xml +++ b/src/android/app/src/main/res/layout/card_folder.xml | |||
| @@ -21,10 +21,7 @@ | |||
| 21 | android:layout_width="0dp" | 21 | android:layout_width="0dp" |
| 22 | android:layout_height="wrap_content" | 22 | android:layout_height="wrap_content" |
| 23 | android:layout_gravity="center_vertical|start" | 23 | android:layout_gravity="center_vertical|start" |
| 24 | android:ellipsize="none" | ||
| 25 | android:marqueeRepeatLimit="marquee_forever" | ||
| 26 | android:requiresFadingEdge="horizontal" | 24 | android:requiresFadingEdge="horizontal" |
| 27 | android:singleLine="true" | ||
| 28 | android:textAlignment="viewStart" | 25 | android:textAlignment="viewStart" |
| 29 | app:layout_constraintBottom_toBottomOf="parent" | 26 | app:layout_constraintBottom_toBottomOf="parent" |
| 30 | app:layout_constraintEnd_toStartOf="@+id/button_layout" | 27 | app:layout_constraintEnd_toStartOf="@+id/button_layout" |
diff --git a/src/android/app/src/main/res/layout/card_game.xml b/src/android/app/src/main/res/layout/card_game.xml index 6340171ec..411b50315 100644 --- a/src/android/app/src/main/res/layout/card_game.xml +++ b/src/android/app/src/main/res/layout/card_game.xml | |||
| @@ -40,10 +40,7 @@ | |||
| 40 | android:layout_width="0dp" | 40 | android:layout_width="0dp" |
| 41 | android:layout_height="wrap_content" | 41 | android:layout_height="wrap_content" |
| 42 | android:layout_marginTop="8dp" | 42 | android:layout_marginTop="8dp" |
| 43 | android:ellipsize="none" | ||
| 44 | android:marqueeRepeatLimit="marquee_forever" | ||
| 45 | android:requiresFadingEdge="horizontal" | 43 | android:requiresFadingEdge="horizontal" |
| 46 | android:singleLine="true" | ||
| 47 | android:textAlignment="center" | 44 | android:textAlignment="center" |
| 48 | android:textSize="14sp" | 45 | android:textSize="14sp" |
| 49 | app:layout_constraintEnd_toEndOf="@+id/image_game_screen" | 46 | app:layout_constraintEnd_toEndOf="@+id/image_game_screen" |
diff --git a/src/android/app/src/main/res/layout/card_simple_outlined.xml b/src/android/app/src/main/res/layout/card_simple_outlined.xml index b73930e7e..e29df6a2d 100644 --- a/src/android/app/src/main/res/layout/card_simple_outlined.xml +++ b/src/android/app/src/main/res/layout/card_simple_outlined.xml | |||
| @@ -59,9 +59,6 @@ | |||
| 59 | android:textAlignment="viewStart" | 59 | android:textAlignment="viewStart" |
| 60 | android:textSize="14sp" | 60 | android:textSize="14sp" |
| 61 | android:textStyle="bold" | 61 | android:textStyle="bold" |
| 62 | android:singleLine="true" | ||
| 63 | android:marqueeRepeatLimit="marquee_forever" | ||
| 64 | android:ellipsize="none" | ||
| 65 | android:requiresFadingEdge="horizontal" | 62 | android:requiresFadingEdge="horizontal" |
| 66 | android:layout_marginTop="6dp" | 63 | android:layout_marginTop="6dp" |
| 67 | android:visibility="gone" | 64 | android:visibility="gone" |
diff --git a/src/android/app/src/main/res/layout/dialog_input_profiles.xml b/src/android/app/src/main/res/layout/dialog_input_profiles.xml new file mode 100644 index 000000000..6ad76fe41 --- /dev/null +++ b/src/android/app/src/main/res/layout/dialog_input_profiles.xml | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 3 | android:id="@+id/list_profiles" | ||
| 4 | android:layout_width="match_parent" | ||
| 5 | android:layout_height="wrap_content" | ||
| 6 | android:fadeScrollbars="false" /> | ||
diff --git a/src/android/app/src/main/res/layout/dialog_mapping.xml b/src/android/app/src/main/res/layout/dialog_mapping.xml new file mode 100644 index 000000000..06190b8d2 --- /dev/null +++ b/src/android/app/src/main/res/layout/dialog_mapping.xml | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 3 | android:layout_width="match_parent" | ||
| 4 | android:layout_height="wrap_content" | ||
| 5 | xmlns:tools="http://schemas.android.com/tools" | ||
| 6 | android:defaultFocusHighlightEnabled="false" | ||
| 7 | android:focusable="true" | ||
| 8 | android:focusableInTouchMode="true" | ||
| 9 | android:focusedByDefault="true" | ||
| 10 | android:orientation="horizontal" | ||
| 11 | android:gravity="center"> | ||
| 12 | |||
| 13 | <ImageView | ||
| 14 | android:id="@+id/image_stick_animation" | ||
| 15 | android:layout_width="@dimen/mapping_anim_size" | ||
| 16 | android:layout_height="@dimen/mapping_anim_size" | ||
| 17 | tools:src="@drawable/stick_two_direction_anim" /> | ||
| 18 | |||
| 19 | <ImageView | ||
| 20 | android:id="@+id/image_button_animation" | ||
| 21 | android:layout_width="@dimen/mapping_anim_size" | ||
| 22 | android:layout_height="@dimen/mapping_anim_size" | ||
| 23 | android:layout_marginStart="48dp" | ||
| 24 | tools:src="@drawable/button_anim" /> | ||
| 25 | |||
| 26 | </LinearLayout> | ||
diff --git a/src/android/app/src/main/res/layout/fragment_game_properties.xml b/src/android/app/src/main/res/layout/fragment_game_properties.xml index 436ebd79d..5e3f3cf28 100644 --- a/src/android/app/src/main/res/layout/fragment_game_properties.xml +++ b/src/android/app/src/main/res/layout/fragment_game_properties.xml | |||
| @@ -76,10 +76,7 @@ | |||
| 76 | android:layout_marginTop="12dp" | 76 | android:layout_marginTop="12dp" |
| 77 | android:layout_marginBottom="12dp" | 77 | android:layout_marginBottom="12dp" |
| 78 | android:layout_marginHorizontal="16dp" | 78 | android:layout_marginHorizontal="16dp" |
| 79 | android:ellipsize="none" | ||
| 80 | android:marqueeRepeatLimit="marquee_forever" | ||
| 81 | android:requiresFadingEdge="horizontal" | 79 | android:requiresFadingEdge="horizontal" |
| 82 | android:singleLine="true" | ||
| 83 | android:textAlignment="center" | 80 | android:textAlignment="center" |
| 84 | tools:text="deko_basic" /> | 81 | tools:text="deko_basic" /> |
| 85 | 82 | ||
diff --git a/src/android/app/src/main/res/layout/list_item_input_profile.xml b/src/android/app/src/main/res/layout/list_item_input_profile.xml new file mode 100644 index 000000000..a08dccf0c --- /dev/null +++ b/src/android/app/src/main/res/layout/list_item_input_profile.xml | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 3 | xmlns:app="http://schemas.android.com/apk/res-auto" | ||
| 4 | xmlns:tools="http://schemas.android.com/tools" | ||
| 5 | android:layout_width="match_parent" | ||
| 6 | android:layout_height="wrap_content" | ||
| 7 | android:focusable="false" | ||
| 8 | android:paddingHorizontal="20dp" | ||
| 9 | android:paddingVertical="16dp"> | ||
| 10 | |||
| 11 | <com.google.android.material.textview.MaterialTextView | ||
| 12 | android:id="@+id/title" | ||
| 13 | style="@style/TextAppearance.Material3.HeadlineMedium" | ||
| 14 | android:layout_width="0dp" | ||
| 15 | android:layout_height="0dp" | ||
| 16 | android:textAlignment="viewStart" | ||
| 17 | android:gravity="start|center_vertical" | ||
| 18 | android:textSize="17sp" | ||
| 19 | android:layout_marginEnd="16dp" | ||
| 20 | app:layout_constraintBottom_toBottomOf="@+id/button_layout" | ||
| 21 | app:layout_constraintEnd_toStartOf="@+id/button_layout" | ||
| 22 | app:layout_constraintStart_toStartOf="parent" | ||
| 23 | app:layout_constraintTop_toTopOf="parent" | ||
| 24 | app:lineHeight="28dp" | ||
| 25 | tools:text="My profile" /> | ||
| 26 | |||
| 27 | <LinearLayout | ||
| 28 | android:id="@+id/button_layout" | ||
| 29 | android:layout_width="wrap_content" | ||
| 30 | android:layout_height="wrap_content" | ||
| 31 | android:gravity="center_vertical" | ||
| 32 | android:orientation="horizontal" | ||
| 33 | app:layout_constraintEnd_toEndOf="parent" | ||
| 34 | app:layout_constraintTop_toTopOf="parent"> | ||
| 35 | |||
| 36 | <Button | ||
| 37 | android:id="@+id/button_new" | ||
| 38 | style="@style/Widget.Material3.Button.IconButton.Filled.Tonal" | ||
| 39 | android:layout_width="wrap_content" | ||
| 40 | android:layout_height="wrap_content" | ||
| 41 | android:contentDescription="@string/create_new_profile" | ||
| 42 | android:tooltipText="@string/create_new_profile" | ||
| 43 | app:icon="@drawable/ic_new_label" /> | ||
| 44 | |||
| 45 | <Button | ||
| 46 | android:id="@+id/button_delete" | ||
| 47 | style="@style/Widget.Material3.Button.IconButton.Filled.Tonal" | ||
| 48 | android:layout_width="wrap_content" | ||
| 49 | android:layout_height="wrap_content" | ||
| 50 | android:contentDescription="@string/delete" | ||
| 51 | android:tooltipText="@string/delete" | ||
| 52 | app:icon="@drawable/ic_delete" /> | ||
| 53 | |||
| 54 | <Button | ||
| 55 | android:id="@+id/button_save" | ||
| 56 | style="@style/Widget.Material3.Button.IconButton.Filled.Tonal" | ||
| 57 | android:layout_width="wrap_content" | ||
| 58 | android:layout_height="wrap_content" | ||
| 59 | android:contentDescription="@string/save" | ||
| 60 | android:tooltipText="@string/save" | ||
| 61 | app:icon="@drawable/ic_save" /> | ||
| 62 | |||
| 63 | <Button | ||
| 64 | android:id="@+id/button_load" | ||
| 65 | style="@style/Widget.Material3.Button.IconButton.Filled.Tonal" | ||
| 66 | android:layout_width="wrap_content" | ||
| 67 | android:layout_height="wrap_content" | ||
| 68 | android:contentDescription="@string/load" | ||
| 69 | android:tooltipText="@string/load" | ||
| 70 | app:icon="@drawable/ic_import" /> | ||
| 71 | |||
| 72 | </LinearLayout> | ||
| 73 | |||
| 74 | </androidx.constraintlayout.widget.ConstraintLayout> | ||
diff --git a/src/android/app/src/main/res/layout/list_item_setting_input.xml b/src/android/app/src/main/res/layout/list_item_setting_input.xml new file mode 100644 index 000000000..d67cbe245 --- /dev/null +++ b/src/android/app/src/main/res/layout/list_item_setting_input.xml | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 3 | xmlns:app="http://schemas.android.com/apk/res-auto" | ||
| 4 | xmlns:tools="http://schemas.android.com/tools" | ||
| 5 | android:id="@+id/setting_body" | ||
| 6 | android:layout_width="match_parent" | ||
| 7 | android:layout_height="wrap_content" | ||
| 8 | android:background="?android:attr/selectableItemBackground" | ||
| 9 | android:clickable="true" | ||
| 10 | android:focusable="true" | ||
| 11 | android:gravity="center_vertical" | ||
| 12 | android:minHeight="72dp" | ||
| 13 | android:padding="16dp" | ||
| 14 | android:nextFocusRight="@id/button_options"> | ||
| 15 | |||
| 16 | <LinearLayout | ||
| 17 | android:layout_width="match_parent" | ||
| 18 | android:layout_height="wrap_content" | ||
| 19 | android:gravity="center_vertical" | ||
| 20 | android:orientation="horizontal"> | ||
| 21 | |||
| 22 | <LinearLayout | ||
| 23 | android:layout_width="0dp" | ||
| 24 | android:layout_height="wrap_content" | ||
| 25 | android:orientation="vertical" | ||
| 26 | android:layout_weight="1"> | ||
| 27 | |||
| 28 | <com.google.android.material.textview.MaterialTextView | ||
| 29 | android:id="@+id/text_setting_name" | ||
| 30 | style="@style/TextAppearance.Material3.HeadlineMedium" | ||
| 31 | android:layout_width="match_parent" | ||
| 32 | android:layout_height="wrap_content" | ||
| 33 | android:textAlignment="viewStart" | ||
| 34 | android:textSize="17sp" | ||
| 35 | app:lineHeight="22dp" | ||
| 36 | tools:text="Setting Name" /> | ||
| 37 | |||
| 38 | <com.google.android.material.textview.MaterialTextView | ||
| 39 | android:id="@+id/text_setting_value" | ||
| 40 | style="@style/TextAppearance.Material3.LabelMedium" | ||
| 41 | android:layout_width="match_parent" | ||
| 42 | android:layout_height="wrap_content" | ||
| 43 | android:layout_marginTop="@dimen/spacing_small" | ||
| 44 | android:textAlignment="viewStart" | ||
| 45 | android:textStyle="bold" | ||
| 46 | android:textSize="13sp" | ||
| 47 | tools:text="1x" /> | ||
| 48 | |||
| 49 | </LinearLayout> | ||
| 50 | |||
| 51 | <Button | ||
| 52 | android:id="@+id/button_options" | ||
| 53 | style="?attr/materialIconButtonStyle" | ||
| 54 | android:layout_width="wrap_content" | ||
| 55 | android:layout_height="wrap_content" | ||
| 56 | android:nextFocusLeft="@id/setting_body" | ||
| 57 | app:icon="@drawable/ic_more_vert" | ||
| 58 | app:iconSize="24dp" | ||
| 59 | app:iconTint="?attr/colorOnSurface" /> | ||
| 60 | |||
| 61 | </LinearLayout> | ||
| 62 | |||
| 63 | </RelativeLayout> | ||
diff --git a/src/android/app/src/main/res/menu/menu_in_game.xml b/src/android/app/src/main/res/menu/menu_in_game.xml index eecb0563b..867197ebc 100644 --- a/src/android/app/src/main/res/menu/menu_in_game.xml +++ b/src/android/app/src/main/res/menu/menu_in_game.xml | |||
| @@ -17,8 +17,13 @@ | |||
| 17 | android:title="@string/per_game_settings" /> | 17 | android:title="@string/per_game_settings" /> |
| 18 | 18 | ||
| 19 | <item | 19 | <item |
| 20 | android:id="@+id/menu_overlay_controls" | 20 | android:id="@+id/menu_controls" |
| 21 | android:icon="@drawable/ic_controller" | 21 | android:icon="@drawable/ic_controller" |
| 22 | android:title="@string/preferences_controls" /> | ||
| 23 | |||
| 24 | <item | ||
| 25 | android:id="@+id/menu_overlay_controls" | ||
| 26 | android:icon="@drawable/ic_overlay" | ||
| 22 | android:title="@string/emulation_input_overlay" /> | 27 | android:title="@string/emulation_input_overlay" /> |
| 23 | 28 | ||
| 24 | <item | 29 | <item |
diff --git a/src/android/app/src/main/res/menu/menu_input_options.xml b/src/android/app/src/main/res/menu/menu_input_options.xml new file mode 100644 index 000000000..81ea5043f --- /dev/null +++ b/src/android/app/src/main/res/menu/menu_input_options.xml | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <menu xmlns:android="http://schemas.android.com/apk/res/android"> | ||
| 3 | |||
| 4 | <item | ||
| 5 | android:id="@+id/invert_axis" | ||
| 6 | android:title="@string/invert_axis" | ||
| 7 | android:visible="false" /> | ||
| 8 | |||
| 9 | <item | ||
| 10 | android:id="@+id/invert_button" | ||
| 11 | android:title="@string/invert_button" | ||
| 12 | android:visible="false" /> | ||
| 13 | |||
| 14 | <item | ||
| 15 | android:id="@+id/toggle_button" | ||
| 16 | android:title="@string/toggle_button" | ||
| 17 | android:visible="false" /> | ||
| 18 | |||
| 19 | <item | ||
| 20 | android:id="@+id/turbo_button" | ||
| 21 | android:title="@string/turbo_button" | ||
| 22 | android:visible="false" /> | ||
| 23 | |||
| 24 | <item | ||
| 25 | android:id="@+id/set_threshold" | ||
| 26 | android:title="@string/set_threshold" | ||
| 27 | android:visible="false" /> | ||
| 28 | |||
| 29 | <item | ||
| 30 | android:id="@+id/toggle_axis" | ||
| 31 | android:title="@string/toggle_axis" | ||
| 32 | android:visible="false" /> | ||
| 33 | |||
| 34 | </menu> | ||
diff --git a/src/android/app/src/main/res/navigation/settings_navigation.xml b/src/android/app/src/main/res/navigation/settings_navigation.xml index 1d87d36b3..e4c66e7d5 100644 --- a/src/android/app/src/main/res/navigation/settings_navigation.xml +++ b/src/android/app/src/main/res/navigation/settings_navigation.xml | |||
| @@ -26,7 +26,7 @@ | |||
| 26 | 26 | ||
| 27 | <fragment | 27 | <fragment |
| 28 | android:id="@+id/settingsSearchFragment" | 28 | android:id="@+id/settingsSearchFragment" |
| 29 | android:name="org.yuzu.yuzu_emu.fragments.SettingsSearchFragment" | 29 | android:name="org.yuzu.yuzu_emu.features.settings.ui.SettingsSearchFragment" |
| 30 | android:label="SettingsSearchFragment" /> | 30 | android:label="SettingsSearchFragment" /> |
| 31 | 31 | ||
| 32 | </navigation> | 32 | </navigation> |
diff --git a/src/android/app/src/main/res/values-w600dp/dimens.xml b/src/android/app/src/main/res/values-w600dp/dimens.xml index 128319e27..0e2d40876 100644 --- a/src/android/app/src/main/res/values-w600dp/dimens.xml +++ b/src/android/app/src/main/res/values-w600dp/dimens.xml | |||
| @@ -2,4 +2,6 @@ | |||
| 2 | <resources> | 2 | <resources> |
| 3 | <dimen name="spacing_navigation">0dp</dimen> | 3 | <dimen name="spacing_navigation">0dp</dimen> |
| 4 | <dimen name="spacing_navigation_rail">80dp</dimen> | 4 | <dimen name="spacing_navigation_rail">80dp</dimen> |
| 5 | |||
| 6 | <dimen name="mapping_anim_size">100dp</dimen> | ||
| 5 | </resources> | 7 | </resources> |
diff --git a/src/android/app/src/main/res/values/dimens.xml b/src/android/app/src/main/res/values/dimens.xml index 992b5ae44..bf733637f 100644 --- a/src/android/app/src/main/res/values/dimens.xml +++ b/src/android/app/src/main/res/values/dimens.xml | |||
| @@ -18,4 +18,6 @@ | |||
| 18 | 18 | ||
| 19 | <dimen name="dialog_margin">20dp</dimen> | 19 | <dimen name="dialog_margin">20dp</dimen> |
| 20 | <dimen name="elevated_app_bar">3dp</dimen> | 20 | <dimen name="elevated_app_bar">3dp</dimen> |
| 21 | |||
| 22 | <dimen name="mapping_anim_size">75dp</dimen> | ||
| 21 | </resources> | 23 | </resources> |
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 78a4c958a..6a631f664 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml | |||
| @@ -255,6 +255,92 @@ | |||
| 255 | <string name="audio_volume">Volume</string> | 255 | <string name="audio_volume">Volume</string> |
| 256 | <string name="audio_volume_description">Specifies the volume of audio output.</string> | 256 | <string name="audio_volume_description">Specifies the volume of audio output.</string> |
| 257 | 257 | ||
| 258 | <!-- Input strings --> | ||
| 259 | <string name="buttons">Buttons</string> | ||
| 260 | <string name="button_a">A</string> | ||
| 261 | <string name="button_b">B</string> | ||
| 262 | <string name="button_x">X</string> | ||
| 263 | <string name="button_y">Y</string> | ||
| 264 | <string name="button_plus">Plus</string> | ||
| 265 | <string name="button_minus">Minus</string> | ||
| 266 | <string name="button_home">Home</string> | ||
| 267 | <string name="button_capture">Capture</string> | ||
| 268 | <string name="start_pause">Start/Pause</string> | ||
| 269 | <string name="dpad">D-Pad</string> | ||
| 270 | <string name="up">Up</string> | ||
| 271 | <string name="down">Down</string> | ||
| 272 | <string name="left">Left</string> | ||
| 273 | <string name="right">Right</string> | ||
| 274 | <string name="left_stick">Left stick</string> | ||
| 275 | <string name="control_stick">Control stick</string> | ||
| 276 | <string name="right_stick">Right stick</string> | ||
| 277 | <string name="c_stick">C-Stick</string> | ||
| 278 | <string name="pressed">Pressed</string> | ||
| 279 | <string name="range">Range</string> | ||
| 280 | <string name="deadzone">Deadzone</string> | ||
| 281 | <string name="modifier">Modifier</string> | ||
| 282 | <string name="modifier_range">Modifier range</string> | ||
| 283 | <string name="triggers">Triggers</string> | ||
| 284 | <string name="button_l">L</string> | ||
| 285 | <string name="button_r">R</string> | ||
| 286 | <string name="button_zl">ZL</string> | ||
| 287 | <string name="button_zr">ZR</string> | ||
| 288 | <string name="button_sl_left">Left SL</string> | ||
| 289 | <string name="button_sr_left">Left SR</string> | ||
| 290 | <string name="button_sl_right">Right SL</string> | ||
| 291 | <string name="button_sr_right">Right SR</string> | ||
| 292 | <string name="button_z">Z</string> | ||
| 293 | <string name="invalid">Invalid</string> | ||
| 294 | <string name="not_set">Not set</string> | ||
| 295 | <string name="unknown">Unknown</string> | ||
| 296 | <string name="qualified_hat">%1$s%2$s%3$sHat %4$s</string> | ||
| 297 | <string name="qualified_button_stick_axis">%1$s%2$s%3$sAxis %4$s</string> | ||
| 298 | <string name="qualified_button">%1$s%2$s%3$sButton %4$s</string> | ||
| 299 | <string name="qualified_axis">Axis %1$s%2$s</string> | ||
| 300 | <string name="unused">Unused</string> | ||
| 301 | <string name="input_prompt">Move or press an input</string> | ||
| 302 | <string name="unsupported_input">Unsupported input type</string> | ||
| 303 | <string name="input_mapping_filter">Input mapping filter</string> | ||
| 304 | <string name="input_mapping_filter_description">Select a device to filter mapping inputs</string> | ||
| 305 | <string name="auto_map">Auto-map a controller</string> | ||
| 306 | <string name="auto_map_description">Select a device to attempt auto-mapping</string> | ||
| 307 | <string name="attempted_auto_map">Attempted auto-map with %1$s</string> | ||
| 308 | <string name="controller_type">Controller type</string> | ||
| 309 | <string name="pro_controller">Pro Controller</string> | ||
| 310 | <string name="handheld">Handheld</string> | ||
| 311 | <string name="dual_joycons">Dual Joycons</string> | ||
| 312 | <string name="left_joycon">Left Joycon</string> | ||
| 313 | <string name="right_joycon">Right Joycon</string> | ||
| 314 | <string name="gamecube_controller">GameCube Controller</string> | ||
| 315 | <string name="invert_axis">Invert axis</string> | ||
| 316 | <string name="invert_button">Invert button</string> | ||
| 317 | <string name="toggle_button">Toggle button</string> | ||
| 318 | <string name="turbo_button">Turbo button</string> | ||
| 319 | <string name="set_threshold">Set threshold</string> | ||
| 320 | <string name="toggle_axis">Toggle axis</string> | ||
| 321 | <string name="connected">Connected</string> | ||
| 322 | <string name="use_system_vibrator">Use system vibrator</string> | ||
| 323 | <string name="input_overlay">Input overlay</string> | ||
| 324 | <string name="vibration">Vibration</string> | ||
| 325 | <string name="vibration_strength">Vibration strength</string> | ||
| 326 | <string name="profile">Profile</string> | ||
| 327 | <string name="create_new_profile">Create new profile</string> | ||
| 328 | <string name="enter_profile_name">Enter profile name</string> | ||
| 329 | <string name="profile_name_already_exists">Profile name already exists</string> | ||
| 330 | <string name="invalid_profile_name">Invalid profile name</string> | ||
| 331 | <string name="use_global_input_configuration">Use global input configuration</string> | ||
| 332 | <string name="player_num_profile">Player %d profile</string> | ||
| 333 | <string name="delete_input_profile">Delete input profile</string> | ||
| 334 | <string name="delete_input_profile_description">Are you sure that you want to delete this profile? This is not recoverable.</string> | ||
| 335 | <string name="stick_map_description">Move a stick left and then up or press a button</string> | ||
| 336 | <string name="button_map_description">Press a button or move a trigger/stick</string> | ||
| 337 | <string name="map_dpad_direction">Map to D-Pad %1$s</string> | ||
| 338 | <string name="map_control">Map to %1$s</string> | ||
| 339 | <string name="failed_to_load_profile">Failed to load profile</string> | ||
| 340 | <string name="failed_to_save_profile">Failed to save profile</string> | ||
| 341 | <string name="reset_mapping">Reset mappings</string> | ||
| 342 | <string name="reset_mapping_description">Are you sure that you want to reset all mappings for this controller to default? This cannot be undone.</string> | ||
| 343 | |||
| 258 | <!-- Miscellaneous --> | 344 | <!-- Miscellaneous --> |
| 259 | <string name="slider_default">Default</string> | 345 | <string name="slider_default">Default</string> |
| 260 | <string name="ini_saved">Saved settings</string> | 346 | <string name="ini_saved">Saved settings</string> |
| @@ -292,6 +378,10 @@ | |||
| 292 | <string name="more_options">More options</string> | 378 | <string name="more_options">More options</string> |
| 293 | <string name="use_global_setting">Use global setting</string> | 379 | <string name="use_global_setting">Use global setting</string> |
| 294 | <string name="operation_completed_successfully">The operation completed successfully</string> | 380 | <string name="operation_completed_successfully">The operation completed successfully</string> |
| 381 | <string name="retry">Retry</string> | ||
| 382 | <string name="confirm">Confirm</string> | ||
| 383 | <string name="load">Load</string> | ||
| 384 | <string name="save">Save</string> | ||
| 295 | 385 | ||
| 296 | <!-- GPU driver installation --> | 386 | <!-- GPU driver installation --> |
| 297 | <string name="select_gpu_driver">Select GPU driver</string> | 387 | <string name="select_gpu_driver">Select GPU driver</string> |
| @@ -313,6 +403,9 @@ | |||
| 313 | <string name="preferences_graphics_description">Accuracy level, resolution, shader cache</string> | 403 | <string name="preferences_graphics_description">Accuracy level, resolution, shader cache</string> |
| 314 | <string name="preferences_audio">Audio</string> | 404 | <string name="preferences_audio">Audio</string> |
| 315 | <string name="preferences_audio_description">Output engine, volume</string> | 405 | <string name="preferences_audio_description">Output engine, volume</string> |
| 406 | <string name="preferences_controls">Controls</string> | ||
| 407 | <string name="preferences_controls_description">Map controller input</string> | ||
| 408 | <string name="preferences_player">Player %d</string> | ||
| 316 | <string name="preferences_theme">Theme and color</string> | 409 | <string name="preferences_theme">Theme and color</string> |
| 317 | <string name="preferences_debug">Debug</string> | 410 | <string name="preferences_debug">Debug</string> |
| 318 | <string name="preferences_debug_description">CPU/GPU debugging, graphics API, fastmem</string> | 411 | <string name="preferences_debug_description">CPU/GPU debugging, graphics API, fastmem</string> |
diff --git a/src/audio_core/sink/cubeb_sink.cpp b/src/audio_core/sink/cubeb_sink.cpp index d97ca2a40..49efae8e3 100644 --- a/src/audio_core/sink/cubeb_sink.cpp +++ b/src/audio_core/sink/cubeb_sink.cpp | |||
| @@ -357,7 +357,9 @@ bool IsCubebSuitable() { | |||
| 357 | return false; | 357 | return false; |
| 358 | } | 358 | } |
| 359 | 359 | ||
| 360 | SCOPE_EXIT({ cubeb_destroy(ctx); }); | 360 | SCOPE_EXIT { |
| 361 | cubeb_destroy(ctx); | ||
| 362 | }; | ||
| 361 | 363 | ||
| 362 | #ifdef _WIN32 | 364 | #ifdef _WIN32 |
| 363 | if (SUCCEEDED(com_init_result)) { | 365 | if (SUCCEEDED(com_init_result)) { |
diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp index c047b0668..0a98eb31e 100644 --- a/src/audio_core/sink/sink_stream.cpp +++ b/src/audio_core/sink/sink_stream.cpp | |||
| @@ -20,10 +20,10 @@ | |||
| 20 | namespace AudioCore::Sink { | 20 | namespace AudioCore::Sink { |
| 21 | 21 | ||
| 22 | void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) { | 22 | void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) { |
| 23 | SCOPE_EXIT({ | 23 | SCOPE_EXIT { |
| 24 | queue.enqueue(buffer); | 24 | queue.enqueue(buffer); |
| 25 | ++queued_buffers; | 25 | ++queued_buffers; |
| 26 | }); | 26 | }; |
| 27 | 27 | ||
| 28 | if (type == StreamType::In) { | 28 | if (type == StreamType::In) { |
| 29 | return; | 29 | return; |
diff --git a/src/common/android/id_cache.cpp b/src/common/android/id_cache.cpp index f39262db9..1145cbdf2 100644 --- a/src/common/android/id_cache.cpp +++ b/src/common/android/id_cache.cpp | |||
| @@ -65,6 +65,30 @@ static jclass s_boolean_class; | |||
| 65 | static jmethodID s_boolean_constructor; | 65 | static jmethodID s_boolean_constructor; |
| 66 | static jfieldID s_boolean_value_field; | 66 | static jfieldID s_boolean_value_field; |
| 67 | 67 | ||
| 68 | static jclass s_player_input_class; | ||
| 69 | static jmethodID s_player_input_constructor; | ||
| 70 | static jfieldID s_player_input_connected_field; | ||
| 71 | static jfieldID s_player_input_buttons_field; | ||
| 72 | static jfieldID s_player_input_analogs_field; | ||
| 73 | static jfieldID s_player_input_motions_field; | ||
| 74 | static jfieldID s_player_input_vibration_enabled_field; | ||
| 75 | static jfieldID s_player_input_vibration_strength_field; | ||
| 76 | static jfieldID s_player_input_body_color_left_field; | ||
| 77 | static jfieldID s_player_input_body_color_right_field; | ||
| 78 | static jfieldID s_player_input_button_color_left_field; | ||
| 79 | static jfieldID s_player_input_button_color_right_field; | ||
| 80 | static jfieldID s_player_input_profile_name_field; | ||
| 81 | static jfieldID s_player_input_use_system_vibrator_field; | ||
| 82 | |||
| 83 | static jclass s_yuzu_input_device_interface; | ||
| 84 | static jmethodID s_yuzu_input_device_get_name; | ||
| 85 | static jmethodID s_yuzu_input_device_get_guid; | ||
| 86 | static jmethodID s_yuzu_input_device_get_port; | ||
| 87 | static jmethodID s_yuzu_input_device_get_supports_vibration; | ||
| 88 | static jmethodID s_yuzu_input_device_vibrate; | ||
| 89 | static jmethodID s_yuzu_input_device_get_axes; | ||
| 90 | static jmethodID s_yuzu_input_device_has_keys; | ||
| 91 | |||
| 68 | static constexpr jint JNI_VERSION = JNI_VERSION_1_6; | 92 | static constexpr jint JNI_VERSION = JNI_VERSION_1_6; |
| 69 | 93 | ||
| 70 | namespace Common::Android { | 94 | namespace Common::Android { |
| @@ -276,6 +300,94 @@ jfieldID GetBooleanValueField() { | |||
| 276 | return s_boolean_value_field; | 300 | return s_boolean_value_field; |
| 277 | } | 301 | } |
| 278 | 302 | ||
| 303 | jclass GetPlayerInputClass() { | ||
| 304 | return s_player_input_class; | ||
| 305 | } | ||
| 306 | |||
| 307 | jmethodID GetPlayerInputConstructor() { | ||
| 308 | return s_player_input_constructor; | ||
| 309 | } | ||
| 310 | |||
| 311 | jfieldID GetPlayerInputConnectedField() { | ||
| 312 | return s_player_input_connected_field; | ||
| 313 | } | ||
| 314 | |||
| 315 | jfieldID GetPlayerInputButtonsField() { | ||
| 316 | return s_player_input_buttons_field; | ||
| 317 | } | ||
| 318 | |||
| 319 | jfieldID GetPlayerInputAnalogsField() { | ||
| 320 | return s_player_input_analogs_field; | ||
| 321 | } | ||
| 322 | |||
| 323 | jfieldID GetPlayerInputMotionsField() { | ||
| 324 | return s_player_input_motions_field; | ||
| 325 | } | ||
| 326 | |||
| 327 | jfieldID GetPlayerInputVibrationEnabledField() { | ||
| 328 | return s_player_input_vibration_enabled_field; | ||
| 329 | } | ||
| 330 | |||
| 331 | jfieldID GetPlayerInputVibrationStrengthField() { | ||
| 332 | return s_player_input_vibration_strength_field; | ||
| 333 | } | ||
| 334 | |||
| 335 | jfieldID GetPlayerInputBodyColorLeftField() { | ||
| 336 | return s_player_input_body_color_left_field; | ||
| 337 | } | ||
| 338 | |||
| 339 | jfieldID GetPlayerInputBodyColorRightField() { | ||
| 340 | return s_player_input_body_color_right_field; | ||
| 341 | } | ||
| 342 | |||
| 343 | jfieldID GetPlayerInputButtonColorLeftField() { | ||
| 344 | return s_player_input_button_color_left_field; | ||
| 345 | } | ||
| 346 | |||
| 347 | jfieldID GetPlayerInputButtonColorRightField() { | ||
| 348 | return s_player_input_button_color_right_field; | ||
| 349 | } | ||
| 350 | |||
| 351 | jfieldID GetPlayerInputProfileNameField() { | ||
| 352 | return s_player_input_profile_name_field; | ||
| 353 | } | ||
| 354 | |||
| 355 | jfieldID GetPlayerInputUseSystemVibratorField() { | ||
| 356 | return s_player_input_use_system_vibrator_field; | ||
| 357 | } | ||
| 358 | |||
| 359 | jclass GetYuzuInputDeviceInterface() { | ||
| 360 | return s_yuzu_input_device_interface; | ||
| 361 | } | ||
| 362 | |||
| 363 | jmethodID GetYuzuDeviceGetName() { | ||
| 364 | return s_yuzu_input_device_get_name; | ||
| 365 | } | ||
| 366 | |||
| 367 | jmethodID GetYuzuDeviceGetGUID() { | ||
| 368 | return s_yuzu_input_device_get_guid; | ||
| 369 | } | ||
| 370 | |||
| 371 | jmethodID GetYuzuDeviceGetPort() { | ||
| 372 | return s_yuzu_input_device_get_port; | ||
| 373 | } | ||
| 374 | |||
| 375 | jmethodID GetYuzuDeviceGetSupportsVibration() { | ||
| 376 | return s_yuzu_input_device_get_supports_vibration; | ||
| 377 | } | ||
| 378 | |||
| 379 | jmethodID GetYuzuDeviceVibrate() { | ||
| 380 | return s_yuzu_input_device_vibrate; | ||
| 381 | } | ||
| 382 | |||
| 383 | jmethodID GetYuzuDeviceGetAxes() { | ||
| 384 | return s_yuzu_input_device_get_axes; | ||
| 385 | } | ||
| 386 | |||
| 387 | jmethodID GetYuzuDeviceHasKeys() { | ||
| 388 | return s_yuzu_input_device_has_keys; | ||
| 389 | } | ||
| 390 | |||
| 279 | #ifdef __cplusplus | 391 | #ifdef __cplusplus |
| 280 | extern "C" { | 392 | extern "C" { |
| 281 | #endif | 393 | #endif |
| @@ -387,6 +499,55 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { | |||
| 387 | s_boolean_value_field = env->GetFieldID(boolean_class, "value", "Z"); | 499 | s_boolean_value_field = env->GetFieldID(boolean_class, "value", "Z"); |
| 388 | env->DeleteLocalRef(boolean_class); | 500 | env->DeleteLocalRef(boolean_class); |
| 389 | 501 | ||
| 502 | const jclass player_input_class = | ||
| 503 | env->FindClass("org/yuzu/yuzu_emu/features/input/model/PlayerInput"); | ||
| 504 | s_player_input_class = reinterpret_cast<jclass>(env->NewGlobalRef(player_input_class)); | ||
| 505 | s_player_input_constructor = env->GetMethodID( | ||
| 506 | player_input_class, "<init>", | ||
| 507 | "(Z[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZIJJJJLjava/lang/String;Z)V"); | ||
| 508 | s_player_input_connected_field = env->GetFieldID(player_input_class, "connected", "Z"); | ||
| 509 | s_player_input_buttons_field = | ||
| 510 | env->GetFieldID(player_input_class, "buttons", "[Ljava/lang/String;"); | ||
| 511 | s_player_input_analogs_field = | ||
| 512 | env->GetFieldID(player_input_class, "analogs", "[Ljava/lang/String;"); | ||
| 513 | s_player_input_motions_field = | ||
| 514 | env->GetFieldID(player_input_class, "motions", "[Ljava/lang/String;"); | ||
| 515 | s_player_input_vibration_enabled_field = | ||
| 516 | env->GetFieldID(player_input_class, "vibrationEnabled", "Z"); | ||
| 517 | s_player_input_vibration_strength_field = | ||
| 518 | env->GetFieldID(player_input_class, "vibrationStrength", "I"); | ||
| 519 | s_player_input_body_color_left_field = | ||
| 520 | env->GetFieldID(player_input_class, "bodyColorLeft", "J"); | ||
| 521 | s_player_input_body_color_right_field = | ||
| 522 | env->GetFieldID(player_input_class, "bodyColorRight", "J"); | ||
| 523 | s_player_input_button_color_left_field = | ||
| 524 | env->GetFieldID(player_input_class, "buttonColorLeft", "J"); | ||
| 525 | s_player_input_button_color_right_field = | ||
| 526 | env->GetFieldID(player_input_class, "buttonColorRight", "J"); | ||
| 527 | s_player_input_profile_name_field = | ||
| 528 | env->GetFieldID(player_input_class, "profileName", "Ljava/lang/String;"); | ||
| 529 | s_player_input_use_system_vibrator_field = | ||
| 530 | env->GetFieldID(player_input_class, "useSystemVibrator", "Z"); | ||
| 531 | env->DeleteLocalRef(player_input_class); | ||
| 532 | |||
| 533 | const jclass yuzu_input_device_interface = | ||
| 534 | env->FindClass("org/yuzu/yuzu_emu/features/input/YuzuInputDevice"); | ||
| 535 | s_yuzu_input_device_interface = | ||
| 536 | reinterpret_cast<jclass>(env->NewGlobalRef(yuzu_input_device_interface)); | ||
| 537 | s_yuzu_input_device_get_name = | ||
| 538 | env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;"); | ||
| 539 | s_yuzu_input_device_get_guid = | ||
| 540 | env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;"); | ||
| 541 | s_yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort", "()I"); | ||
| 542 | s_yuzu_input_device_get_supports_vibration = | ||
| 543 | env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z"); | ||
| 544 | s_yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate", "(F)V"); | ||
| 545 | s_yuzu_input_device_get_axes = | ||
| 546 | env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;"); | ||
| 547 | s_yuzu_input_device_has_keys = | ||
| 548 | env->GetMethodID(yuzu_input_device_interface, "hasKeys", "([I)[Z"); | ||
| 549 | env->DeleteLocalRef(yuzu_input_device_interface); | ||
| 550 | |||
| 390 | // Initialize Android Storage | 551 | // Initialize Android Storage |
| 391 | Common::FS::Android::RegisterCallbacks(env, s_native_library_class); | 552 | Common::FS::Android::RegisterCallbacks(env, s_native_library_class); |
| 392 | 553 | ||
| @@ -416,6 +577,8 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) { | |||
| 416 | env->DeleteGlobalRef(s_double_class); | 577 | env->DeleteGlobalRef(s_double_class); |
| 417 | env->DeleteGlobalRef(s_integer_class); | 578 | env->DeleteGlobalRef(s_integer_class); |
| 418 | env->DeleteGlobalRef(s_boolean_class); | 579 | env->DeleteGlobalRef(s_boolean_class); |
| 580 | env->DeleteGlobalRef(s_player_input_class); | ||
| 581 | env->DeleteGlobalRef(s_yuzu_input_device_interface); | ||
| 419 | 582 | ||
| 420 | // UnInitialize applets | 583 | // UnInitialize applets |
| 421 | SoftwareKeyboard::CleanupJNI(env); | 584 | SoftwareKeyboard::CleanupJNI(env); |
diff --git a/src/common/android/id_cache.h b/src/common/android/id_cache.h index 47802f96c..cd2844dcc 100644 --- a/src/common/android/id_cache.h +++ b/src/common/android/id_cache.h | |||
| @@ -85,4 +85,28 @@ jclass GetBooleanClass(); | |||
| 85 | jmethodID GetBooleanConstructor(); | 85 | jmethodID GetBooleanConstructor(); |
| 86 | jfieldID GetBooleanValueField(); | 86 | jfieldID GetBooleanValueField(); |
| 87 | 87 | ||
| 88 | jclass GetPlayerInputClass(); | ||
| 89 | jmethodID GetPlayerInputConstructor(); | ||
| 90 | jfieldID GetPlayerInputConnectedField(); | ||
| 91 | jfieldID GetPlayerInputButtonsField(); | ||
| 92 | jfieldID GetPlayerInputAnalogsField(); | ||
| 93 | jfieldID GetPlayerInputMotionsField(); | ||
| 94 | jfieldID GetPlayerInputVibrationEnabledField(); | ||
| 95 | jfieldID GetPlayerInputVibrationStrengthField(); | ||
| 96 | jfieldID GetPlayerInputBodyColorLeftField(); | ||
| 97 | jfieldID GetPlayerInputBodyColorRightField(); | ||
| 98 | jfieldID GetPlayerInputButtonColorLeftField(); | ||
| 99 | jfieldID GetPlayerInputButtonColorRightField(); | ||
| 100 | jfieldID GetPlayerInputProfileNameField(); | ||
| 101 | jfieldID GetPlayerInputUseSystemVibratorField(); | ||
| 102 | |||
| 103 | jclass GetYuzuInputDeviceInterface(); | ||
| 104 | jmethodID GetYuzuDeviceGetName(); | ||
| 105 | jmethodID GetYuzuDeviceGetGUID(); | ||
| 106 | jmethodID GetYuzuDeviceGetPort(); | ||
| 107 | jmethodID GetYuzuDeviceGetSupportsVibration(); | ||
| 108 | jmethodID GetYuzuDeviceVibrate(); | ||
| 109 | jmethodID GetYuzuDeviceGetAxes(); | ||
| 110 | jmethodID GetYuzuDeviceHasKeys(); | ||
| 111 | |||
| 88 | } // namespace Common::Android | 112 | } // namespace Common::Android |
diff --git a/src/common/demangle.cpp b/src/common/demangle.cpp index 6e117cb41..b2c9d126a 100644 --- a/src/common/demangle.cpp +++ b/src/common/demangle.cpp | |||
| @@ -20,7 +20,9 @@ std::string DemangleSymbol(const std::string& mangled) { | |||
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | char* demangled = nullptr; | 22 | char* demangled = nullptr; |
| 23 | SCOPE_EXIT({ std::free(demangled); }); | 23 | SCOPE_EXIT { |
| 24 | std::free(demangled); | ||
| 25 | }; | ||
| 24 | 26 | ||
| 25 | if (is_itanium(mangled)) { | 27 | if (is_itanium(mangled)) { |
| 26 | demangled = llvm::itaniumDemangle(mangled.c_str()); | 28 | demangled = llvm::itaniumDemangle(mangled.c_str()); |
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 860c39e6a..e0b5a6a67 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp | |||
| @@ -430,11 +430,11 @@ public: | |||
| 430 | explicit Impl(size_t backing_size_, size_t virtual_size_) | 430 | explicit Impl(size_t backing_size_, size_t virtual_size_) |
| 431 | : backing_size{backing_size_}, virtual_size{virtual_size_} { | 431 | : backing_size{backing_size_}, virtual_size{virtual_size_} { |
| 432 | bool good = false; | 432 | bool good = false; |
| 433 | SCOPE_EXIT({ | 433 | SCOPE_EXIT { |
| 434 | if (!good) { | 434 | if (!good) { |
| 435 | Release(); | 435 | Release(); |
| 436 | } | 436 | } |
| 437 | }); | 437 | }; |
| 438 | 438 | ||
| 439 | long page_size = sysconf(_SC_PAGESIZE); | 439 | long page_size = sysconf(_SC_PAGESIZE); |
| 440 | if (page_size != 0x1000) { | 440 | if (page_size != 0x1000) { |
diff --git a/src/common/page_table.cpp b/src/common/page_table.cpp index 85dc18c11..3205eb7da 100644 --- a/src/common/page_table.cpp +++ b/src/common/page_table.cpp | |||
| @@ -24,10 +24,10 @@ bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* c | |||
| 24 | out_entry->block_size = page_size; | 24 | out_entry->block_size = page_size; |
| 25 | 25 | ||
| 26 | // Regardless of whether the page was mapped, advance on exit. | 26 | // Regardless of whether the page was mapped, advance on exit. |
| 27 | SCOPE_EXIT({ | 27 | SCOPE_EXIT { |
| 28 | context->next_page += 1; | 28 | context->next_page += 1; |
| 29 | context->next_offset += page_size; | 29 | context->next_offset += page_size; |
| 30 | }); | 30 | }; |
| 31 | 31 | ||
| 32 | // Validate that we can read the actual entry. | 32 | // Validate that we can read the actual entry. |
| 33 | const auto page = context->next_page; | 33 | const auto page = context->next_page; |
diff --git a/src/common/scope_exit.h b/src/common/scope_exit.h index e9c789c88..f3e88cde9 100644 --- a/src/common/scope_exit.h +++ b/src/common/scope_exit.h | |||
| @@ -7,29 +7,61 @@ | |||
| 7 | #include "common/common_funcs.h" | 7 | #include "common/common_funcs.h" |
| 8 | 8 | ||
| 9 | namespace detail { | 9 | namespace detail { |
| 10 | template <typename Func> | 10 | template <class F> |
| 11 | struct ScopeExitHelper { | 11 | class ScopeGuard { |
| 12 | explicit ScopeExitHelper(Func&& func_) : func(std::move(func_)) {} | 12 | YUZU_NON_COPYABLE(ScopeGuard); |
| 13 | ~ScopeExitHelper() { | 13 | |
| 14 | private: | ||
| 15 | F f; | ||
| 16 | bool active; | ||
| 17 | |||
| 18 | public: | ||
| 19 | constexpr ScopeGuard(F f_) : f(std::move(f_)), active(true) {} | ||
| 20 | constexpr ~ScopeGuard() { | ||
| 14 | if (active) { | 21 | if (active) { |
| 15 | func(); | 22 | f(); |
| 16 | } | 23 | } |
| 17 | } | 24 | } |
| 18 | 25 | constexpr void Cancel() { | |
| 19 | void Cancel() { | ||
| 20 | active = false; | 26 | active = false; |
| 21 | } | 27 | } |
| 22 | 28 | ||
| 23 | Func func; | 29 | constexpr ScopeGuard(ScopeGuard&& rhs) : f(std::move(rhs.f)), active(rhs.active) { |
| 24 | bool active{true}; | 30 | rhs.Cancel(); |
| 31 | } | ||
| 32 | |||
| 33 | ScopeGuard& operator=(ScopeGuard&& rhs) = delete; | ||
| 25 | }; | 34 | }; |
| 26 | 35 | ||
| 27 | template <typename Func> | 36 | template <class F> |
| 28 | ScopeExitHelper<Func> ScopeExit(Func&& func) { | 37 | constexpr ScopeGuard<F> MakeScopeGuard(F f) { |
| 29 | return ScopeExitHelper<Func>(std::forward<Func>(func)); | 38 | return ScopeGuard<F>(std::move(f)); |
| 30 | } | 39 | } |
| 40 | |||
| 41 | enum class ScopeGuardOnExit {}; | ||
| 42 | |||
| 43 | template <typename F> | ||
| 44 | constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F&& f) { | ||
| 45 | return ScopeGuard<F>(std::forward<F>(f)); | ||
| 46 | } | ||
| 47 | |||
| 31 | } // namespace detail | 48 | } // namespace detail |
| 32 | 49 | ||
| 50 | #define CONCATENATE_IMPL(s1, s2) s1##s2 | ||
| 51 | #define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2) | ||
| 52 | |||
| 53 | #ifdef __COUNTER__ | ||
| 54 | #define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __COUNTER__) | ||
| 55 | #else | ||
| 56 | #define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __LINE__) | ||
| 57 | #endif | ||
| 58 | |||
| 59 | /** | ||
| 60 | * This macro is similar to SCOPE_EXIT, except the object is caller managed. This is intended to be | ||
| 61 | * used when the caller might want to cancel the ScopeExit. | ||
| 62 | */ | ||
| 63 | #define SCOPE_GUARD detail::ScopeGuardOnExit() + [&]() | ||
| 64 | |||
| 33 | /** | 65 | /** |
| 34 | * This macro allows you to conveniently specify a block of code that will run on scope exit. Handy | 66 | * This macro allows you to conveniently specify a block of code that will run on scope exit. Handy |
| 35 | * for doing ad-hoc clean-up tasks in a function with multiple returns. | 67 | * for doing ad-hoc clean-up tasks in a function with multiple returns. |
| @@ -38,7 +70,7 @@ ScopeExitHelper<Func> ScopeExit(Func&& func) { | |||
| 38 | * \code | 70 | * \code |
| 39 | * const int saved_val = g_foo; | 71 | * const int saved_val = g_foo; |
| 40 | * g_foo = 55; | 72 | * g_foo = 55; |
| 41 | * SCOPE_EXIT({ g_foo = saved_val; }); | 73 | * SCOPE_EXIT{ g_foo = saved_val; }; |
| 42 | * | 74 | * |
| 43 | * if (Bar()) { | 75 | * if (Bar()) { |
| 44 | * return 0; | 76 | * return 0; |
| @@ -47,10 +79,4 @@ ScopeExitHelper<Func> ScopeExit(Func&& func) { | |||
| 47 | * } | 79 | * } |
| 48 | * \endcode | 80 | * \endcode |
| 49 | */ | 81 | */ |
| 50 | #define SCOPE_EXIT(body) auto CONCAT2(scope_exit_helper_, __LINE__) = detail::ScopeExit([&]() body) | 82 | #define SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE_) = SCOPE_GUARD |
| 51 | |||
| 52 | /** | ||
| 53 | * This macro is similar to SCOPE_EXIT, except the object is caller managed. This is intended to be | ||
| 54 | * used when the caller might want to cancel the ScopeExit. | ||
| 55 | */ | ||
| 56 | #define SCOPE_GUARD(body) detail::ScopeExit([&]() body) | ||
diff --git a/src/common/settings_input.h b/src/common/settings_input.h index 53a95ef8f..a99bb0892 100644 --- a/src/common/settings_input.h +++ b/src/common/settings_input.h | |||
| @@ -395,6 +395,10 @@ struct PlayerInput { | |||
| 395 | u32 button_color_left; | 395 | u32 button_color_left; |
| 396 | u32 button_color_right; | 396 | u32 button_color_right; |
| 397 | std::string profile_name; | 397 | std::string profile_name; |
| 398 | |||
| 399 | // This is meant to tell the Android frontend whether to use a device's built-in vibration | ||
| 400 | // motor or a controller's vibrations. | ||
| 401 | bool use_system_vibrator; | ||
| 398 | }; | 402 | }; |
| 399 | 403 | ||
| 400 | struct TouchscreenInput { | 404 | struct TouchscreenInput { |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 93c548942..f67a12f8f 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -2,8 +2,8 @@ | |||
| 2 | # SPDX-License-Identifier: GPL-2.0-or-later | 2 | # SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | add_library(core STATIC | 4 | add_library(core STATIC |
| 5 | arm/arm_interface.h | ||
| 6 | arm/arm_interface.cpp | 5 | arm/arm_interface.cpp |
| 6 | arm/arm_interface.h | ||
| 7 | arm/debug.cpp | 7 | arm/debug.cpp |
| 8 | arm/debug.h | 8 | arm/debug.h |
| 9 | arm/exclusive_monitor.cpp | 9 | arm/exclusive_monitor.cpp |
| @@ -37,10 +37,10 @@ add_library(core STATIC | |||
| 37 | debugger/gdbstub.h | 37 | debugger/gdbstub.h |
| 38 | debugger/gdbstub_arch.cpp | 38 | debugger/gdbstub_arch.cpp |
| 39 | debugger/gdbstub_arch.h | 39 | debugger/gdbstub_arch.h |
| 40 | device_memory_manager.h | ||
| 41 | device_memory_manager.inc | ||
| 42 | device_memory.cpp | 40 | device_memory.cpp |
| 43 | device_memory.h | 41 | device_memory.h |
| 42 | device_memory_manager.h | ||
| 43 | device_memory_manager.inc | ||
| 44 | file_sys/bis_factory.cpp | 44 | file_sys/bis_factory.cpp |
| 45 | file_sys/bis_factory.h | 45 | file_sys/bis_factory.h |
| 46 | file_sys/card_image.cpp | 46 | file_sys/card_image.cpp |
| @@ -390,6 +390,20 @@ add_library(core STATIC | |||
| 390 | hle/service/acc/errors.h | 390 | hle/service/acc/errors.h |
| 391 | hle/service/acc/profile_manager.cpp | 391 | hle/service/acc/profile_manager.cpp |
| 392 | hle/service/acc/profile_manager.h | 392 | hle/service/acc/profile_manager.h |
| 393 | hle/service/am/am.cpp | ||
| 394 | hle/service/am/am.h | ||
| 395 | hle/service/am/am_results.h | ||
| 396 | hle/service/am/am_types.h | ||
| 397 | hle/service/am/applet.cpp | ||
| 398 | hle/service/am/applet.h | ||
| 399 | hle/service/am/applet_data_broker.cpp | ||
| 400 | hle/service/am/applet_data_broker.h | ||
| 401 | hle/service/am/applet_manager.cpp | ||
| 402 | hle/service/am/applet_manager.h | ||
| 403 | hle/service/am/applet_message_queue.cpp | ||
| 404 | hle/service/am/applet_message_queue.h | ||
| 405 | hle/service/am/display_layer_manager.cpp | ||
| 406 | hle/service/am/display_layer_manager.h | ||
| 393 | hle/service/am/frontend/applet_cabinet.cpp | 407 | hle/service/am/frontend/applet_cabinet.cpp |
| 394 | hle/service/am/frontend/applet_cabinet.h | 408 | hle/service/am/frontend/applet_cabinet.h |
| 395 | hle/service/am/frontend/applet_controller.cpp | 409 | hle/service/am/frontend/applet_controller.cpp |
| @@ -411,24 +425,10 @@ add_library(core STATIC | |||
| 411 | hle/service/am/frontend/applet_web_browser_types.h | 425 | hle/service/am/frontend/applet_web_browser_types.h |
| 412 | hle/service/am/frontend/applets.cpp | 426 | hle/service/am/frontend/applets.cpp |
| 413 | hle/service/am/frontend/applets.h | 427 | hle/service/am/frontend/applets.h |
| 414 | hle/service/am/am.cpp | ||
| 415 | hle/service/am/am.h | ||
| 416 | hle/service/am/am_results.h | ||
| 417 | hle/service/am/am_types.h | ||
| 418 | hle/service/am/applet.cpp | ||
| 419 | hle/service/am/applet.h | ||
| 420 | hle/service/am/applet_manager.cpp | ||
| 421 | hle/service/am/applet_data_broker.cpp | ||
| 422 | hle/service/am/applet_data_broker.h | ||
| 423 | hle/service/am/applet_manager.h | ||
| 424 | hle/service/am/applet_message_queue.cpp | ||
| 425 | hle/service/am/applet_message_queue.h | ||
| 426 | hle/service/am/hid_registration.cpp | 428 | hle/service/am/hid_registration.cpp |
| 427 | hle/service/am/hid_registration.h | 429 | hle/service/am/hid_registration.h |
| 428 | hle/service/am/library_applet_storage.cpp | 430 | hle/service/am/library_applet_storage.cpp |
| 429 | hle/service/am/library_applet_storage.h | 431 | hle/service/am/library_applet_storage.h |
| 430 | hle/service/am/managed_layer_holder.cpp | ||
| 431 | hle/service/am/managed_layer_holder.h | ||
| 432 | hle/service/am/process.cpp | 432 | hle/service/am/process.cpp |
| 433 | hle/service/am/process.h | 433 | hle/service/am/process.h |
| 434 | hle/service/am/service/all_system_applet_proxies_service.cpp | 434 | hle/service/am/service/all_system_applet_proxies_service.cpp |
| @@ -441,10 +441,10 @@ add_library(core STATIC | |||
| 441 | hle/service/am/service/application_creator.h | 441 | hle/service/am/service/application_creator.h |
| 442 | hle/service/am/service/application_functions.cpp | 442 | hle/service/am/service/application_functions.cpp |
| 443 | hle/service/am/service/application_functions.h | 443 | hle/service/am/service/application_functions.h |
| 444 | hle/service/am/service/application_proxy_service.cpp | ||
| 445 | hle/service/am/service/application_proxy_service.h | ||
| 446 | hle/service/am/service/application_proxy.cpp | 444 | hle/service/am/service/application_proxy.cpp |
| 447 | hle/service/am/service/application_proxy.h | 445 | hle/service/am/service/application_proxy.h |
| 446 | hle/service/am/service/application_proxy_service.cpp | ||
| 447 | hle/service/am/service/application_proxy_service.h | ||
| 448 | hle/service/am/service/audio_controller.cpp | 448 | hle/service/am/service/audio_controller.cpp |
| 449 | hle/service/am/service/audio_controller.h | 449 | hle/service/am/service/audio_controller.h |
| 450 | hle/service/am/service/common_state_getter.cpp | 450 | hle/service/am/service/common_state_getter.cpp |
| @@ -473,16 +473,14 @@ add_library(core STATIC | |||
| 473 | hle/service/am/service/process_winding_controller.h | 473 | hle/service/am/service/process_winding_controller.h |
| 474 | hle/service/am/service/self_controller.cpp | 474 | hle/service/am/service/self_controller.cpp |
| 475 | hle/service/am/service/self_controller.h | 475 | hle/service/am/service/self_controller.h |
| 476 | hle/service/am/service/storage_accessor.cpp | ||
| 477 | hle/service/am/service/storage_accessor.h | ||
| 478 | hle/service/am/service/storage.cpp | 476 | hle/service/am/service/storage.cpp |
| 479 | hle/service/am/service/storage.h | 477 | hle/service/am/service/storage.h |
| 478 | hle/service/am/service/storage_accessor.cpp | ||
| 479 | hle/service/am/service/storage_accessor.h | ||
| 480 | hle/service/am/service/system_applet_proxy.cpp | 480 | hle/service/am/service/system_applet_proxy.cpp |
| 481 | hle/service/am/service/system_applet_proxy.h | 481 | hle/service/am/service/system_applet_proxy.h |
| 482 | hle/service/am/service/window_controller.cpp | 482 | hle/service/am/service/window_controller.cpp |
| 483 | hle/service/am/service/window_controller.h | 483 | hle/service/am/service/window_controller.h |
| 484 | hle/service/am/system_buffer_manager.cpp | ||
| 485 | hle/service/am/system_buffer_manager.h | ||
| 486 | hle/service/aoc/aoc_u.cpp | 484 | hle/service/aoc/aoc_u.cpp |
| 487 | hle/service/aoc/aoc_u.h | 485 | hle/service/aoc/aoc_u.h |
| 488 | hle/service/apm/apm.cpp | 486 | hle/service/apm/apm.cpp |
| @@ -491,12 +489,12 @@ add_library(core STATIC | |||
| 491 | hle/service/apm/apm_controller.h | 489 | hle/service/apm/apm_controller.h |
| 492 | hle/service/apm/apm_interface.cpp | 490 | hle/service/apm/apm_interface.cpp |
| 493 | hle/service/apm/apm_interface.h | 491 | hle/service/apm/apm_interface.h |
| 494 | hle/service/audio/audctl.cpp | ||
| 495 | hle/service/audio/audctl.h | ||
| 496 | hle/service/audio/audin_u.cpp | 492 | hle/service/audio/audin_u.cpp |
| 497 | hle/service/audio/audin_u.h | 493 | hle/service/audio/audin_u.h |
| 498 | hle/service/audio/audio.cpp | 494 | hle/service/audio/audio.cpp |
| 499 | hle/service/audio/audio.h | 495 | hle/service/audio/audio.h |
| 496 | hle/service/audio/audio_controller.cpp | ||
| 497 | hle/service/audio/audio_controller.h | ||
| 500 | hle/service/audio/audout_u.cpp | 498 | hle/service/audio/audout_u.cpp |
| 501 | hle/service/audio/audout_u.h | 499 | hle/service/audio/audout_u.h |
| 502 | hle/service/audio/audrec_a.cpp | 500 | hle/service/audio/audrec_a.cpp |
| @@ -510,18 +508,6 @@ add_library(core STATIC | |||
| 510 | hle/service/audio/hwopus.h | 508 | hle/service/audio/hwopus.h |
| 511 | hle/service/bcat/backend/backend.cpp | 509 | hle/service/bcat/backend/backend.cpp |
| 512 | hle/service/bcat/backend/backend.h | 510 | hle/service/bcat/backend/backend.h |
| 513 | hle/service/bcat/news/newly_arrived_event_holder.cpp | ||
| 514 | hle/service/bcat/news/newly_arrived_event_holder.h | ||
| 515 | hle/service/bcat/news/news_data_service.cpp | ||
| 516 | hle/service/bcat/news/news_data_service.h | ||
| 517 | hle/service/bcat/news/news_database_service.cpp | ||
| 518 | hle/service/bcat/news/news_database_service.h | ||
| 519 | hle/service/bcat/news/news_service.cpp | ||
| 520 | hle/service/bcat/news/news_service.h | ||
| 521 | hle/service/bcat/news/overwrite_event_holder.cpp | ||
| 522 | hle/service/bcat/news/overwrite_event_holder.h | ||
| 523 | hle/service/bcat/news/service_creator.cpp | ||
| 524 | hle/service/bcat/news/service_creator.h | ||
| 525 | hle/service/bcat/bcat.cpp | 511 | hle/service/bcat/bcat.cpp |
| 526 | hle/service/bcat/bcat.h | 512 | hle/service/bcat/bcat.h |
| 527 | hle/service/bcat/bcat_result.h | 513 | hle/service/bcat/bcat_result.h |
| @@ -537,6 +523,18 @@ add_library(core STATIC | |||
| 537 | hle/service/bcat/delivery_cache_progress_service.h | 523 | hle/service/bcat/delivery_cache_progress_service.h |
| 538 | hle/service/bcat/delivery_cache_storage_service.cpp | 524 | hle/service/bcat/delivery_cache_storage_service.cpp |
| 539 | hle/service/bcat/delivery_cache_storage_service.h | 525 | hle/service/bcat/delivery_cache_storage_service.h |
| 526 | hle/service/bcat/news/newly_arrived_event_holder.cpp | ||
| 527 | hle/service/bcat/news/newly_arrived_event_holder.h | ||
| 528 | hle/service/bcat/news/news_data_service.cpp | ||
| 529 | hle/service/bcat/news/news_data_service.h | ||
| 530 | hle/service/bcat/news/news_database_service.cpp | ||
| 531 | hle/service/bcat/news/news_database_service.h | ||
| 532 | hle/service/bcat/news/news_service.cpp | ||
| 533 | hle/service/bcat/news/news_service.h | ||
| 534 | hle/service/bcat/news/overwrite_event_holder.cpp | ||
| 535 | hle/service/bcat/news/overwrite_event_holder.h | ||
| 536 | hle/service/bcat/news/service_creator.cpp | ||
| 537 | hle/service/bcat/news/service_creator.h | ||
| 540 | hle/service/bcat/service_creator.cpp | 538 | hle/service/bcat/service_creator.cpp |
| 541 | hle/service/bcat/service_creator.h | 539 | hle/service/bcat/service_creator.h |
| 542 | hle/service/bpc/bpc.cpp | 540 | hle/service/bpc/bpc.cpp |
| @@ -610,8 +608,6 @@ add_library(core STATIC | |||
| 610 | hle/service/filesystem/romfs_controller.h | 608 | hle/service/filesystem/romfs_controller.h |
| 611 | hle/service/filesystem/save_data_controller.cpp | 609 | hle/service/filesystem/save_data_controller.cpp |
| 612 | hle/service/filesystem/save_data_controller.h | 610 | hle/service/filesystem/save_data_controller.h |
| 613 | hle/service/fgm/fgm.cpp | ||
| 614 | hle/service/fgm/fgm.h | ||
| 615 | hle/service/friend/friend.cpp | 611 | hle/service/friend/friend.cpp |
| 616 | hle/service/friend/friend.h | 612 | hle/service/friend/friend.h |
| 617 | hle/service/friend/friend_interface.cpp | 613 | hle/service/friend/friend_interface.cpp |
| @@ -749,15 +745,48 @@ add_library(core STATIC | |||
| 749 | hle/service/nim/nim.h | 745 | hle/service/nim/nim.h |
| 750 | hle/service/npns/npns.cpp | 746 | hle/service/npns/npns.cpp |
| 751 | hle/service/npns/npns.h | 747 | hle/service/npns/npns.h |
| 752 | hle/service/ns/errors.h | 748 | hle/service/ns/account_proxy_interface.cpp |
| 753 | hle/service/ns/iplatform_service_manager.cpp | 749 | hle/service/ns/account_proxy_interface.h |
| 754 | hle/service/ns/iplatform_service_manager.h | 750 | hle/service/ns/application_manager_interface.cpp |
| 751 | hle/service/ns/application_manager_interface.h | ||
| 752 | hle/service/ns/application_version_interface.cpp | ||
| 753 | hle/service/ns/application_version_interface.h | ||
| 754 | hle/service/ns/content_management_interface.cpp | ||
| 755 | hle/service/ns/content_management_interface.h | ||
| 756 | hle/service/ns/develop_interface.cpp | ||
| 757 | hle/service/ns/develop_interface.h | ||
| 758 | hle/service/ns/document_interface.cpp | ||
| 759 | hle/service/ns/document_interface.h | ||
| 760 | hle/service/ns/download_task_interface.cpp | ||
| 761 | hle/service/ns/download_task_interface.h | ||
| 762 | hle/service/ns/dynamic_rights_interface.cpp | ||
| 763 | hle/service/ns/dynamic_rights_interface.h | ||
| 764 | hle/service/ns/ecommerce_interface.cpp | ||
| 765 | hle/service/ns/ecommerce_interface.h | ||
| 766 | hle/service/ns/factory_reset_interface.cpp | ||
| 767 | hle/service/ns/factory_reset_interface.h | ||
| 755 | hle/service/ns/language.cpp | 768 | hle/service/ns/language.cpp |
| 756 | hle/service/ns/language.h | 769 | hle/service/ns/language.h |
| 757 | hle/service/ns/ns.cpp | 770 | hle/service/ns/ns.cpp |
| 758 | hle/service/ns/ns.h | 771 | hle/service/ns/ns.h |
| 759 | hle/service/ns/pdm_qry.cpp | 772 | hle/service/ns/ns_results.h |
| 760 | hle/service/ns/pdm_qry.h | 773 | hle/service/ns/ns_types.h |
| 774 | hle/service/ns/platform_service_manager.cpp | ||
| 775 | hle/service/ns/platform_service_manager.h | ||
| 776 | hle/service/ns/query_service.cpp | ||
| 777 | hle/service/ns/query_service.h | ||
| 778 | hle/service/ns/read_only_application_control_data_interface.cpp | ||
| 779 | hle/service/ns/read_only_application_control_data_interface.h | ||
| 780 | hle/service/ns/read_only_application_record_interface.cpp | ||
| 781 | hle/service/ns/read_only_application_record_interface.h | ||
| 782 | hle/service/ns/service_getter_interface.cpp | ||
| 783 | hle/service/ns/service_getter_interface.h | ||
| 784 | hle/service/ns/system_update_control.cpp | ||
| 785 | hle/service/ns/system_update_control.h | ||
| 786 | hle/service/ns/system_update_interface.cpp | ||
| 787 | hle/service/ns/system_update_interface.h | ||
| 788 | hle/service/ns/vulnerability_manager_interface.cpp | ||
| 789 | hle/service/ns/vulnerability_manager_interface.h | ||
| 761 | hle/service/nvdrv/core/container.cpp | 790 | hle/service/nvdrv/core/container.cpp |
| 762 | hle/service/nvdrv/core/container.h | 791 | hle/service/nvdrv/core/container.h |
| 763 | hle/service/nvdrv/core/heap_mapper.cpp | 792 | hle/service/nvdrv/core/heap_mapper.cpp |
| @@ -810,14 +839,14 @@ add_library(core STATIC | |||
| 810 | hle/service/nvnflinger/consumer_base.cpp | 839 | hle/service/nvnflinger/consumer_base.cpp |
| 811 | hle/service/nvnflinger/consumer_base.h | 840 | hle/service/nvnflinger/consumer_base.h |
| 812 | hle/service/nvnflinger/consumer_listener.h | 841 | hle/service/nvnflinger/consumer_listener.h |
| 813 | hle/service/nvnflinger/fb_share_buffer_manager.cpp | ||
| 814 | hle/service/nvnflinger/fb_share_buffer_manager.h | ||
| 815 | hle/service/nvnflinger/graphic_buffer_producer.cpp | 842 | hle/service/nvnflinger/graphic_buffer_producer.cpp |
| 816 | hle/service/nvnflinger/graphic_buffer_producer.h | 843 | hle/service/nvnflinger/graphic_buffer_producer.h |
| 817 | hle/service/nvnflinger/hos_binder_driver_server.cpp | ||
| 818 | hle/service/nvnflinger/hos_binder_driver_server.h | ||
| 819 | hle/service/nvnflinger/hardware_composer.cpp | 844 | hle/service/nvnflinger/hardware_composer.cpp |
| 820 | hle/service/nvnflinger/hardware_composer.h | 845 | hle/service/nvnflinger/hardware_composer.h |
| 846 | hle/service/nvnflinger/hos_binder_driver.cpp | ||
| 847 | hle/service/nvnflinger/hos_binder_driver.h | ||
| 848 | hle/service/nvnflinger/hos_binder_driver_server.cpp | ||
| 849 | hle/service/nvnflinger/hos_binder_driver_server.h | ||
| 821 | hle/service/nvnflinger/hwc_layer.h | 850 | hle/service/nvnflinger/hwc_layer.h |
| 822 | hle/service/nvnflinger/nvnflinger.cpp | 851 | hle/service/nvnflinger/nvnflinger.cpp |
| 823 | hle/service/nvnflinger/nvnflinger.h | 852 | hle/service/nvnflinger/nvnflinger.h |
| @@ -825,6 +854,8 @@ add_library(core STATIC | |||
| 825 | hle/service/nvnflinger/pixel_format.h | 854 | hle/service/nvnflinger/pixel_format.h |
| 826 | hle/service/nvnflinger/producer_listener.h | 855 | hle/service/nvnflinger/producer_listener.h |
| 827 | hle/service/nvnflinger/status.h | 856 | hle/service/nvnflinger/status.h |
| 857 | hle/service/nvnflinger/surface_flinger.cpp | ||
| 858 | hle/service/nvnflinger/surface_flinger.h | ||
| 828 | hle/service/nvnflinger/ui/fence.h | 859 | hle/service/nvnflinger/ui/fence.h |
| 829 | hle/service/nvnflinger/ui/graphic_buffer.cpp | 860 | hle/service/nvnflinger/ui/graphic_buffer.cpp |
| 830 | hle/service/nvnflinger/ui/graphic_buffer.h | 861 | hle/service/nvnflinger/ui/graphic_buffer.h |
| @@ -841,11 +872,11 @@ add_library(core STATIC | |||
| 841 | hle/service/omm/power_state_interface.h | 872 | hle/service/omm/power_state_interface.h |
| 842 | hle/service/os/event.cpp | 873 | hle/service/os/event.cpp |
| 843 | hle/service/os/event.h | 874 | hle/service/os/event.h |
| 875 | hle/service/os/multi_wait.cpp | ||
| 876 | hle/service/os/multi_wait.h | ||
| 844 | hle/service/os/multi_wait_holder.cpp | 877 | hle/service/os/multi_wait_holder.cpp |
| 845 | hle/service/os/multi_wait_holder.h | 878 | hle/service/os/multi_wait_holder.h |
| 846 | hle/service/os/multi_wait_utils.h | 879 | hle/service/os/multi_wait_utils.h |
| 847 | hle/service/os/multi_wait.cpp | ||
| 848 | hle/service/os/multi_wait.h | ||
| 849 | hle/service/os/mutex.cpp | 880 | hle/service/os/mutex.cpp |
| 850 | hle/service/os/mutex.h | 881 | hle/service/os/mutex.h |
| 851 | hle/service/pcie/pcie.cpp | 882 | hle/service/pcie/pcie.cpp |
| @@ -883,15 +914,17 @@ add_library(core STATIC | |||
| 883 | hle/service/psc/time/common.cpp | 914 | hle/service/psc/time/common.cpp |
| 884 | hle/service/psc/time/common.h | 915 | hle/service/psc/time/common.h |
| 885 | hle/service/psc/time/errors.h | 916 | hle/service/psc/time/errors.h |
| 886 | hle/service/psc/time/shared_memory.cpp | ||
| 887 | hle/service/psc/time/shared_memory.h | ||
| 888 | hle/service/psc/time/static.cpp | ||
| 889 | hle/service/psc/time/static.h | ||
| 890 | hle/service/psc/time/manager.h | 917 | hle/service/psc/time/manager.h |
| 918 | hle/service/psc/time/power_state_request_manager.cpp | ||
| 919 | hle/service/psc/time/power_state_request_manager.h | ||
| 891 | hle/service/psc/time/power_state_service.cpp | 920 | hle/service/psc/time/power_state_service.cpp |
| 892 | hle/service/psc/time/power_state_service.h | 921 | hle/service/psc/time/power_state_service.h |
| 893 | hle/service/psc/time/service_manager.cpp | 922 | hle/service/psc/time/service_manager.cpp |
| 894 | hle/service/psc/time/service_manager.h | 923 | hle/service/psc/time/service_manager.h |
| 924 | hle/service/psc/time/shared_memory.cpp | ||
| 925 | hle/service/psc/time/shared_memory.h | ||
| 926 | hle/service/psc/time/static.cpp | ||
| 927 | hle/service/psc/time/static.h | ||
| 895 | hle/service/psc/time/steady_clock.cpp | 928 | hle/service/psc/time/steady_clock.cpp |
| 896 | hle/service/psc/time/steady_clock.h | 929 | hle/service/psc/time/steady_clock.h |
| 897 | hle/service/psc/time/system_clock.cpp | 930 | hle/service/psc/time/system_clock.cpp |
| @@ -900,8 +933,6 @@ add_library(core STATIC | |||
| 900 | hle/service/psc/time/time_zone.h | 933 | hle/service/psc/time/time_zone.h |
| 901 | hle/service/psc/time/time_zone_service.cpp | 934 | hle/service/psc/time/time_zone_service.cpp |
| 902 | hle/service/psc/time/time_zone_service.h | 935 | hle/service/psc/time/time_zone_service.h |
| 903 | hle/service/psc/time/power_state_request_manager.cpp | ||
| 904 | hle/service/psc/time/power_state_request_manager.h | ||
| 905 | hle/service/ptm/psm.cpp | 936 | hle/service/ptm/psm.cpp |
| 906 | hle/service/ptm/psm.h | 937 | hle/service/ptm/psm.h |
| 907 | hle/service/ptm/ptm.cpp | 938 | hle/service/ptm/ptm.cpp |
| @@ -918,19 +949,21 @@ add_library(core STATIC | |||
| 918 | hle/service/server_manager.h | 949 | hle/service/server_manager.h |
| 919 | hle/service/service.cpp | 950 | hle/service/service.cpp |
| 920 | hle/service/service.h | 951 | hle/service/service.h |
| 952 | hle/service/services.cpp | ||
| 953 | hle/service/services.h | ||
| 954 | hle/service/set/factory_settings_server.cpp | ||
| 955 | hle/service/set/factory_settings_server.h | ||
| 956 | hle/service/set/firmware_debug_settings_server.cpp | ||
| 957 | hle/service/set/firmware_debug_settings_server.h | ||
| 958 | hle/service/set/key_code_map.h | ||
| 921 | hle/service/set/setting_formats/appln_settings.cpp | 959 | hle/service/set/setting_formats/appln_settings.cpp |
| 922 | hle/service/set/setting_formats/appln_settings.h | 960 | hle/service/set/setting_formats/appln_settings.h |
| 923 | hle/service/set/setting_formats/device_settings.cpp | 961 | hle/service/set/setting_formats/device_settings.cpp |
| 924 | hle/service/set/setting_formats/device_settings.h | 962 | hle/service/set/setting_formats/device_settings.h |
| 925 | hle/service/set/setting_formats/system_settings.cpp | ||
| 926 | hle/service/set/setting_formats/system_settings.h | ||
| 927 | hle/service/set/setting_formats/private_settings.cpp | 963 | hle/service/set/setting_formats/private_settings.cpp |
| 928 | hle/service/set/setting_formats/private_settings.h | 964 | hle/service/set/setting_formats/private_settings.h |
| 929 | hle/service/set/factory_settings_server.cpp | 965 | hle/service/set/setting_formats/system_settings.cpp |
| 930 | hle/service/set/factory_settings_server.h | 966 | hle/service/set/setting_formats/system_settings.h |
| 931 | hle/service/set/firmware_debug_settings_server.cpp | ||
| 932 | hle/service/set/firmware_debug_settings_server.h | ||
| 933 | hle/service/set/key_code_map.h | ||
| 934 | hle/service/set/settings.cpp | 967 | hle/service/set/settings.cpp |
| 935 | hle/service/set/settings.h | 968 | hle/service/set/settings.h |
| 936 | hle/service/set/settings_server.cpp | 969 | hle/service/set/settings_server.cpp |
| @@ -965,30 +998,36 @@ add_library(core STATIC | |||
| 965 | hle/service/ssl/ssl_backend.h | 998 | hle/service/ssl/ssl_backend.h |
| 966 | hle/service/usb/usb.cpp | 999 | hle/service/usb/usb.cpp |
| 967 | hle/service/usb/usb.h | 1000 | hle/service/usb/usb.h |
| 968 | hle/service/vi/display/vi_display.cpp | ||
| 969 | hle/service/vi/display/vi_display.h | ||
| 970 | hle/service/vi/layer/vi_layer.cpp | ||
| 971 | hle/service/vi/layer/vi_layer.h | ||
| 972 | hle/service/vi/application_display_service.cpp | 1001 | hle/service/vi/application_display_service.cpp |
| 973 | hle/service/vi/application_display_service.h | 1002 | hle/service/vi/application_display_service.h |
| 974 | hle/service/vi/application_root_service.cpp | 1003 | hle/service/vi/application_root_service.cpp |
| 975 | hle/service/vi/application_root_service.h | 1004 | hle/service/vi/application_root_service.h |
| 976 | hle/service/vi/hos_binder_driver.cpp | 1005 | hle/service/vi/conductor.cpp |
| 977 | hle/service/vi/hos_binder_driver.h | 1006 | hle/service/vi/conductor.h |
| 1007 | hle/service/vi/container.cpp | ||
| 1008 | hle/service/vi/container.h | ||
| 1009 | hle/service/vi/display.h | ||
| 1010 | hle/service/vi/display_list.h | ||
| 1011 | hle/service/vi/layer.h | ||
| 1012 | hle/service/vi/layer_list.h | ||
| 978 | hle/service/vi/manager_display_service.cpp | 1013 | hle/service/vi/manager_display_service.cpp |
| 979 | hle/service/vi/manager_display_service.h | 1014 | hle/service/vi/manager_display_service.h |
| 980 | hle/service/vi/manager_root_service.cpp | 1015 | hle/service/vi/manager_root_service.cpp |
| 981 | hle/service/vi/manager_root_service.h | 1016 | hle/service/vi/manager_root_service.h |
| 982 | hle/service/vi/service_creator.cpp | 1017 | hle/service/vi/service_creator.cpp |
| 983 | hle/service/vi/service_creator.h | 1018 | hle/service/vi/service_creator.h |
| 1019 | hle/service/vi/shared_buffer_manager.cpp | ||
| 1020 | hle/service/vi/shared_buffer_manager.h | ||
| 984 | hle/service/vi/system_display_service.cpp | 1021 | hle/service/vi/system_display_service.cpp |
| 985 | hle/service/vi/system_display_service.h | 1022 | hle/service/vi/system_display_service.h |
| 986 | hle/service/vi/system_root_service.cpp | 1023 | hle/service/vi/system_root_service.cpp |
| 987 | hle/service/vi/system_root_service.h | 1024 | hle/service/vi/system_root_service.h |
| 988 | hle/service/vi/vi_results.h | ||
| 989 | hle/service/vi/vi_types.h | ||
| 990 | hle/service/vi/vi.cpp | 1025 | hle/service/vi/vi.cpp |
| 991 | hle/service/vi/vi.h | 1026 | hle/service/vi/vi.h |
| 1027 | hle/service/vi/vi_results.h | ||
| 1028 | hle/service/vi/vi_types.h | ||
| 1029 | hle/service/vi/vsync_manager.cpp | ||
| 1030 | hle/service/vi/vsync_manager.h | ||
| 992 | internal_network/network.cpp | 1031 | internal_network/network.cpp |
| 993 | internal_network/network.h | 1032 | internal_network/network.h |
| 994 | internal_network/network_interface.cpp | 1033 | internal_network/network_interface.cpp |
diff --git a/src/core/core.cpp b/src/core/core.cpp index 435ef6793..9e8936728 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -47,6 +47,7 @@ | |||
| 47 | #include "core/hle/service/psc/time/system_clock.h" | 47 | #include "core/hle/service/psc/time/system_clock.h" |
| 48 | #include "core/hle/service/psc/time/time_zone_service.h" | 48 | #include "core/hle/service/psc/time/time_zone_service.h" |
| 49 | #include "core/hle/service/service.h" | 49 | #include "core/hle/service/service.h" |
| 50 | #include "core/hle/service/services.h" | ||
| 50 | #include "core/hle/service/set/system_settings_server.h" | 51 | #include "core/hle/service/set/system_settings_server.h" |
| 51 | #include "core/hle/service/sm/sm.h" | 52 | #include "core/hle/service/sm/sm.h" |
| 52 | #include "core/internal_network/network.h" | 53 | #include "core/internal_network/network.h" |
| @@ -242,7 +243,7 @@ struct System::Impl { | |||
| 242 | void Run() { | 243 | void Run() { |
| 243 | std::unique_lock<std::mutex> lk(suspend_guard); | 244 | std::unique_lock<std::mutex> lk(suspend_guard); |
| 244 | 245 | ||
| 245 | kernel.SuspendApplication(false); | 246 | kernel.SuspendEmulation(false); |
| 246 | core_timing.SyncPause(false); | 247 | core_timing.SyncPause(false); |
| 247 | is_paused.store(false, std::memory_order_relaxed); | 248 | is_paused.store(false, std::memory_order_relaxed); |
| 248 | } | 249 | } |
| @@ -251,7 +252,7 @@ struct System::Impl { | |||
| 251 | std::unique_lock<std::mutex> lk(suspend_guard); | 252 | std::unique_lock<std::mutex> lk(suspend_guard); |
| 252 | 253 | ||
| 253 | core_timing.SyncPause(true); | 254 | core_timing.SyncPause(true); |
| 254 | kernel.SuspendApplication(true); | 255 | kernel.SuspendEmulation(true); |
| 255 | is_paused.store(true, std::memory_order_relaxed); | 256 | is_paused.store(true, std::memory_order_relaxed); |
| 256 | } | 257 | } |
| 257 | 258 | ||
| @@ -261,7 +262,7 @@ struct System::Impl { | |||
| 261 | 262 | ||
| 262 | std::unique_lock<std::mutex> StallApplication() { | 263 | std::unique_lock<std::mutex> StallApplication() { |
| 263 | std::unique_lock<std::mutex> lk(suspend_guard); | 264 | std::unique_lock<std::mutex> lk(suspend_guard); |
| 264 | kernel.SuspendApplication(true); | 265 | kernel.SuspendEmulation(true); |
| 265 | core_timing.SyncPause(true); | 266 | core_timing.SyncPause(true); |
| 266 | return lk; | 267 | return lk; |
| 267 | } | 268 | } |
| @@ -269,7 +270,7 @@ struct System::Impl { | |||
| 269 | void UnstallApplication() { | 270 | void UnstallApplication() { |
| 270 | if (!IsPaused()) { | 271 | if (!IsPaused()) { |
| 271 | core_timing.SyncPause(false); | 272 | core_timing.SyncPause(false); |
| 272 | kernel.SuspendApplication(false); | 273 | kernel.SuspendEmulation(false); |
| 273 | } | 274 | } |
| 274 | } | 275 | } |
| 275 | 276 | ||
| @@ -310,7 +311,8 @@ struct System::Impl { | |||
| 310 | audio_core = std::make_unique<AudioCore::AudioCore>(system); | 311 | audio_core = std::make_unique<AudioCore::AudioCore>(system); |
| 311 | 312 | ||
| 312 | service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); | 313 | service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); |
| 313 | services = std::make_unique<Service::Services>(service_manager, system); | 314 | services = |
| 315 | std::make_unique<Service::Services>(service_manager, system, stop_event.get_token()); | ||
| 314 | 316 | ||
| 315 | is_powered_on = true; | 317 | is_powered_on = true; |
| 316 | exit_locked = false; | 318 | exit_locked = false; |
| @@ -458,11 +460,10 @@ struct System::Impl { | |||
| 458 | gpu_core->NotifyShutdown(); | 460 | gpu_core->NotifyShutdown(); |
| 459 | } | 461 | } |
| 460 | 462 | ||
| 463 | stop_event.request_stop(); | ||
| 464 | core_timing.SyncPause(false); | ||
| 461 | Network::CancelPendingSocketOperations(); | 465 | Network::CancelPendingSocketOperations(); |
| 462 | kernel.SuspendApplication(true); | 466 | kernel.SuspendEmulation(true); |
| 463 | if (services) { | ||
| 464 | services->KillNVNFlinger(); | ||
| 465 | } | ||
| 466 | kernel.CloseServices(); | 467 | kernel.CloseServices(); |
| 467 | kernel.ShutdownCores(); | 468 | kernel.ShutdownCores(); |
| 468 | applet_manager.Reset(); | 469 | applet_manager.Reset(); |
| @@ -480,6 +481,7 @@ struct System::Impl { | |||
| 480 | cpu_manager.Shutdown(); | 481 | cpu_manager.Shutdown(); |
| 481 | debugger.reset(); | 482 | debugger.reset(); |
| 482 | kernel.Shutdown(); | 483 | kernel.Shutdown(); |
| 484 | stop_event = {}; | ||
| 483 | Network::RestartSocketOperations(); | 485 | Network::RestartSocketOperations(); |
| 484 | 486 | ||
| 485 | if (auto room_member = room_network.GetRoomMember().lock()) { | 487 | if (auto room_member = room_network.GetRoomMember().lock()) { |
| @@ -615,6 +617,7 @@ struct System::Impl { | |||
| 615 | 617 | ||
| 616 | ExecuteProgramCallback execute_program_callback; | 618 | ExecuteProgramCallback execute_program_callback; |
| 617 | ExitCallback exit_callback; | 619 | ExitCallback exit_callback; |
| 620 | std::stop_source stop_event; | ||
| 618 | 621 | ||
| 619 | std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; | 622 | std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; |
| 620 | std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{}; | 623 | std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{}; |
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 7a5c22f78..9b1c77387 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp | |||
| @@ -199,10 +199,10 @@ void CpuManager::RunThread(std::stop_token token, std::size_t core) { | |||
| 199 | data.host_context = Common::Fiber::ThreadToFiber(); | 199 | data.host_context = Common::Fiber::ThreadToFiber(); |
| 200 | 200 | ||
| 201 | // Cleanup | 201 | // Cleanup |
| 202 | SCOPE_EXIT({ | 202 | SCOPE_EXIT { |
| 203 | data.host_context->Exit(); | 203 | data.host_context->Exit(); |
| 204 | MicroProfileOnThreadExit(); | 204 | MicroProfileOnThreadExit(); |
| 205 | }); | 205 | }; |
| 206 | 206 | ||
| 207 | // Running | 207 | // Running |
| 208 | if (!gpu_barrier->Sync(token)) { | 208 | if (!gpu_barrier->Sync(token)) { |
diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index 6dfee806c..37c1e69c3 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc | |||
| @@ -391,12 +391,12 @@ void DeviceMemoryManager<Traits>::WalkBlock(DAddr addr, std::size_t size, auto o | |||
| 391 | std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size); | 391 | std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size); |
| 392 | const auto current_vaddr = | 392 | const auto current_vaddr = |
| 393 | static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset); | 393 | static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset); |
| 394 | SCOPE_EXIT({ | 394 | SCOPE_EXIT{ |
| 395 | page_index += next_pages; | 395 | page_index += next_pages; |
| 396 | page_offset = 0; | 396 | page_offset = 0; |
| 397 | increment(copy_amount); | 397 | increment(copy_amount); |
| 398 | remaining_size -= copy_amount; | 398 | remaining_size -= copy_amount; |
| 399 | }); | 399 | }; |
| 400 | 400 | ||
| 401 | auto phys_addr = compressed_physical_ptr[page_index]; | 401 | auto phys_addr = compressed_physical_ptr[page_index]; |
| 402 | if (phys_addr == 0) { | 402 | if (phys_addr == 0) { |
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index 555b9d8f7..667efbbab 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h | |||
| @@ -64,8 +64,8 @@ struct RawNACP { | |||
| 64 | u64_le cache_storage_size; | 64 | u64_le cache_storage_size; |
| 65 | u64_le cache_storage_journal_size; | 65 | u64_le cache_storage_journal_size; |
| 66 | u64_le cache_storage_data_and_journal_max_size; | 66 | u64_le cache_storage_data_and_journal_max_size; |
| 67 | u64_le cache_storage_max_index; | 67 | u16_le cache_storage_max_index; |
| 68 | INSERT_PADDING_BYTES(0xE70); | 68 | INSERT_PADDING_BYTES(0xE76); |
| 69 | }; | 69 | }; |
| 70 | static_assert(sizeof(RawNACP) == 0x4000, "RawNACP has incorrect size."); | 70 | static_assert(sizeof(RawNACP) == 0x4000, "RawNACP has incorrect size."); |
| 71 | 71 | ||
diff --git a/src/core/file_sys/fs_directory.h b/src/core/file_sys/fs_directory.h index 25c9cb18a..3f90abb8f 100644 --- a/src/core/file_sys/fs_directory.h +++ b/src/core/file_sys/fs_directory.h | |||
| @@ -3,6 +3,10 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <string_view> | ||
| 7 | #include "common/common_funcs.h" | ||
| 8 | #include "common/common_types.h" | ||
| 9 | |||
| 6 | namespace FileSys { | 10 | namespace FileSys { |
| 7 | 11 | ||
| 8 | constexpr inline size_t EntryNameLengthMax = 0x300; | 12 | constexpr inline size_t EntryNameLengthMax = 0x300; |
diff --git a/src/core/file_sys/fs_path_utility.h b/src/core/file_sys/fs_path_utility.h index e9011d065..5643141f9 100644 --- a/src/core/file_sys/fs_path_utility.h +++ b/src/core/file_sys/fs_path_utility.h | |||
| @@ -447,7 +447,7 @@ public: | |||
| 447 | char* replacement_path = nullptr; | 447 | char* replacement_path = nullptr; |
| 448 | size_t replacement_path_size = 0; | 448 | size_t replacement_path_size = 0; |
| 449 | 449 | ||
| 450 | SCOPE_EXIT({ | 450 | SCOPE_EXIT { |
| 451 | if (replacement_path != nullptr) { | 451 | if (replacement_path != nullptr) { |
| 452 | if (std::is_constant_evaluated()) { | 452 | if (std::is_constant_evaluated()) { |
| 453 | delete[] replacement_path; | 453 | delete[] replacement_path; |
| @@ -455,7 +455,7 @@ public: | |||
| 455 | Deallocate(replacement_path, replacement_path_size); | 455 | Deallocate(replacement_path, replacement_path_size); |
| 456 | } | 456 | } |
| 457 | } | 457 | } |
| 458 | }); | 458 | }; |
| 459 | 459 | ||
| 460 | // Perform path replacement, if necessary | 460 | // Perform path replacement, if necessary |
| 461 | if (IsParentDirectoryPathReplacementNeeded(cur_path)) { | 461 | if (IsParentDirectoryPathReplacementNeeded(cur_path)) { |
| @@ -1102,8 +1102,8 @@ public: | |||
| 1102 | R_SUCCEED(); | 1102 | R_SUCCEED(); |
| 1103 | } | 1103 | } |
| 1104 | 1104 | ||
| 1105 | static Result Normalize(char* dst, size_t dst_size, const char* path, size_t path_len, | 1105 | static constexpr Result Normalize(char* dst, size_t dst_size, const char* path, size_t path_len, |
| 1106 | const PathFlags& flags) { | 1106 | const PathFlags& flags) { |
| 1107 | // Use StringTraits names for remainder of scope | 1107 | // Use StringTraits names for remainder of scope |
| 1108 | using namespace StringTraits; | 1108 | using namespace StringTraits; |
| 1109 | 1109 | ||
| @@ -1199,7 +1199,7 @@ public: | |||
| 1199 | const size_t replaced_src_len = path_len - (src - path); | 1199 | const size_t replaced_src_len = path_len - (src - path); |
| 1200 | 1200 | ||
| 1201 | char* replaced_src = nullptr; | 1201 | char* replaced_src = nullptr; |
| 1202 | SCOPE_EXIT({ | 1202 | SCOPE_EXIT { |
| 1203 | if (replaced_src != nullptr) { | 1203 | if (replaced_src != nullptr) { |
| 1204 | if (std::is_constant_evaluated()) { | 1204 | if (std::is_constant_evaluated()) { |
| 1205 | delete[] replaced_src; | 1205 | delete[] replaced_src; |
| @@ -1207,7 +1207,7 @@ public: | |||
| 1207 | Deallocate(replaced_src, replaced_src_len); | 1207 | Deallocate(replaced_src, replaced_src_len); |
| 1208 | } | 1208 | } |
| 1209 | } | 1209 | } |
| 1210 | }); | 1210 | }; |
| 1211 | 1211 | ||
| 1212 | if (std::is_constant_evaluated()) { | 1212 | if (std::is_constant_evaluated()) { |
| 1213 | replaced_src = new char[replaced_src_len]; | 1213 | replaced_src = new char[replaced_src_len]; |
diff --git a/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp b/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp index caea0b8f8..a68fd973c 100644 --- a/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp +++ b/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp | |||
| @@ -36,7 +36,9 @@ Result HierarchicalSha256Storage::Initialize(VirtualFile* base_storages, s32 lay | |||
| 36 | // Get the base storage size. | 36 | // Get the base storage size. |
| 37 | m_base_storage_size = base_storages[2]->GetSize(); | 37 | m_base_storage_size = base_storages[2]->GetSize(); |
| 38 | { | 38 | { |
| 39 | auto size_guard = SCOPE_GUARD({ m_base_storage_size = 0; }); | 39 | auto size_guard = SCOPE_GUARD { |
| 40 | m_base_storage_size = 0; | ||
| 41 | }; | ||
| 40 | R_UNLESS(m_base_storage_size <= static_cast<s64>(HashSize) | 42 | R_UNLESS(m_base_storage_size <= static_cast<s64>(HashSize) |
| 41 | << m_log_size_ratio << m_log_size_ratio, | 43 | << m_log_size_ratio << m_log_size_ratio, |
| 42 | ResultHierarchicalSha256BaseStorageTooLarge); | 44 | ResultHierarchicalSha256BaseStorageTooLarge); |
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp index ae4e441c9..289969cc4 100644 --- a/src/core/file_sys/program_metadata.cpp +++ b/src/core/file_sys/program_metadata.cpp | |||
| @@ -98,7 +98,9 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) { | |||
| 98 | 98 | ||
| 99 | Loader::ResultStatus ProgramMetadata::Reload(VirtualFile file) { | 99 | Loader::ResultStatus ProgramMetadata::Reload(VirtualFile file) { |
| 100 | const u64 original_program_id = aci_header.title_id; | 100 | const u64 original_program_id = aci_header.title_id; |
| 101 | SCOPE_EXIT({ aci_header.title_id = original_program_id; }); | 101 | SCOPE_EXIT { |
| 102 | aci_header.title_id = original_program_id; | ||
| 103 | }; | ||
| 102 | 104 | ||
| 103 | return this->Load(file); | 105 | return this->Load(file); |
| 104 | } | 106 | } |
diff --git a/src/core/file_sys/system_archive/shared_font.cpp b/src/core/file_sys/system_archive/shared_font.cpp index deb52069d..9ea16aa59 100644 --- a/src/core/file_sys/system_archive/shared_font.cpp +++ b/src/core/file_sys/system_archive/shared_font.cpp | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | #include "core/file_sys/system_archive/data/font_standard.h" | 9 | #include "core/file_sys/system_archive/data/font_standard.h" |
| 10 | #include "core/file_sys/system_archive/shared_font.h" | 10 | #include "core/file_sys/system_archive/shared_font.h" |
| 11 | #include "core/file_sys/vfs/vfs_vector.h" | 11 | #include "core/file_sys/vfs/vfs_vector.h" |
| 12 | #include "core/hle/service/ns/iplatform_service_manager.h" | 12 | #include "core/hle/service/ns/platform_service_manager.h" |
| 13 | 13 | ||
| 14 | namespace FileSys::SystemArchive { | 14 | namespace FileSys::SystemArchive { |
| 15 | 15 | ||
diff --git a/src/core/hle/kernel/k_client_session.cpp b/src/core/hle/kernel/k_client_session.cpp index 472e8571c..3e01e3b67 100644 --- a/src/core/hle/kernel/k_client_session.cpp +++ b/src/core/hle/kernel/k_client_session.cpp | |||
| @@ -24,7 +24,9 @@ Result KClientSession::SendSyncRequest(uintptr_t address, size_t size) { | |||
| 24 | // Create a session request. | 24 | // Create a session request. |
| 25 | KSessionRequest* request = KSessionRequest::Create(m_kernel); | 25 | KSessionRequest* request = KSessionRequest::Create(m_kernel); |
| 26 | R_UNLESS(request != nullptr, ResultOutOfResource); | 26 | R_UNLESS(request != nullptr, ResultOutOfResource); |
| 27 | SCOPE_EXIT({ request->Close(); }); | 27 | SCOPE_EXIT { |
| 28 | request->Close(); | ||
| 29 | }; | ||
| 28 | 30 | ||
| 29 | // Initialize the request. | 31 | // Initialize the request. |
| 30 | request->Initialize(nullptr, address, size); | 32 | request->Initialize(nullptr, address, size); |
| @@ -37,7 +39,9 @@ Result KClientSession::SendAsyncRequest(KEvent* event, uintptr_t address, size_t | |||
| 37 | // Create a session request. | 39 | // Create a session request. |
| 38 | KSessionRequest* request = KSessionRequest::Create(m_kernel); | 40 | KSessionRequest* request = KSessionRequest::Create(m_kernel); |
| 39 | R_UNLESS(request != nullptr, ResultOutOfResource); | 41 | R_UNLESS(request != nullptr, ResultOutOfResource); |
| 40 | SCOPE_EXIT({ request->Close(); }); | 42 | SCOPE_EXIT { |
| 43 | request->Close(); | ||
| 44 | }; | ||
| 41 | 45 | ||
| 42 | // Initialize the request. | 46 | // Initialize the request. |
| 43 | request->Initialize(event, address, size); | 47 | request->Initialize(event, address, size); |
diff --git a/src/core/hle/kernel/k_page_table_base.cpp b/src/core/hle/kernel/k_page_table_base.cpp index 1dd86fb3c..19cdf4f3a 100644 --- a/src/core/hle/kernel/k_page_table_base.cpp +++ b/src/core/hle/kernel/k_page_table_base.cpp | |||
| @@ -1305,11 +1305,11 @@ Result KPageTableBase::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddr | |||
| 1305 | 1305 | ||
| 1306 | // Ensure that we maintain the instruction cache. | 1306 | // Ensure that we maintain the instruction cache. |
| 1307 | bool reprotected_pages = false; | 1307 | bool reprotected_pages = false; |
| 1308 | SCOPE_EXIT({ | 1308 | SCOPE_EXIT { |
| 1309 | if (reprotected_pages && any_code_pages) { | 1309 | if (reprotected_pages && any_code_pages) { |
| 1310 | InvalidateInstructionCache(m_kernel, this, dst_address, size); | 1310 | InvalidateInstructionCache(m_kernel, this, dst_address, size); |
| 1311 | } | 1311 | } |
| 1312 | }); | 1312 | }; |
| 1313 | 1313 | ||
| 1314 | // Unmap. | 1314 | // Unmap. |
| 1315 | { | 1315 | { |
| @@ -1397,7 +1397,9 @@ Result KPageTableBase::MapInsecureMemory(KProcessAddress address, size_t size) { | |||
| 1397 | // Close the opened pages when we're done with them. | 1397 | // Close the opened pages when we're done with them. |
| 1398 | // If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed | 1398 | // If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed |
| 1399 | // automatically. | 1399 | // automatically. |
| 1400 | SCOPE_EXIT({ pg.Close(); }); | 1400 | SCOPE_EXIT { |
| 1401 | pg.Close(); | ||
| 1402 | }; | ||
| 1401 | 1403 | ||
| 1402 | // Clear all the newly allocated pages. | 1404 | // Clear all the newly allocated pages. |
| 1403 | for (const auto& it : pg) { | 1405 | for (const auto& it : pg) { |
| @@ -1603,7 +1605,9 @@ Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProce | |||
| 1603 | m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option)); | 1605 | m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option)); |
| 1604 | 1606 | ||
| 1605 | // Ensure that the page group is closed when we're done working with it. | 1607 | // Ensure that the page group is closed when we're done working with it. |
| 1606 | SCOPE_EXIT({ pg.Close(); }); | 1608 | SCOPE_EXIT { |
| 1609 | pg.Close(); | ||
| 1610 | }; | ||
| 1607 | 1611 | ||
| 1608 | // Clear all pages. | 1612 | // Clear all pages. |
| 1609 | for (const auto& it : pg) { | 1613 | for (const auto& it : pg) { |
| @@ -2191,7 +2195,9 @@ Result KPageTableBase::SetHeapSize(KProcessAddress* out, size_t size) { | |||
| 2191 | // Close the opened pages when we're done with them. | 2195 | // Close the opened pages when we're done with them. |
| 2192 | // If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed | 2196 | // If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed |
| 2193 | // automatically. | 2197 | // automatically. |
| 2194 | SCOPE_EXIT({ pg.Close(); }); | 2198 | SCOPE_EXIT { |
| 2199 | pg.Close(); | ||
| 2200 | }; | ||
| 2195 | 2201 | ||
| 2196 | // Clear all the newly allocated pages. | 2202 | // Clear all the newly allocated pages. |
| 2197 | for (const auto& it : pg) { | 2203 | for (const auto& it : pg) { |
| @@ -2592,7 +2598,9 @@ Result KPageTableBase::UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddre | |||
| 2592 | // Temporarily unlock ourselves, so that other operations can occur while we flush the | 2598 | // Temporarily unlock ourselves, so that other operations can occur while we flush the |
| 2593 | // region. | 2599 | // region. |
| 2594 | m_general_lock.Unlock(); | 2600 | m_general_lock.Unlock(); |
| 2595 | SCOPE_EXIT({ m_general_lock.Lock(); }); | 2601 | SCOPE_EXIT { |
| 2602 | m_general_lock.Lock(); | ||
| 2603 | }; | ||
| 2596 | 2604 | ||
| 2597 | // Flush the region. | 2605 | // Flush the region. |
| 2598 | R_ASSERT(FlushDataCache(dst_address, size)); | 2606 | R_ASSERT(FlushDataCache(dst_address, size)); |
| @@ -3311,10 +3319,10 @@ Result KPageTableBase::ReadIoMemoryImpl(KProcessAddress dst_addr, KPhysicalAddre | |||
| 3311 | // Ensure we unmap the io memory when we're done with it. | 3319 | // Ensure we unmap the io memory when we're done with it. |
| 3312 | const KPageProperties unmap_properties = | 3320 | const KPageProperties unmap_properties = |
| 3313 | KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None}; | 3321 | KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None}; |
| 3314 | SCOPE_EXIT({ | 3322 | SCOPE_EXIT { |
| 3315 | R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false, | 3323 | R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false, |
| 3316 | unmap_properties, OperationType::Unmap, true)); | 3324 | unmap_properties, OperationType::Unmap, true)); |
| 3317 | }); | 3325 | }; |
| 3318 | 3326 | ||
| 3319 | // Read the memory. | 3327 | // Read the memory. |
| 3320 | const KProcessAddress read_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1)); | 3328 | const KProcessAddress read_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1)); |
| @@ -3347,10 +3355,10 @@ Result KPageTableBase::WriteIoMemoryImpl(KPhysicalAddress phys_addr, KProcessAdd | |||
| 3347 | // Ensure we unmap the io memory when we're done with it. | 3355 | // Ensure we unmap the io memory when we're done with it. |
| 3348 | const KPageProperties unmap_properties = | 3356 | const KPageProperties unmap_properties = |
| 3349 | KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None}; | 3357 | KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None}; |
| 3350 | SCOPE_EXIT({ | 3358 | SCOPE_EXIT { |
| 3351 | R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false, | 3359 | R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false, |
| 3352 | unmap_properties, OperationType::Unmap, true)); | 3360 | unmap_properties, OperationType::Unmap, true)); |
| 3353 | }); | 3361 | }; |
| 3354 | 3362 | ||
| 3355 | // Write the memory. | 3363 | // Write the memory. |
| 3356 | const KProcessAddress write_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1)); | 3364 | const KProcessAddress write_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1)); |
| @@ -4491,14 +4499,14 @@ Result KPageTableBase::SetupForIpcServer(KProcessAddress* out_addr, size_t size, | |||
| 4491 | 4499 | ||
| 4492 | // If the partial pages are mapped, an extra reference will have been opened. Otherwise, they'll | 4500 | // If the partial pages are mapped, an extra reference will have been opened. Otherwise, they'll |
| 4493 | // free on scope exit. | 4501 | // free on scope exit. |
| 4494 | SCOPE_EXIT({ | 4502 | SCOPE_EXIT { |
| 4495 | if (start_partial_page != 0) { | 4503 | if (start_partial_page != 0) { |
| 4496 | m_kernel.MemoryManager().Close(start_partial_page, 1); | 4504 | m_kernel.MemoryManager().Close(start_partial_page, 1); |
| 4497 | } | 4505 | } |
| 4498 | if (end_partial_page != 0) { | 4506 | if (end_partial_page != 0) { |
| 4499 | m_kernel.MemoryManager().Close(end_partial_page, 1); | 4507 | m_kernel.MemoryManager().Close(end_partial_page, 1); |
| 4500 | } | 4508 | } |
| 4501 | }); | 4509 | }; |
| 4502 | 4510 | ||
| 4503 | ON_RESULT_FAILURE { | 4511 | ON_RESULT_FAILURE { |
| 4504 | if (cur_mapped_addr != dst_addr) { | 4512 | if (cur_mapped_addr != dst_addr) { |
| @@ -5166,10 +5174,10 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) { | |||
| 5166 | GetCurrentProcess(m_kernel).GetId(), m_heap_fill_value)); | 5174 | GetCurrentProcess(m_kernel).GetId(), m_heap_fill_value)); |
| 5167 | 5175 | ||
| 5168 | // If we fail in the next bit (or retry), we need to cleanup the pages. | 5176 | // If we fail in the next bit (or retry), we need to cleanup the pages. |
| 5169 | auto pg_guard = SCOPE_GUARD({ | 5177 | auto pg_guard = SCOPE_GUARD { |
| 5170 | pg.OpenFirst(); | 5178 | pg.OpenFirst(); |
| 5171 | pg.Close(); | 5179 | pg.Close(); |
| 5172 | }); | 5180 | }; |
| 5173 | 5181 | ||
| 5174 | // Map the memory. | 5182 | // Map the memory. |
| 5175 | { | 5183 | { |
| @@ -5694,7 +5702,9 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a | |||
| 5694 | 5702 | ||
| 5695 | // Ensure that any pages we track are closed on exit. | 5703 | // Ensure that any pages we track are closed on exit. |
| 5696 | KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager()); | 5704 | KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager()); |
| 5697 | SCOPE_EXIT({ pages_to_close.CloseAndReset(); }); | 5705 | SCOPE_EXIT { |
| 5706 | pages_to_close.CloseAndReset(); | ||
| 5707 | }; | ||
| 5698 | 5708 | ||
| 5699 | // Make a page group representing the region to unmap. | 5709 | // Make a page group representing the region to unmap. |
| 5700 | this->MakePageGroup(pages_to_close, virt_addr, num_pages); | 5710 | this->MakePageGroup(pages_to_close, virt_addr, num_pages); |
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 1bcc42890..cb9a11a63 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -77,7 +77,9 @@ Result TerminateChildren(KernelCore& kernel, KProcess* process, | |||
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | // Terminate and close the thread. | 79 | // Terminate and close the thread. |
| 80 | SCOPE_EXIT({ cur_child->Close(); }); | 80 | SCOPE_EXIT { |
| 81 | cur_child->Close(); | ||
| 82 | }; | ||
| 81 | 83 | ||
| 82 | if (const Result terminate_result = cur_child->Terminate(); | 84 | if (const Result terminate_result = cur_child->Terminate(); |
| 83 | ResultTerminationRequested == terminate_result) { | 85 | ResultTerminationRequested == terminate_result) { |
| @@ -466,11 +468,11 @@ void KProcess::DoWorkerTaskImpl() { | |||
| 466 | 468 | ||
| 467 | Result KProcess::StartTermination() { | 469 | Result KProcess::StartTermination() { |
| 468 | // Finalize the handle table when we're done, if the process isn't immortal. | 470 | // Finalize the handle table when we're done, if the process isn't immortal. |
| 469 | SCOPE_EXIT({ | 471 | SCOPE_EXIT { |
| 470 | if (!m_is_immortal) { | 472 | if (!m_is_immortal) { |
| 471 | this->FinalizeHandleTable(); | 473 | this->FinalizeHandleTable(); |
| 472 | } | 474 | } |
| 473 | }); | 475 | }; |
| 474 | 476 | ||
| 475 | // Terminate child threads other than the current one. | 477 | // Terminate child threads other than the current one. |
| 476 | R_RETURN(TerminateChildren(m_kernel, this, GetCurrentThreadPointer(m_kernel))); | 478 | R_RETURN(TerminateChildren(m_kernel, this, GetCurrentThreadPointer(m_kernel))); |
| @@ -964,7 +966,9 @@ Result KProcess::Run(s32 priority, size_t stack_size) { | |||
| 964 | // Create a new thread for the process. | 966 | // Create a new thread for the process. |
| 965 | KThread* main_thread = KThread::Create(m_kernel); | 967 | KThread* main_thread = KThread::Create(m_kernel); |
| 966 | R_UNLESS(main_thread != nullptr, ResultOutOfResource); | 968 | R_UNLESS(main_thread != nullptr, ResultOutOfResource); |
| 967 | SCOPE_EXIT({ main_thread->Close(); }); | 969 | SCOPE_EXIT { |
| 970 | main_thread->Close(); | ||
| 971 | }; | ||
| 968 | 972 | ||
| 969 | // Initialize the thread. | 973 | // Initialize the thread. |
| 970 | R_TRY(KThread::InitializeUserThread(m_kernel.System(), main_thread, this->GetEntryPoint(), 0, | 974 | R_TRY(KThread::InitializeUserThread(m_kernel.System(), main_thread, this->GetEntryPoint(), 0, |
| @@ -1155,7 +1159,9 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std: | |||
| 1155 | Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size); | 1159 | Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size); |
| 1156 | 1160 | ||
| 1157 | // Ensure we maintain a clean state on exit. | 1161 | // Ensure we maintain a clean state on exit. |
| 1158 | SCOPE_EXIT({ res_limit->Close(); }); | 1162 | SCOPE_EXIT { |
| 1163 | res_limit->Close(); | ||
| 1164 | }; | ||
| 1159 | 1165 | ||
| 1160 | // Declare flags and code address. | 1166 | // Declare flags and code address. |
| 1161 | Svc::CreateProcessFlag flag{}; | 1167 | Svc::CreateProcessFlag flag{}; |
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index adaabdd6d..40c3323ef 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp | |||
| @@ -651,11 +651,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m | |||
| 651 | // Process any special data. | 651 | // Process any special data. |
| 652 | if (src_header.GetHasSpecialHeader()) { | 652 | if (src_header.GetHasSpecialHeader()) { |
| 653 | // After we process, make sure we track whether the receive list is broken. | 653 | // After we process, make sure we track whether the receive list is broken. |
| 654 | SCOPE_EXIT({ | 654 | SCOPE_EXIT { |
| 655 | if (offset > dst_recv_list_idx) { | 655 | if (offset > dst_recv_list_idx) { |
| 656 | recv_list_broken = true; | 656 | recv_list_broken = true; |
| 657 | } | 657 | } |
| 658 | }); | 658 | }; |
| 659 | 659 | ||
| 660 | // Process special data. | 660 | // Process special data. |
| 661 | R_TRY(ProcessMessageSpecialData<false>(offset, dst_process, src_process, src_thread, | 661 | R_TRY(ProcessMessageSpecialData<false>(offset, dst_process, src_process, src_thread, |
| @@ -665,11 +665,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m | |||
| 665 | // Process any pointer buffers. | 665 | // Process any pointer buffers. |
| 666 | for (auto i = 0; i < src_header.GetPointerCount(); ++i) { | 666 | for (auto i = 0; i < src_header.GetPointerCount(); ++i) { |
| 667 | // After we process, make sure we track whether the receive list is broken. | 667 | // After we process, make sure we track whether the receive list is broken. |
| 668 | SCOPE_EXIT({ | 668 | SCOPE_EXIT { |
| 669 | if (offset > dst_recv_list_idx) { | 669 | if (offset > dst_recv_list_idx) { |
| 670 | recv_list_broken = true; | 670 | recv_list_broken = true; |
| 671 | } | 671 | } |
| 672 | }); | 672 | }; |
| 673 | 673 | ||
| 674 | R_TRY(ProcessReceiveMessagePointerDescriptors( | 674 | R_TRY(ProcessReceiveMessagePointerDescriptors( |
| 675 | offset, pointer_key, dst_page_table, src_page_table, dst_msg, src_msg, dst_recv_list, | 675 | offset, pointer_key, dst_page_table, src_page_table, dst_msg, src_msg, dst_recv_list, |
| @@ -680,11 +680,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m | |||
| 680 | // Process any map alias buffers. | 680 | // Process any map alias buffers. |
| 681 | for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) { | 681 | for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) { |
| 682 | // After we process, make sure we track whether the receive list is broken. | 682 | // After we process, make sure we track whether the receive list is broken. |
| 683 | SCOPE_EXIT({ | 683 | SCOPE_EXIT { |
| 684 | if (offset > dst_recv_list_idx) { | 684 | if (offset > dst_recv_list_idx) { |
| 685 | recv_list_broken = true; | 685 | recv_list_broken = true; |
| 686 | } | 686 | } |
| 687 | }); | 687 | }; |
| 688 | 688 | ||
| 689 | // We process in order send, recv, exch. Buffers after send (recv/exch) are ReadWrite. | 689 | // We process in order send, recv, exch. Buffers after send (recv/exch) are ReadWrite. |
| 690 | const KMemoryPermission perm = (i >= src_header.GetSendCount()) | 690 | const KMemoryPermission perm = (i >= src_header.GetSendCount()) |
| @@ -702,11 +702,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m | |||
| 702 | // Process any raw data. | 702 | // Process any raw data. |
| 703 | if (const auto raw_count = src_header.GetRawCount(); raw_count != 0) { | 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. | 704 | // After we process, make sure we track whether the receive list is broken. |
| 705 | SCOPE_EXIT({ | 705 | SCOPE_EXIT { |
| 706 | if (offset + raw_count > dst_recv_list_idx) { | 706 | if (offset + raw_count > dst_recv_list_idx) { |
| 707 | recv_list_broken = true; | 707 | recv_list_broken = true; |
| 708 | } | 708 | } |
| 709 | }); | 709 | }; |
| 710 | 710 | ||
| 711 | // Get the offset and size. | 711 | // Get the offset and size. |
| 712 | const size_t offset_words = offset * sizeof(u32); | 712 | const size_t offset_words = offset * sizeof(u32); |
| @@ -1124,7 +1124,9 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server | |||
| 1124 | client_thread->Open(); | 1124 | client_thread->Open(); |
| 1125 | } | 1125 | } |
| 1126 | 1126 | ||
| 1127 | SCOPE_EXIT({ client_thread->Close(); }); | 1127 | SCOPE_EXIT { |
| 1128 | client_thread->Close(); | ||
| 1129 | }; | ||
| 1128 | 1130 | ||
| 1129 | // Set the request as our current. | 1131 | // Set the request as our current. |
| 1130 | m_current_request = request; | 1132 | m_current_request = request; |
| @@ -1174,7 +1176,9 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server | |||
| 1174 | // Reply to the client. | 1176 | // Reply to the client. |
| 1175 | { | 1177 | { |
| 1176 | // After we reply, close our reference to the request. | 1178 | // After we reply, close our reference to the request. |
| 1177 | SCOPE_EXIT({ request->Close(); }); | 1179 | SCOPE_EXIT { |
| 1180 | request->Close(); | ||
| 1181 | }; | ||
| 1178 | 1182 | ||
| 1179 | // Get the event to check whether the request is async. | 1183 | // Get the event to check whether the request is async. |
| 1180 | if (KEvent* event = request->GetEvent(); event != nullptr) { | 1184 | if (KEvent* event = request->GetEvent(); event != nullptr) { |
| @@ -1236,7 +1240,9 @@ Result KServerSession::SendReply(uintptr_t server_message, uintptr_t server_buff | |||
| 1236 | } | 1240 | } |
| 1237 | 1241 | ||
| 1238 | // Close reference to the request once we're done processing it. | 1242 | // Close reference to the request once we're done processing it. |
| 1239 | SCOPE_EXIT({ request->Close(); }); | 1243 | SCOPE_EXIT { |
| 1244 | request->Close(); | ||
| 1245 | }; | ||
| 1240 | 1246 | ||
| 1241 | // Extract relevant information from the request. | 1247 | // Extract relevant information from the request. |
| 1242 | const uint64_t client_message = request->GetAddress(); | 1248 | const uint64_t client_message = request->GetAddress(); |
| @@ -1394,7 +1400,9 @@ void KServerSession::CleanupRequests() { | |||
| 1394 | } | 1400 | } |
| 1395 | 1401 | ||
| 1396 | // Close a reference to the request once it's cleaned up. | 1402 | // Close a reference to the request once it's cleaned up. |
| 1397 | SCOPE_EXIT({ request->Close(); }); | 1403 | SCOPE_EXIT { |
| 1404 | request->Close(); | ||
| 1405 | }; | ||
| 1398 | 1406 | ||
| 1399 | // Extract relevant information from the request. | 1407 | // Extract relevant information from the request. |
| 1400 | const uint64_t client_message = request->GetAddress(); | 1408 | const uint64_t client_message = request->GetAddress(); |
| @@ -1491,7 +1499,9 @@ void KServerSession::OnClientClosed() { | |||
| 1491 | ASSERT(thread != nullptr); | 1499 | ASSERT(thread != nullptr); |
| 1492 | 1500 | ||
| 1493 | // Ensure that we close the request when done. | 1501 | // Ensure that we close the request when done. |
| 1494 | SCOPE_EXIT({ request->Close(); }); | 1502 | SCOPE_EXIT { |
| 1503 | request->Close(); | ||
| 1504 | }; | ||
| 1495 | 1505 | ||
| 1496 | // If we're terminating, close a reference to the thread and event. | 1506 | // If we're terminating, close a reference to the thread and event. |
| 1497 | if (terminate) { | 1507 | if (terminate) { |
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index f13e232b2..e928cfebc 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -66,6 +66,7 @@ enum class SuspendType : u32 { | |||
| 66 | Debug = 2, | 66 | Debug = 2, |
| 67 | Backtrace = 3, | 67 | Backtrace = 3, |
| 68 | Init = 4, | 68 | Init = 4, |
| 69 | System = 5, | ||
| 69 | 70 | ||
| 70 | Count, | 71 | Count, |
| 71 | }; | 72 | }; |
| @@ -84,8 +85,9 @@ enum class ThreadState : u16 { | |||
| 84 | DebugSuspended = (1 << (2 + SuspendShift)), | 85 | DebugSuspended = (1 << (2 + SuspendShift)), |
| 85 | BacktraceSuspended = (1 << (3 + SuspendShift)), | 86 | BacktraceSuspended = (1 << (3 + SuspendShift)), |
| 86 | InitSuspended = (1 << (4 + SuspendShift)), | 87 | InitSuspended = (1 << (4 + SuspendShift)), |
| 88 | SystemSuspended = (1 << (5 + SuspendShift)), | ||
| 87 | 89 | ||
| 88 | SuspendFlagMask = ((1 << 5) - 1) << SuspendShift, | 90 | SuspendFlagMask = ((1 << 6) - 1) << SuspendShift, |
| 89 | }; | 91 | }; |
| 90 | DECLARE_ENUM_FLAG_OPERATORS(ThreadState); | 92 | DECLARE_ENUM_FLAG_OPERATORS(ThreadState); |
| 91 | 93 | ||
diff --git a/src/core/hle/kernel/k_thread_local_page.cpp b/src/core/hle/kernel/k_thread_local_page.cpp index a632d1634..1952c0083 100644 --- a/src/core/hle/kernel/k_thread_local_page.cpp +++ b/src/core/hle/kernel/k_thread_local_page.cpp | |||
| @@ -21,7 +21,9 @@ Result KThreadLocalPage::Initialize(KernelCore& kernel, KProcess* process) { | |||
| 21 | // Allocate a new page. | 21 | // Allocate a new page. |
| 22 | KPageBuffer* page_buf = KPageBuffer::Allocate(kernel); | 22 | KPageBuffer* page_buf = KPageBuffer::Allocate(kernel); |
| 23 | R_UNLESS(page_buf != nullptr, ResultOutOfMemory); | 23 | R_UNLESS(page_buf != nullptr, ResultOutOfMemory); |
| 24 | auto page_buf_guard = SCOPE_GUARD({ KPageBuffer::Free(kernel, page_buf); }); | 24 | auto page_buf_guard = SCOPE_GUARD { |
| 25 | KPageBuffer::Free(kernel, page_buf); | ||
| 26 | }; | ||
| 25 | 27 | ||
| 26 | // Map the address in. | 28 | // Map the address in. |
| 27 | const auto phys_addr = kernel.System().DeviceMemory().GetPhysicalAddr(page_buf); | 29 | const auto phys_addr = kernel.System().DeviceMemory().GetPhysicalAddr(page_buf); |
diff --git a/src/core/hle/kernel/k_transfer_memory.cpp b/src/core/hle/kernel/k_transfer_memory.cpp index cbb1b02bb..09295e8ad 100644 --- a/src/core/hle/kernel/k_transfer_memory.cpp +++ b/src/core/hle/kernel/k_transfer_memory.cpp | |||
| @@ -24,7 +24,9 @@ Result KTransferMemory::Initialize(KProcessAddress addr, std::size_t size, | |||
| 24 | 24 | ||
| 25 | // Construct the page group, guarding to make sure our state is valid on exit. | 25 | // Construct the page group, guarding to make sure our state is valid on exit. |
| 26 | m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager()); | 26 | m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager()); |
| 27 | auto pg_guard = SCOPE_GUARD({ m_page_group.reset(); }); | 27 | auto pg_guard = SCOPE_GUARD { |
| 28 | m_page_group.reset(); | ||
| 29 | }; | ||
| 28 | 30 | ||
| 29 | // Lock the memory. | 31 | // Lock the memory. |
| 30 | R_TRY(page_table.LockForTransferMemory(std::addressof(*m_page_group), addr, size, | 32 | R_TRY(page_table.LockForTransferMemory(std::addressof(*m_page_group), addr, size, |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 34b25be66..9e5eaeec4 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -109,7 +109,9 @@ struct KernelCore::Impl { | |||
| 109 | 109 | ||
| 110 | void Shutdown() { | 110 | void Shutdown() { |
| 111 | is_shutting_down.store(true, std::memory_order_relaxed); | 111 | is_shutting_down.store(true, std::memory_order_relaxed); |
| 112 | SCOPE_EXIT({ is_shutting_down.store(false, std::memory_order_relaxed); }); | 112 | SCOPE_EXIT { |
| 113 | is_shutting_down.store(false, std::memory_order_relaxed); | ||
| 114 | }; | ||
| 113 | 115 | ||
| 114 | CloseServices(); | 116 | CloseServices(); |
| 115 | 117 | ||
| @@ -1080,7 +1082,9 @@ std::jthread KernelCore::RunOnHostCoreProcess(std::string&& process_name, | |||
| 1080 | process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false))); | 1082 | process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false))); |
| 1081 | 1083 | ||
| 1082 | // Ensure that we don't hold onto any extra references. | 1084 | // Ensure that we don't hold onto any extra references. |
| 1083 | SCOPE_EXIT({ process->Close(); }); | 1085 | SCOPE_EXIT { |
| 1086 | process->Close(); | ||
| 1087 | }; | ||
| 1084 | 1088 | ||
| 1085 | // Register the new process. | 1089 | // Register the new process. |
| 1086 | KProcess::Register(*this, process); | 1090 | KProcess::Register(*this, process); |
| @@ -1108,7 +1112,9 @@ void KernelCore::RunOnGuestCoreProcess(std::string&& process_name, std::function | |||
| 1108 | process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false))); | 1112 | process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false))); |
| 1109 | 1113 | ||
| 1110 | // Ensure that we don't hold onto any extra references. | 1114 | // Ensure that we don't hold onto any extra references. |
| 1111 | SCOPE_EXIT({ process->Close(); }); | 1115 | SCOPE_EXIT { |
| 1116 | process->Close(); | ||
| 1117 | }; | ||
| 1112 | 1118 | ||
| 1113 | // Register the new process. | 1119 | // Register the new process. |
| 1114 | KProcess::Register(*this, process); | 1120 | KProcess::Register(*this, process); |
| @@ -1204,39 +1210,48 @@ const Kernel::KSharedMemory& KernelCore::GetHidBusSharedMem() const { | |||
| 1204 | return *impl->hidbus_shared_mem; | 1210 | return *impl->hidbus_shared_mem; |
| 1205 | } | 1211 | } |
| 1206 | 1212 | ||
| 1207 | void KernelCore::SuspendApplication(bool suspended) { | 1213 | void KernelCore::SuspendEmulation(bool suspended) { |
| 1208 | const bool should_suspend{exception_exited || suspended}; | 1214 | const bool should_suspend{exception_exited || suspended}; |
| 1209 | const auto activity = | 1215 | auto processes = GetProcessList(); |
| 1210 | should_suspend ? Svc::ProcessActivity::Paused : Svc::ProcessActivity::Runnable; | ||
| 1211 | 1216 | ||
| 1212 | // Get the application process. | 1217 | for (auto& process : processes) { |
| 1213 | KScopedAutoObject<KProcess> process = ApplicationProcess(); | 1218 | KScopedLightLock ll{process->GetListLock()}; |
| 1214 | if (process.IsNull()) { | 1219 | |
| 1215 | return; | 1220 | for (auto& thread : process->GetThreadList()) { |
| 1221 | if (should_suspend) { | ||
| 1222 | thread.RequestSuspend(SuspendType::System); | ||
| 1223 | } else { | ||
| 1224 | thread.Resume(SuspendType::System); | ||
| 1225 | } | ||
| 1226 | } | ||
| 1216 | } | 1227 | } |
| 1217 | 1228 | ||
| 1218 | // Set the new activity. | 1229 | if (!should_suspend) { |
| 1219 | process->SetActivity(activity); | 1230 | return; |
| 1231 | } | ||
| 1220 | 1232 | ||
| 1221 | // Wait for process execution to stop. | 1233 | // Wait for process execution to stop. |
| 1222 | bool must_wait{should_suspend}; | 1234 | // KernelCore::SuspendEmulation must be called from locked context, |
| 1223 | 1235 | // or we could race another call, interfering with waiting. | |
| 1224 | // KernelCore::SuspendApplication must be called from locked context, | 1236 | const auto TryWait = [&]() { |
| 1225 | // or we could race another call to SetActivity, interfering with waiting. | ||
| 1226 | while (must_wait) { | ||
| 1227 | KScopedSchedulerLock sl{*this}; | 1237 | KScopedSchedulerLock sl{*this}; |
| 1228 | 1238 | ||
| 1229 | // Assume that all threads have finished running. | 1239 | for (auto& process : processes) { |
| 1230 | must_wait = false; | 1240 | for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { |
| 1231 | 1241 | if (Scheduler(i).GetSchedulerCurrentThread()->GetOwnerProcess() == | |
| 1232 | for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { | 1242 | process.GetPointerUnsafe()) { |
| 1233 | if (Scheduler(i).GetSchedulerCurrentThread()->GetOwnerProcess() == | 1243 | // A thread has not finished running yet. |
| 1234 | process.GetPointerUnsafe()) { | 1244 | // Continue waiting. |
| 1235 | // A thread has not finished running yet. | 1245 | return false; |
| 1236 | // Continue waiting. | 1246 | } |
| 1237 | must_wait = true; | ||
| 1238 | } | 1247 | } |
| 1239 | } | 1248 | } |
| 1249 | |||
| 1250 | return true; | ||
| 1251 | }; | ||
| 1252 | |||
| 1253 | while (!TryWait()) { | ||
| 1254 | // ... | ||
| 1240 | } | 1255 | } |
| 1241 | } | 1256 | } |
| 1242 | 1257 | ||
| @@ -1260,7 +1275,7 @@ bool KernelCore::IsShuttingDown() const { | |||
| 1260 | 1275 | ||
| 1261 | void KernelCore::ExceptionalExitApplication() { | 1276 | void KernelCore::ExceptionalExitApplication() { |
| 1262 | exception_exited = true; | 1277 | exception_exited = true; |
| 1263 | SuspendApplication(true); | 1278 | SuspendEmulation(true); |
| 1264 | } | 1279 | } |
| 1265 | 1280 | ||
| 1266 | void KernelCore::EnterSVCProfile() { | 1281 | void KernelCore::EnterSVCProfile() { |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 8ea5bed1c..57182c0c8 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -258,8 +258,8 @@ public: | |||
| 258 | /// Gets the shared memory object for HIDBus services. | 258 | /// Gets the shared memory object for HIDBus services. |
| 259 | const Kernel::KSharedMemory& GetHidBusSharedMem() const; | 259 | const Kernel::KSharedMemory& GetHidBusSharedMem() const; |
| 260 | 260 | ||
| 261 | /// Suspend/unsuspend application process. | 261 | /// Suspend/unsuspend emulated processes. |
| 262 | void SuspendApplication(bool suspend); | 262 | void SuspendEmulation(bool suspend); |
| 263 | 263 | ||
| 264 | /// Exceptional exit application process. | 264 | /// Exceptional exit application process. |
| 265 | void ExceptionalExitApplication(); | 265 | void ExceptionalExitApplication(); |
diff --git a/src/core/hle/kernel/svc/svc_code_memory.cpp b/src/core/hle/kernel/svc/svc_code_memory.cpp index bae4cb0cd..7be2802f0 100644 --- a/src/core/hle/kernel/svc/svc_code_memory.cpp +++ b/src/core/hle/kernel/svc/svc_code_memory.cpp | |||
| @@ -45,7 +45,9 @@ Result CreateCodeMemory(Core::System& system, Handle* out, u64 address, uint64_t | |||
| 45 | 45 | ||
| 46 | KCodeMemory* code_mem = KCodeMemory::Create(kernel); | 46 | KCodeMemory* code_mem = KCodeMemory::Create(kernel); |
| 47 | R_UNLESS(code_mem != nullptr, ResultOutOfResource); | 47 | R_UNLESS(code_mem != nullptr, ResultOutOfResource); |
| 48 | SCOPE_EXIT({ code_mem->Close(); }); | 48 | SCOPE_EXIT { |
| 49 | code_mem->Close(); | ||
| 50 | }; | ||
| 49 | 51 | ||
| 50 | // Verify that the region is in range. | 52 | // Verify that the region is in range. |
| 51 | R_UNLESS(GetCurrentProcess(system.Kernel()).GetPageTable().Contains(address, size), | 53 | R_UNLESS(GetCurrentProcess(system.Kernel()).GetPageTable().Contains(address, size), |
diff --git a/src/core/hle/kernel/svc/svc_device_address_space.cpp b/src/core/hle/kernel/svc/svc_device_address_space.cpp index 42add9473..ac828320f 100644 --- a/src/core/hle/kernel/svc/svc_device_address_space.cpp +++ b/src/core/hle/kernel/svc/svc_device_address_space.cpp | |||
| @@ -28,7 +28,9 @@ Result CreateDeviceAddressSpace(Core::System& system, Handle* out, uint64_t das_ | |||
| 28 | // Create the device address space. | 28 | // Create the device address space. |
| 29 | KDeviceAddressSpace* das = KDeviceAddressSpace::Create(system.Kernel()); | 29 | KDeviceAddressSpace* das = KDeviceAddressSpace::Create(system.Kernel()); |
| 30 | R_UNLESS(das != nullptr, ResultOutOfResource); | 30 | R_UNLESS(das != nullptr, ResultOutOfResource); |
| 31 | SCOPE_EXIT({ das->Close(); }); | 31 | SCOPE_EXIT { |
| 32 | das->Close(); | ||
| 33 | }; | ||
| 32 | 34 | ||
| 33 | // Initialize the device address space. | 35 | // Initialize the device address space. |
| 34 | R_TRY(das->Initialize(das_address, das_size)); | 36 | R_TRY(das->Initialize(das_address, das_size)); |
diff --git a/src/core/hle/kernel/svc/svc_event.cpp b/src/core/hle/kernel/svc/svc_event.cpp index 901202e6a..8e4beb396 100644 --- a/src/core/hle/kernel/svc/svc_event.cpp +++ b/src/core/hle/kernel/svc/svc_event.cpp | |||
| @@ -72,10 +72,10 @@ Result CreateEvent(Core::System& system, Handle* out_write, Handle* out_read) { | |||
| 72 | event_reservation.Commit(); | 72 | event_reservation.Commit(); |
| 73 | 73 | ||
| 74 | // Ensure that we clean up the event (and its only references are handle table) on function end. | 74 | // Ensure that we clean up the event (and its only references are handle table) on function end. |
| 75 | SCOPE_EXIT({ | 75 | SCOPE_EXIT { |
| 76 | event->GetReadableEvent().Close(); | 76 | event->GetReadableEvent().Close(); |
| 77 | event->Close(); | 77 | event->Close(); |
| 78 | }); | 78 | }; |
| 79 | 79 | ||
| 80 | // Register the event. | 80 | // Register the event. |
| 81 | KEvent::Register(kernel, event); | 81 | KEvent::Register(kernel, event); |
diff --git a/src/core/hle/kernel/svc/svc_ipc.cpp b/src/core/hle/kernel/svc/svc_ipc.cpp index 85cc4f561..b619bd70a 100644 --- a/src/core/hle/kernel/svc/svc_ipc.cpp +++ b/src/core/hle/kernel/svc/svc_ipc.cpp | |||
| @@ -129,11 +129,11 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes | |||
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | // Ensure handles are closed when we're done. | 131 | // Ensure handles are closed when we're done. |
| 132 | SCOPE_EXIT({ | 132 | SCOPE_EXIT { |
| 133 | for (auto i = 0; i < num_handles; ++i) { | 133 | for (auto i = 0; i < num_handles; ++i) { |
| 134 | objs[i]->Close(); | 134 | objs[i]->Close(); |
| 135 | } | 135 | } |
| 136 | }); | 136 | }; |
| 137 | 137 | ||
| 138 | R_RETURN(ReplyAndReceiveImpl(kernel, out_index, message, buffer_size, message_paddr, objs, | 138 | R_RETURN(ReplyAndReceiveImpl(kernel, out_index, message, buffer_size, message_paddr, objs, |
| 139 | num_handles, reply_target, timeout_ns)); | 139 | num_handles, reply_target, timeout_ns)); |
| @@ -208,10 +208,10 @@ Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_ha | |||
| 208 | event_reservation.Commit(); | 208 | event_reservation.Commit(); |
| 209 | 209 | ||
| 210 | // At end of scope, kill the standing references to the sub events. | 210 | // At end of scope, kill the standing references to the sub events. |
| 211 | SCOPE_EXIT({ | 211 | SCOPE_EXIT { |
| 212 | event->GetReadableEvent().Close(); | 212 | event->GetReadableEvent().Close(); |
| 213 | event->Close(); | 213 | event->Close(); |
| 214 | }); | 214 | }; |
| 215 | 215 | ||
| 216 | // Register the event. | 216 | // Register the event. |
| 217 | KEvent::Register(system.Kernel(), event); | 217 | KEvent::Register(system.Kernel(), event); |
diff --git a/src/core/hle/kernel/svc/svc_port.cpp b/src/core/hle/kernel/svc/svc_port.cpp index 737749f7d..9a22dadaf 100644 --- a/src/core/hle/kernel/svc/svc_port.cpp +++ b/src/core/hle/kernel/svc/svc_port.cpp | |||
| @@ -68,10 +68,10 @@ Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client, | |||
| 68 | port->Initialize(max_sessions, is_light, name); | 68 | port->Initialize(max_sessions, is_light, name); |
| 69 | 69 | ||
| 70 | // Ensure that we clean up the port (and its only references are handle table) on function end. | 70 | // Ensure that we clean up the port (and its only references are handle table) on function end. |
| 71 | SCOPE_EXIT({ | 71 | SCOPE_EXIT { |
| 72 | port->GetServerPort().Close(); | 72 | port->GetServerPort().Close(); |
| 73 | port->GetClientPort().Close(); | 73 | port->GetClientPort().Close(); |
| 74 | }); | 74 | }; |
| 75 | 75 | ||
| 76 | // Register the port. | 76 | // Register the port. |
| 77 | KPort::Register(kernel, port); | 77 | KPort::Register(kernel, port); |
| @@ -150,10 +150,10 @@ Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t | |||
| 150 | KPort::Register(system.Kernel(), port); | 150 | KPort::Register(system.Kernel(), port); |
| 151 | 151 | ||
| 152 | // Ensure that our only reference to the port is in the handle table when we're done. | 152 | // Ensure that our only reference to the port is in the handle table when we're done. |
| 153 | SCOPE_EXIT({ | 153 | SCOPE_EXIT { |
| 154 | port->GetClientPort().Close(); | 154 | port->GetClientPort().Close(); |
| 155 | port->GetServerPort().Close(); | 155 | port->GetServerPort().Close(); |
| 156 | }); | 156 | }; |
| 157 | 157 | ||
| 158 | // Register the handle in the table. | 158 | // Register the handle in the table. |
| 159 | R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort()))); | 159 | R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort()))); |
diff --git a/src/core/hle/kernel/svc/svc_resource_limit.cpp b/src/core/hle/kernel/svc/svc_resource_limit.cpp index c8e820b6a..6f3972482 100644 --- a/src/core/hle/kernel/svc/svc_resource_limit.cpp +++ b/src/core/hle/kernel/svc/svc_resource_limit.cpp | |||
| @@ -18,7 +18,9 @@ Result CreateResourceLimit(Core::System& system, Handle* out_handle) { | |||
| 18 | R_UNLESS(resource_limit != nullptr, ResultOutOfResource); | 18 | R_UNLESS(resource_limit != nullptr, ResultOutOfResource); |
| 19 | 19 | ||
| 20 | // Ensure we don't leak a reference to the limit. | 20 | // Ensure we don't leak a reference to the limit. |
| 21 | SCOPE_EXIT({ resource_limit->Close(); }); | 21 | SCOPE_EXIT { |
| 22 | resource_limit->Close(); | ||
| 23 | }; | ||
| 22 | 24 | ||
| 23 | // Initialize the resource limit. | 25 | // Initialize the resource limit. |
| 24 | resource_limit->Initialize(); | 26 | resource_limit->Initialize(); |
diff --git a/src/core/hle/kernel/svc/svc_session.cpp b/src/core/hle/kernel/svc/svc_session.cpp index 2f5905f32..b034d21d1 100644 --- a/src/core/hle/kernel/svc/svc_session.cpp +++ b/src/core/hle/kernel/svc/svc_session.cpp | |||
| @@ -69,10 +69,10 @@ Result CreateSession(Core::System& system, Handle* out_server, Handle* out_clien | |||
| 69 | 69 | ||
| 70 | // Ensure that we clean up the session (and its only references are handle table) on function | 70 | // Ensure that we clean up the session (and its only references are handle table) on function |
| 71 | // end. | 71 | // end. |
| 72 | SCOPE_EXIT({ | 72 | SCOPE_EXIT { |
| 73 | session->GetClientSession().Close(); | 73 | session->GetClientSession().Close(); |
| 74 | session->GetServerSession().Close(); | 74 | session->GetServerSession().Close(); |
| 75 | }); | 75 | }; |
| 76 | 76 | ||
| 77 | // Register the session. | 77 | // Register the session. |
| 78 | T::Register(system.Kernel(), session); | 78 | T::Register(system.Kernel(), session); |
diff --git a/src/core/hle/kernel/svc/svc_synchronization.cpp b/src/core/hle/kernel/svc/svc_synchronization.cpp index 6c79cfd8d..fb03908d7 100644 --- a/src/core/hle/kernel/svc/svc_synchronization.cpp +++ b/src/core/hle/kernel/svc/svc_synchronization.cpp | |||
| @@ -78,11 +78,11 @@ Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_ha | |||
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | // Ensure handles are closed when we're done. | 80 | // Ensure handles are closed when we're done. |
| 81 | SCOPE_EXIT({ | 81 | SCOPE_EXIT { |
| 82 | for (auto i = 0; i < num_handles; ++i) { | 82 | for (auto i = 0; i < num_handles; ++i) { |
| 83 | objs[i]->Close(); | 83 | objs[i]->Close(); |
| 84 | } | 84 | } |
| 85 | }); | 85 | }; |
| 86 | 86 | ||
| 87 | // Convert the timeout from nanoseconds to ticks. | 87 | // Convert the timeout from nanoseconds to ticks. |
| 88 | s64 timeout; | 88 | s64 timeout; |
diff --git a/src/core/hle/kernel/svc/svc_thread.cpp b/src/core/hle/kernel/svc/svc_thread.cpp index 7681afa33..7517bb9d3 100644 --- a/src/core/hle/kernel/svc/svc_thread.cpp +++ b/src/core/hle/kernel/svc/svc_thread.cpp | |||
| @@ -51,7 +51,9 @@ Result CreateThread(Core::System& system, Handle* out_handle, u64 entry_point, u | |||
| 51 | // Create the thread. | 51 | // Create the thread. |
| 52 | KThread* thread = KThread::Create(kernel); | 52 | KThread* thread = KThread::Create(kernel); |
| 53 | R_UNLESS(thread != nullptr, ResultOutOfResource) | 53 | R_UNLESS(thread != nullptr, ResultOutOfResource) |
| 54 | SCOPE_EXIT({ thread->Close(); }); | 54 | SCOPE_EXIT { |
| 55 | thread->Close(); | ||
| 56 | }; | ||
| 55 | 57 | ||
| 56 | // Initialize the thread. | 58 | // Initialize the thread. |
| 57 | { | 59 | { |
diff --git a/src/core/hle/kernel/svc/svc_transfer_memory.cpp b/src/core/hle/kernel/svc/svc_transfer_memory.cpp index 671bca23f..2ea0d4421 100644 --- a/src/core/hle/kernel/svc/svc_transfer_memory.cpp +++ b/src/core/hle/kernel/svc/svc_transfer_memory.cpp | |||
| @@ -52,7 +52,9 @@ Result CreateTransferMemory(Core::System& system, Handle* out, u64 address, u64 | |||
| 52 | R_UNLESS(trmem != nullptr, ResultOutOfResource); | 52 | R_UNLESS(trmem != nullptr, ResultOutOfResource); |
| 53 | 53 | ||
| 54 | // Ensure the only reference is in the handle table when we're done. | 54 | // Ensure the only reference is in the handle table when we're done. |
| 55 | SCOPE_EXIT({ trmem->Close(); }); | 55 | SCOPE_EXIT { |
| 56 | trmem->Close(); | ||
| 57 | }; | ||
| 56 | 58 | ||
| 57 | // Ensure that the region is in range. | 59 | // Ensure that the region is in range. |
| 58 | R_UNLESS(process.GetPageTable().Contains(address, size), ResultInvalidCurrentMemory); | 60 | R_UNLESS(process.GetPageTable().Contains(address, size), ResultInvalidCurrentMemory); |
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 29a10ad13..ee9795532 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp | |||
| @@ -329,9 +329,8 @@ bool ProfileManager::GetProfileBaseAndData(const ProfileInfo& user, ProfileBase& | |||
| 329 | 329 | ||
| 330 | /// Returns if the system is allowing user registrations or not | 330 | /// Returns if the system is allowing user registrations or not |
| 331 | bool ProfileManager::CanSystemRegisterUser() const { | 331 | bool ProfileManager::CanSystemRegisterUser() const { |
| 332 | return false; // TODO(ogniK): Games shouldn't have | 332 | // TODO: Both games and applets can register users. Determine when this condition is not meet. |
| 333 | // access to user registration, when we | 333 | return true; |
| 334 | // emulate qlaunch. Update this to dynamically change. | ||
| 335 | } | 334 | } |
| 336 | 335 | ||
| 337 | bool ProfileManager::RemoveUser(UUID uuid) { | 336 | bool ProfileManager::RemoveUser(UUID uuid) { |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 9dc710ba9..8c4e14f08 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -8,13 +8,13 @@ | |||
| 8 | 8 | ||
| 9 | namespace Service::AM { | 9 | namespace Service::AM { |
| 10 | 10 | ||
| 11 | void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { | 11 | void LoopProcess(Core::System& system) { |
| 12 | auto server_manager = std::make_unique<ServerManager>(system); | 12 | auto server_manager = std::make_unique<ServerManager>(system); |
| 13 | 13 | ||
| 14 | server_manager->RegisterNamedService( | 14 | server_manager->RegisterNamedService("appletAE", |
| 15 | "appletAE", std::make_shared<IAllSystemAppletProxiesService>(system, nvnflinger)); | 15 | std::make_shared<IAllSystemAppletProxiesService>(system)); |
| 16 | server_manager->RegisterNamedService( | 16 | server_manager->RegisterNamedService("appletOE", |
| 17 | "appletOE", std::make_shared<IApplicationProxyService>(system, nvnflinger)); | 17 | std::make_shared<IApplicationProxyService>(system)); |
| 18 | ServerManager::RunServer(std::move(server_manager)); | 18 | ServerManager::RunServer(std::move(server_manager)); |
| 19 | } | 19 | } |
| 20 | 20 | ||
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 4a2d797bd..1afe253ae 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -7,12 +7,8 @@ namespace Core { | |||
| 7 | class System; | 7 | class System; |
| 8 | } | 8 | } |
| 9 | 9 | ||
| 10 | namespace Service::Nvnflinger { | ||
| 11 | class Nvnflinger; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace Service::AM { | 10 | namespace Service::AM { |
| 15 | 11 | ||
| 16 | void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system); | 12 | void LoopProcess(Core::System& system); |
| 17 | 13 | ||
| 18 | } // namespace Service::AM | 14 | } // namespace Service::AM |
diff --git a/src/core/hle/service/am/applet.h b/src/core/hle/service/am/applet.h index 4f34d4811..ad602153e 100644 --- a/src/core/hle/service/am/applet.h +++ b/src/core/hle/service/am/applet.h | |||
| @@ -14,10 +14,9 @@ | |||
| 14 | 14 | ||
| 15 | #include "core/hle/service/am/am_types.h" | 15 | #include "core/hle/service/am/am_types.h" |
| 16 | #include "core/hle/service/am/applet_message_queue.h" | 16 | #include "core/hle/service/am/applet_message_queue.h" |
| 17 | #include "core/hle/service/am/display_layer_manager.h" | ||
| 17 | #include "core/hle/service/am/hid_registration.h" | 18 | #include "core/hle/service/am/hid_registration.h" |
| 18 | #include "core/hle/service/am/managed_layer_holder.h" | ||
| 19 | #include "core/hle/service/am/process.h" | 19 | #include "core/hle/service/am/process.h" |
| 20 | #include "core/hle/service/am/system_buffer_manager.h" | ||
| 21 | 20 | ||
| 22 | namespace Service::AM { | 21 | namespace Service::AM { |
| 23 | 22 | ||
| @@ -54,8 +53,7 @@ struct Applet { | |||
| 54 | HidRegistration hid_registration; | 53 | HidRegistration hid_registration; |
| 55 | 54 | ||
| 56 | // vi state | 55 | // vi state |
| 57 | SystemBufferManager system_buffer_manager{}; | 56 | DisplayLayerManager display_layer_manager{}; |
| 58 | ManagedLayerHolder managed_layer_holder{}; | ||
| 59 | 57 | ||
| 60 | // Applet common functions | 58 | // Applet common functions |
| 61 | Result terminate_result{}; | 59 | Result terminate_result{}; |
diff --git a/src/core/hle/service/am/applet_data_broker.cpp b/src/core/hle/service/am/applet_data_broker.cpp index 4d58c4db5..9057244a9 100644 --- a/src/core/hle/service/am/applet_data_broker.cpp +++ b/src/core/hle/service/am/applet_data_broker.cpp | |||
| @@ -24,11 +24,11 @@ void AppletStorageChannel::Push(std::shared_ptr<IStorage> storage) { | |||
| 24 | Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* out_storage) { | 24 | Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* out_storage) { |
| 25 | std::scoped_lock lk{m_lock}; | 25 | std::scoped_lock lk{m_lock}; |
| 26 | 26 | ||
| 27 | SCOPE_EXIT({ | 27 | SCOPE_EXIT { |
| 28 | if (m_data.empty()) { | 28 | if (m_data.empty()) { |
| 29 | m_event.Clear(); | 29 | m_event.Clear(); |
| 30 | } | 30 | } |
| 31 | }); | 31 | }; |
| 32 | 32 | ||
| 33 | R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel); | 33 | R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel); |
| 34 | 34 | ||
diff --git a/src/core/hle/service/am/applet_manager.cpp b/src/core/hle/service/am/applet_manager.cpp index 4c7266f89..2e109181d 100644 --- a/src/core/hle/service/am/applet_manager.cpp +++ b/src/core/hle/service/am/applet_manager.cpp | |||
| @@ -35,6 +35,21 @@ AppletStorageChannel& InitializeFakeCallerApplet(Core::System& system, | |||
| 35 | return applet->caller_applet_broker->GetInData(); | 35 | return applet->caller_applet_broker->GetInData(); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | void PushInShowQlaunch(Core::System& system, AppletStorageChannel& channel) { | ||
| 39 | const CommonArguments arguments{ | ||
| 40 | .arguments_version = CommonArgumentVersion::Version3, | ||
| 41 | .size = CommonArgumentSize::Version3, | ||
| 42 | .library_version = 0, | ||
| 43 | .theme_color = ThemeColor::BasicBlack, | ||
| 44 | .play_startup_sound = true, | ||
| 45 | .system_tick = system.CoreTiming().GetClockTicks(), | ||
| 46 | }; | ||
| 47 | |||
| 48 | std::vector<u8> argument_data(sizeof(arguments)); | ||
| 49 | std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); | ||
| 50 | channel.Push(std::make_shared<IStorage>(system, std::move(argument_data))); | ||
| 51 | } | ||
| 52 | |||
| 38 | void PushInShowAlbum(Core::System& system, AppletStorageChannel& channel) { | 53 | void PushInShowAlbum(Core::System& system, AppletStorageChannel& channel) { |
| 39 | const CommonArguments arguments{ | 54 | const CommonArguments arguments{ |
| 40 | .arguments_version = CommonArgumentVersion::Version3, | 55 | .arguments_version = CommonArgumentVersion::Version3, |
| @@ -284,6 +299,9 @@ void AppletManager::CreateAndInsertByFrontendAppletParameters( | |||
| 284 | 299 | ||
| 285 | // Starting from frontend, some applets require input data. | 300 | // Starting from frontend, some applets require input data. |
| 286 | switch (applet->applet_id) { | 301 | switch (applet->applet_id) { |
| 302 | case AppletId::QLaunch: | ||
| 303 | PushInShowQlaunch(m_system, InitializeFakeCallerApplet(m_system, applet)); | ||
| 304 | break; | ||
| 287 | case AppletId::Cabinet: | 305 | case AppletId::Cabinet: |
| 288 | PushInShowCabinetData(m_system, InitializeFakeCallerApplet(m_system, applet)); | 306 | PushInShowCabinetData(m_system, InitializeFakeCallerApplet(m_system, applet)); |
| 289 | break; | 307 | break; |
diff --git a/src/core/hle/service/am/display_layer_manager.cpp b/src/core/hle/service/am/display_layer_manager.cpp new file mode 100644 index 000000000..85ff6fb88 --- /dev/null +++ b/src/core/hle/service/am/display_layer_manager.cpp | |||
| @@ -0,0 +1,151 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/hle/service/am/display_layer_manager.h" | ||
| 6 | #include "core/hle/service/sm/sm.h" | ||
| 7 | #include "core/hle/service/vi/application_display_service.h" | ||
| 8 | #include "core/hle/service/vi/container.h" | ||
| 9 | #include "core/hle/service/vi/manager_display_service.h" | ||
| 10 | #include "core/hle/service/vi/manager_root_service.h" | ||
| 11 | #include "core/hle/service/vi/shared_buffer_manager.h" | ||
| 12 | #include "core/hle/service/vi/vi_results.h" | ||
| 13 | #include "core/hle/service/vi/vi_types.h" | ||
| 14 | |||
| 15 | namespace Service::AM { | ||
| 16 | |||
| 17 | DisplayLayerManager::DisplayLayerManager() = default; | ||
| 18 | DisplayLayerManager::~DisplayLayerManager() { | ||
| 19 | this->Finalize(); | ||
| 20 | } | ||
| 21 | |||
| 22 | void DisplayLayerManager::Initialize(Core::System& system, Kernel::KProcess* process, | ||
| 23 | AppletId applet_id, LibraryAppletMode mode) { | ||
| 24 | R_ASSERT(system.ServiceManager() | ||
| 25 | .GetService<VI::IManagerRootService>("vi:m", true) | ||
| 26 | ->GetDisplayService(&m_display_service, VI::Policy::Compositor)); | ||
| 27 | R_ASSERT(m_display_service->GetManagerDisplayService(&m_manager_display_service)); | ||
| 28 | |||
| 29 | m_process = process; | ||
| 30 | m_system_shared_buffer_id = 0; | ||
| 31 | m_system_shared_layer_id = 0; | ||
| 32 | m_applet_id = applet_id; | ||
| 33 | m_buffer_sharing_enabled = false; | ||
| 34 | m_blending_enabled = mode == LibraryAppletMode::PartialForeground || | ||
| 35 | mode == LibraryAppletMode::PartialForegroundIndirectDisplay; | ||
| 36 | } | ||
| 37 | |||
| 38 | void DisplayLayerManager::Finalize() { | ||
| 39 | if (!m_manager_display_service) { | ||
| 40 | return; | ||
| 41 | } | ||
| 42 | |||
| 43 | // Clean up managed layers. | ||
| 44 | for (const auto& layer : m_managed_display_layers) { | ||
| 45 | m_manager_display_service->DestroyManagedLayer(layer); | ||
| 46 | } | ||
| 47 | |||
| 48 | for (const auto& layer : m_managed_display_recording_layers) { | ||
| 49 | m_manager_display_service->DestroyManagedLayer(layer); | ||
| 50 | } | ||
| 51 | |||
| 52 | // Clean up shared layers. | ||
| 53 | if (m_buffer_sharing_enabled) { | ||
| 54 | m_manager_display_service->DestroySharedLayerSession(m_process); | ||
| 55 | } | ||
| 56 | |||
| 57 | m_manager_display_service = nullptr; | ||
| 58 | m_display_service = nullptr; | ||
| 59 | } | ||
| 60 | |||
| 61 | Result DisplayLayerManager::CreateManagedDisplayLayer(u64* out_layer_id) { | ||
| 62 | R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed); | ||
| 63 | |||
| 64 | // TODO(Subv): Find out how AM determines the display to use, for now just | ||
| 65 | // create the layer in the Default display. | ||
| 66 | u64 display_id; | ||
| 67 | R_TRY(m_display_service->OpenDisplay(&display_id, VI::DisplayName{"Default"})); | ||
| 68 | R_TRY(m_manager_display_service->CreateManagedLayer( | ||
| 69 | out_layer_id, 0, display_id, Service::AppletResourceUserId{m_process->GetProcessId()})); | ||
| 70 | |||
| 71 | m_manager_display_service->SetLayerVisibility(m_visible, *out_layer_id); | ||
| 72 | m_managed_display_layers.emplace(*out_layer_id); | ||
| 73 | |||
| 74 | R_SUCCEED(); | ||
| 75 | } | ||
| 76 | |||
| 77 | Result DisplayLayerManager::CreateManagedDisplaySeparableLayer(u64* out_layer_id, | ||
| 78 | u64* out_recording_layer_id) { | ||
| 79 | R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed); | ||
| 80 | |||
| 81 | // TODO(Subv): Find out how AM determines the display to use, for now just | ||
| 82 | // create the layer in the Default display. | ||
| 83 | // This calls nn::vi::CreateRecordingLayer() which creates another layer. | ||
| 84 | // Currently we do not support more than 1 layer per display, output 1 layer id for now. | ||
| 85 | // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse | ||
| 86 | // side effects. | ||
| 87 | *out_recording_layer_id = 0; | ||
| 88 | R_RETURN(this->CreateManagedDisplayLayer(out_layer_id)); | ||
| 89 | } | ||
| 90 | |||
| 91 | Result DisplayLayerManager::IsSystemBufferSharingEnabled() { | ||
| 92 | // Succeed if already enabled. | ||
| 93 | R_SUCCEED_IF(m_buffer_sharing_enabled); | ||
| 94 | |||
| 95 | // Ensure we can access shared layers. | ||
| 96 | R_UNLESS(m_manager_display_service != nullptr, VI::ResultOperationFailed); | ||
| 97 | R_UNLESS(m_applet_id != AppletId::Application, VI::ResultPermissionDenied); | ||
| 98 | |||
| 99 | // Create the shared layer. | ||
| 100 | u64 display_id; | ||
| 101 | R_TRY(m_display_service->OpenDisplay(&display_id, VI::DisplayName{"Default"})); | ||
| 102 | R_TRY(m_manager_display_service->CreateSharedLayerSession(m_process, &m_system_shared_buffer_id, | ||
| 103 | &m_system_shared_layer_id, display_id, | ||
| 104 | m_blending_enabled)); | ||
| 105 | |||
| 106 | // We succeeded, so set up remaining state. | ||
| 107 | m_buffer_sharing_enabled = true; | ||
| 108 | m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id); | ||
| 109 | R_SUCCEED(); | ||
| 110 | } | ||
| 111 | |||
| 112 | Result DisplayLayerManager::GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id, | ||
| 113 | u64* out_system_shared_layer_id) { | ||
| 114 | R_TRY(this->IsSystemBufferSharingEnabled()); | ||
| 115 | |||
| 116 | *out_system_shared_buffer_id = m_system_shared_buffer_id; | ||
| 117 | *out_system_shared_layer_id = m_system_shared_layer_id; | ||
| 118 | |||
| 119 | R_SUCCEED(); | ||
| 120 | } | ||
| 121 | |||
| 122 | void DisplayLayerManager::SetWindowVisibility(bool visible) { | ||
| 123 | if (m_visible == visible) { | ||
| 124 | return; | ||
| 125 | } | ||
| 126 | |||
| 127 | m_visible = visible; | ||
| 128 | |||
| 129 | if (m_manager_display_service) { | ||
| 130 | if (m_system_shared_layer_id) { | ||
| 131 | m_manager_display_service->SetLayerVisibility(m_visible, m_system_shared_layer_id); | ||
| 132 | } | ||
| 133 | |||
| 134 | for (const auto layer_id : m_managed_display_layers) { | ||
| 135 | m_manager_display_service->SetLayerVisibility(m_visible, layer_id); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | bool DisplayLayerManager::GetWindowVisibility() const { | ||
| 141 | return m_visible; | ||
| 142 | } | ||
| 143 | |||
| 144 | Result DisplayLayerManager::WriteAppletCaptureBuffer(bool* out_was_written, | ||
| 145 | s32* out_fbshare_layer_index) { | ||
| 146 | R_UNLESS(m_buffer_sharing_enabled, VI::ResultPermissionDenied); | ||
| 147 | R_RETURN(m_display_service->GetContainer()->GetSharedBufferManager()->WriteAppletCaptureBuffer( | ||
| 148 | out_was_written, out_fbshare_layer_index)); | ||
| 149 | } | ||
| 150 | |||
| 151 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/display_layer_manager.h b/src/core/hle/service/am/display_layer_manager.h new file mode 100644 index 000000000..a66509c04 --- /dev/null +++ b/src/core/hle/service/am/display_layer_manager.h | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <set> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/hle/result.h" | ||
| 10 | #include "core/hle/service/am/am_types.h" | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Kernel { | ||
| 17 | class KProcess; | ||
| 18 | } | ||
| 19 | |||
| 20 | namespace Service::VI { | ||
| 21 | class IApplicationDisplayService; | ||
| 22 | class IManagerDisplayService; | ||
| 23 | } // namespace Service::VI | ||
| 24 | |||
| 25 | namespace Service::AM { | ||
| 26 | |||
| 27 | class DisplayLayerManager { | ||
| 28 | public: | ||
| 29 | explicit DisplayLayerManager(); | ||
| 30 | ~DisplayLayerManager(); | ||
| 31 | |||
| 32 | void Initialize(Core::System& system, Kernel::KProcess* process, AppletId applet_id, | ||
| 33 | LibraryAppletMode mode); | ||
| 34 | void Finalize(); | ||
| 35 | |||
| 36 | Result CreateManagedDisplayLayer(u64* out_layer_id); | ||
| 37 | Result CreateManagedDisplaySeparableLayer(u64* out_layer_id, u64* out_recording_layer_id); | ||
| 38 | |||
| 39 | Result IsSystemBufferSharingEnabled(); | ||
| 40 | Result GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id, | ||
| 41 | u64* out_system_shared_layer_id); | ||
| 42 | |||
| 43 | void SetWindowVisibility(bool visible); | ||
| 44 | bool GetWindowVisibility() const; | ||
| 45 | |||
| 46 | Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index); | ||
| 47 | |||
| 48 | private: | ||
| 49 | Kernel::KProcess* m_process{}; | ||
| 50 | std::shared_ptr<VI::IApplicationDisplayService> m_display_service{}; | ||
| 51 | std::shared_ptr<VI::IManagerDisplayService> m_manager_display_service{}; | ||
| 52 | std::set<u64> m_managed_display_layers{}; | ||
| 53 | std::set<u64> m_managed_display_recording_layers{}; | ||
| 54 | u64 m_system_shared_buffer_id{}; | ||
| 55 | u64 m_system_shared_layer_id{}; | ||
| 56 | AppletId m_applet_id{}; | ||
| 57 | bool m_buffer_sharing_enabled{}; | ||
| 58 | bool m_blending_enabled{}; | ||
| 59 | bool m_visible{true}; | ||
| 60 | }; | ||
| 61 | |||
| 62 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/frontend/applet_web_browser.cpp b/src/core/hle/service/am/frontend/applet_web_browser.cpp index bb60260b4..835c20c4e 100644 --- a/src/core/hle/service/am/frontend/applet_web_browser.cpp +++ b/src/core/hle/service/am/frontend/applet_web_browser.cpp | |||
| @@ -22,7 +22,7 @@ | |||
| 22 | #include "core/hle/service/am/frontend/applet_web_browser.h" | 22 | #include "core/hle/service/am/frontend/applet_web_browser.h" |
| 23 | #include "core/hle/service/am/service/storage.h" | 23 | #include "core/hle/service/am/service/storage.h" |
| 24 | #include "core/hle/service/filesystem/filesystem.h" | 24 | #include "core/hle/service/filesystem/filesystem.h" |
| 25 | #include "core/hle/service/ns/iplatform_service_manager.h" | 25 | #include "core/hle/service/ns/platform_service_manager.h" |
| 26 | #include "core/loader/loader.h" | 26 | #include "core/loader/loader.h" |
| 27 | 27 | ||
| 28 | namespace Service::AM::Frontend { | 28 | namespace Service::AM::Frontend { |
diff --git a/src/core/hle/service/am/library_applet_storage.cpp b/src/core/hle/service/am/library_applet_storage.cpp index 46e6c0111..0412c215d 100644 --- a/src/core/hle/service/am/library_applet_storage.cpp +++ b/src/core/hle/service/am/library_applet_storage.cpp | |||
| @@ -70,7 +70,7 @@ public: | |||
| 70 | Result Read(s64 offset, void* buffer, size_t size) override { | 70 | Result Read(s64 offset, void* buffer, size_t size) override { |
| 71 | R_TRY(ValidateOffset(offset, size, m_size)); | 71 | R_TRY(ValidateOffset(offset, size, m_size)); |
| 72 | 72 | ||
| 73 | m_memory.ReadBlock(m_trmem->GetSourceAddress(), buffer, size); | 73 | m_memory.ReadBlock(m_trmem->GetSourceAddress() + offset, buffer, size); |
| 74 | 74 | ||
| 75 | R_SUCCEED(); | 75 | R_SUCCEED(); |
| 76 | } | 76 | } |
| @@ -79,7 +79,7 @@ public: | |||
| 79 | R_UNLESS(m_is_writable, ResultUnknown); | 79 | R_UNLESS(m_is_writable, ResultUnknown); |
| 80 | R_TRY(ValidateOffset(offset, size, m_size)); | 80 | R_TRY(ValidateOffset(offset, size, m_size)); |
| 81 | 81 | ||
| 82 | m_memory.WriteBlock(m_trmem->GetSourceAddress(), buffer, size); | 82 | m_memory.WriteBlock(m_trmem->GetSourceAddress() + offset, buffer, size); |
| 83 | 83 | ||
| 84 | R_SUCCEED(); | 84 | R_SUCCEED(); |
| 85 | } | 85 | } |
diff --git a/src/core/hle/service/am/managed_layer_holder.cpp b/src/core/hle/service/am/managed_layer_holder.cpp deleted file mode 100644 index 61eb8641a..000000000 --- a/src/core/hle/service/am/managed_layer_holder.cpp +++ /dev/null | |||
| @@ -1,59 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/am/managed_layer_holder.h" | ||
| 5 | #include "core/hle/service/nvnflinger/nvnflinger.h" | ||
| 6 | |||
| 7 | namespace Service::AM { | ||
| 8 | |||
| 9 | ManagedLayerHolder::ManagedLayerHolder() = default; | ||
| 10 | ManagedLayerHolder::~ManagedLayerHolder() { | ||
| 11 | if (!m_nvnflinger) { | ||
| 12 | return; | ||
| 13 | } | ||
| 14 | |||
| 15 | for (const auto& layer : m_managed_display_layers) { | ||
| 16 | m_nvnflinger->DestroyLayer(layer); | ||
| 17 | } | ||
| 18 | |||
| 19 | for (const auto& layer : m_managed_display_recording_layers) { | ||
| 20 | m_nvnflinger->DestroyLayer(layer); | ||
| 21 | } | ||
| 22 | |||
| 23 | m_nvnflinger = nullptr; | ||
| 24 | } | ||
| 25 | |||
| 26 | void ManagedLayerHolder::Initialize(Nvnflinger::Nvnflinger* nvnflinger) { | ||
| 27 | m_nvnflinger = nvnflinger; | ||
| 28 | } | ||
| 29 | |||
| 30 | void ManagedLayerHolder::CreateManagedDisplayLayer(u64* out_layer) { | ||
| 31 | // TODO(Subv): Find out how AM determines the display to use, for now just | ||
| 32 | // create the layer in the Default display. | ||
| 33 | const auto display_id = m_nvnflinger->OpenDisplay("Default"); | ||
| 34 | const auto layer_id = m_nvnflinger->CreateLayer(*display_id); | ||
| 35 | |||
| 36 | m_managed_display_layers.emplace(*layer_id); | ||
| 37 | |||
| 38 | *out_layer = *layer_id; | ||
| 39 | } | ||
| 40 | |||
| 41 | void ManagedLayerHolder::CreateManagedDisplaySeparableLayer(u64* out_layer, | ||
| 42 | u64* out_recording_layer) { | ||
| 43 | // TODO(Subv): Find out how AM determines the display to use, for now just | ||
| 44 | // create the layer in the Default display. | ||
| 45 | // This calls nn::vi::CreateRecordingLayer() which creates another layer. | ||
| 46 | // Currently we do not support more than 1 layer per display, output 1 layer id for now. | ||
| 47 | // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse | ||
| 48 | // side effects. | ||
| 49 | // TODO: Support multiple layers | ||
| 50 | const auto display_id = m_nvnflinger->OpenDisplay("Default"); | ||
| 51 | const auto layer_id = m_nvnflinger->CreateLayer(*display_id); | ||
| 52 | |||
| 53 | m_managed_display_layers.emplace(*layer_id); | ||
| 54 | |||
| 55 | *out_layer = *layer_id; | ||
| 56 | *out_recording_layer = 0; | ||
| 57 | } | ||
| 58 | |||
| 59 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/managed_layer_holder.h b/src/core/hle/service/am/managed_layer_holder.h deleted file mode 100644 index f7fe03f24..000000000 --- a/src/core/hle/service/am/managed_layer_holder.h +++ /dev/null | |||
| @@ -1,32 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <set> | ||
| 7 | |||
| 8 | #include "common/common_funcs.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | namespace Service::Nvnflinger { | ||
| 12 | class Nvnflinger; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::AM { | ||
| 16 | |||
| 17 | class ManagedLayerHolder { | ||
| 18 | public: | ||
| 19 | ManagedLayerHolder(); | ||
| 20 | ~ManagedLayerHolder(); | ||
| 21 | |||
| 22 | void Initialize(Nvnflinger::Nvnflinger* nvnflinger); | ||
| 23 | void CreateManagedDisplayLayer(u64* out_layer); | ||
| 24 | void CreateManagedDisplaySeparableLayer(u64* out_layer, u64* out_recording_layer); | ||
| 25 | |||
| 26 | private: | ||
| 27 | Nvnflinger::Nvnflinger* m_nvnflinger{}; | ||
| 28 | std::set<u64> m_managed_display_layers{}; | ||
| 29 | std::set<u64> m_managed_display_recording_layers{}; | ||
| 30 | }; | ||
| 31 | |||
| 32 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/process.cpp b/src/core/hle/service/am/process.cpp index 992c50713..388d2045c 100644 --- a/src/core/hle/service/am/process.cpp +++ b/src/core/hle/service/am/process.cpp | |||
| @@ -68,7 +68,9 @@ bool Process::Initialize(u64 program_id, u8 minimum_key_generation, u8 maximum_k | |||
| 68 | Kernel::KProcess::Register(m_system.Kernel(), process); | 68 | Kernel::KProcess::Register(m_system.Kernel(), process); |
| 69 | 69 | ||
| 70 | // On exit, ensure we free the additional reference to the process. | 70 | // On exit, ensure we free the additional reference to the process. |
| 71 | SCOPE_EXIT({ process->Close(); }); | 71 | SCOPE_EXIT { |
| 72 | process->Close(); | ||
| 73 | }; | ||
| 72 | 74 | ||
| 73 | // Insert process modules into memory. | 75 | // Insert process modules into memory. |
| 74 | const auto [load_result, load_parameters] = app_loader->Load(*process, m_system); | 76 | const auto [load_result, load_parameters] = app_loader->Load(*process, m_system); |
diff --git a/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp b/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp index eebd90ba2..21747783a 100644 --- a/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp +++ b/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp | |||
| @@ -10,9 +10,8 @@ | |||
| 10 | 10 | ||
| 11 | namespace Service::AM { | 11 | namespace Service::AM { |
| 12 | 12 | ||
| 13 | IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_, | 13 | IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_) |
| 14 | Nvnflinger::Nvnflinger& nvnflinger) | 14 | : ServiceFramework{system_, "appletAE"} { |
| 15 | : ServiceFramework{system_, "appletAE"}, m_nvnflinger{nvnflinger} { | ||
| 16 | // clang-format off | 15 | // clang-format off |
| 17 | static const FunctionInfo functions[] = { | 16 | static const FunctionInfo functions[] = { |
| 18 | {100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"}, | 17 | {100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"}, |
| @@ -37,8 +36,8 @@ Result IAllSystemAppletProxiesService::OpenSystemAppletProxy( | |||
| 37 | LOG_DEBUG(Service_AM, "called"); | 36 | LOG_DEBUG(Service_AM, "called"); |
| 38 | 37 | ||
| 39 | if (const auto applet = this->GetAppletFromProcessId(pid); applet) { | 38 | if (const auto applet = this->GetAppletFromProcessId(pid); applet) { |
| 40 | *out_system_applet_proxy = std::make_shared<ISystemAppletProxy>( | 39 | *out_system_applet_proxy = |
| 41 | system, applet, process_handle.Get(), m_nvnflinger); | 40 | std::make_shared<ISystemAppletProxy>(system, applet, process_handle.Get()); |
| 42 | R_SUCCEED(); | 41 | R_SUCCEED(); |
| 43 | } else { | 42 | } else { |
| 44 | UNIMPLEMENTED(); | 43 | UNIMPLEMENTED(); |
| @@ -53,8 +52,8 @@ Result IAllSystemAppletProxiesService::OpenLibraryAppletProxy( | |||
| 53 | LOG_DEBUG(Service_AM, "called"); | 52 | LOG_DEBUG(Service_AM, "called"); |
| 54 | 53 | ||
| 55 | if (const auto applet = this->GetAppletFromProcessId(pid); applet) { | 54 | if (const auto applet = this->GetAppletFromProcessId(pid); applet) { |
| 56 | *out_library_applet_proxy = std::make_shared<ILibraryAppletProxy>( | 55 | *out_library_applet_proxy = |
| 57 | system, applet, process_handle.Get(), m_nvnflinger); | 56 | std::make_shared<ILibraryAppletProxy>(system, applet, process_handle.Get()); |
| 58 | R_SUCCEED(); | 57 | R_SUCCEED(); |
| 59 | } else { | 58 | } else { |
| 60 | UNIMPLEMENTED(); | 59 | UNIMPLEMENTED(); |
diff --git a/src/core/hle/service/am/service/all_system_applet_proxies_service.h b/src/core/hle/service/am/service/all_system_applet_proxies_service.h index 38b1ca2ea..0e2dcb86d 100644 --- a/src/core/hle/service/am/service/all_system_applet_proxies_service.h +++ b/src/core/hle/service/am/service/all_system_applet_proxies_service.h | |||
| @@ -8,10 +8,6 @@ | |||
| 8 | 8 | ||
| 9 | namespace Service { | 9 | namespace Service { |
| 10 | 10 | ||
| 11 | namespace Nvnflinger { | ||
| 12 | class Nvnflinger; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace AM { | 11 | namespace AM { |
| 16 | 12 | ||
| 17 | struct Applet; | 13 | struct Applet; |
| @@ -22,8 +18,7 @@ class ISystemAppletProxy; | |||
| 22 | class IAllSystemAppletProxiesService final | 18 | class IAllSystemAppletProxiesService final |
| 23 | : public ServiceFramework<IAllSystemAppletProxiesService> { | 19 | : public ServiceFramework<IAllSystemAppletProxiesService> { |
| 24 | public: | 20 | public: |
| 25 | explicit IAllSystemAppletProxiesService(Core::System& system_, | 21 | explicit IAllSystemAppletProxiesService(Core::System& system_); |
| 26 | Nvnflinger::Nvnflinger& nvnflinger); | ||
| 27 | ~IAllSystemAppletProxiesService() override; | 22 | ~IAllSystemAppletProxiesService() override; |
| 28 | 23 | ||
| 29 | private: | 24 | private: |
| @@ -40,7 +35,6 @@ private: | |||
| 40 | 35 | ||
| 41 | private: | 36 | private: |
| 42 | std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid); | 37 | std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid); |
| 43 | Nvnflinger::Nvnflinger& m_nvnflinger; | ||
| 44 | }; | 38 | }; |
| 45 | 39 | ||
| 46 | } // namespace AM | 40 | } // namespace AM |
diff --git a/src/core/hle/service/am/service/application_functions.cpp b/src/core/hle/service/am/service/application_functions.cpp index b788fddd4..cb53b07e0 100644 --- a/src/core/hle/service/am/service/application_functions.cpp +++ b/src/core/hle/service/am/service/application_functions.cpp | |||
| @@ -15,7 +15,9 @@ | |||
| 15 | #include "core/hle/service/cmif_serialization.h" | 15 | #include "core/hle/service/cmif_serialization.h" |
| 16 | #include "core/hle/service/filesystem/filesystem.h" | 16 | #include "core/hle/service/filesystem/filesystem.h" |
| 17 | #include "core/hle/service/filesystem/save_data_controller.h" | 17 | #include "core/hle/service/filesystem/save_data_controller.h" |
| 18 | #include "core/hle/service/ns/ns.h" | 18 | #include "core/hle/service/glue/glue_manager.h" |
| 19 | #include "core/hle/service/ns/application_manager_interface.h" | ||
| 20 | #include "core/hle/service/ns/service_getter_interface.h" | ||
| 19 | #include "core/hle/service/sm/sm.h" | 21 | #include "core/hle/service/sm/sm.h" |
| 20 | 22 | ||
| 21 | namespace Service::AM { | 23 | namespace Service::AM { |
| @@ -40,7 +42,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ | |||
| 40 | {26, D<&IApplicationFunctions::GetSaveDataSize>, "GetSaveDataSize"}, | 42 | {26, D<&IApplicationFunctions::GetSaveDataSize>, "GetSaveDataSize"}, |
| 41 | {27, D<&IApplicationFunctions::CreateCacheStorage>, "CreateCacheStorage"}, | 43 | {27, D<&IApplicationFunctions::CreateCacheStorage>, "CreateCacheStorage"}, |
| 42 | {28, D<&IApplicationFunctions::GetSaveDataSizeMax>, "GetSaveDataSizeMax"}, | 44 | {28, D<&IApplicationFunctions::GetSaveDataSizeMax>, "GetSaveDataSizeMax"}, |
| 43 | {29, nullptr, "GetCacheStorageMax"}, | 45 | {29, D<&IApplicationFunctions::GetCacheStorageMax>, "GetCacheStorageMax"}, |
| 44 | {30, D<&IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed>, "BeginBlockingHomeButtonShortAndLongPressed"}, | 46 | {30, D<&IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed>, "BeginBlockingHomeButtonShortAndLongPressed"}, |
| 45 | {31, D<&IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed>, "EndBlockingHomeButtonShortAndLongPressed"}, | 47 | {31, D<&IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed>, "EndBlockingHomeButtonShortAndLongPressed"}, |
| 46 | {32, D<&IApplicationFunctions::BeginBlockingHomeButton>, "BeginBlockingHomeButton"}, | 48 | {32, D<&IApplicationFunctions::BeginBlockingHomeButton>, "BeginBlockingHomeButton"}, |
| @@ -162,11 +164,13 @@ Result IApplicationFunctions::GetDesiredLanguage(Out<u64> out_language_code) { | |||
| 162 | 164 | ||
| 163 | // Call IApplicationManagerInterface implementation. | 165 | // Call IApplicationManagerInterface implementation. |
| 164 | auto& service_manager = system.ServiceManager(); | 166 | auto& service_manager = system.ServiceManager(); |
| 165 | auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2"); | 167 | auto ns_am2 = service_manager.GetService<NS::IServiceGetterInterface>("ns:am2"); |
| 166 | auto app_man = ns_am2->GetApplicationManagerInterface(); | 168 | |
| 169 | std::shared_ptr<NS::IApplicationManagerInterface> app_man; | ||
| 170 | R_TRY(ns_am2->GetApplicationManagerInterface(&app_man)); | ||
| 167 | 171 | ||
| 168 | // Get desired application language | 172 | // Get desired application language |
| 169 | u8 desired_language{}; | 173 | NS::ApplicationLanguage desired_language{}; |
| 170 | R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages)); | 174 | R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages)); |
| 171 | 175 | ||
| 172 | // Convert to settings language code. | 176 | // Convert to settings language code. |
| @@ -267,6 +271,22 @@ Result IApplicationFunctions::GetSaveDataSizeMax(Out<u64> out_max_normal_size, | |||
| 267 | R_SUCCEED(); | 271 | R_SUCCEED(); |
| 268 | } | 272 | } |
| 269 | 273 | ||
| 274 | Result IApplicationFunctions::GetCacheStorageMax(Out<u32> out_cache_storage_index_max, | ||
| 275 | Out<u64> out_max_journal_size) { | ||
| 276 | LOG_DEBUG(Service_AM, "called"); | ||
| 277 | |||
| 278 | std::vector<u8> nacp; | ||
| 279 | R_TRY(system.GetARPManager().GetControlProperty(&nacp, m_applet->program_id)); | ||
| 280 | |||
| 281 | auto raw_nacp = std::make_unique<FileSys::RawNACP>(); | ||
| 282 | std::memcpy(raw_nacp.get(), nacp.data(), std::min(sizeof(*raw_nacp), nacp.size())); | ||
| 283 | |||
| 284 | *out_cache_storage_index_max = static_cast<u32>(raw_nacp->cache_storage_max_index); | ||
| 285 | *out_max_journal_size = static_cast<u64>(raw_nacp->cache_storage_data_and_journal_max_size); | ||
| 286 | |||
| 287 | R_SUCCEED(); | ||
| 288 | } | ||
| 289 | |||
| 270 | Result IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(s64 unused) { | 290 | Result IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(s64 unused) { |
| 271 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 291 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 272 | 292 | ||
diff --git a/src/core/hle/service/am/service/application_functions.h b/src/core/hle/service/am/service/application_functions.h index 3548202f8..10025a152 100644 --- a/src/core/hle/service/am/service/application_functions.h +++ b/src/core/hle/service/am/service/application_functions.h | |||
| @@ -40,6 +40,7 @@ private: | |||
| 40 | Result CreateCacheStorage(Out<u32> out_target_media, Out<u64> out_required_size, u16 index, | 40 | Result CreateCacheStorage(Out<u32> out_target_media, Out<u64> out_required_size, u16 index, |
| 41 | u64 normal_size, u64 journal_size); | 41 | u64 normal_size, u64 journal_size); |
| 42 | Result GetSaveDataSizeMax(Out<u64> out_max_normal_size, Out<u64> out_max_journal_size); | 42 | Result GetSaveDataSizeMax(Out<u64> out_max_normal_size, Out<u64> out_max_journal_size); |
| 43 | Result GetCacheStorageMax(Out<u32> out_cache_storage_index_max, Out<u64> out_max_journal_size); | ||
| 43 | Result BeginBlockingHomeButtonShortAndLongPressed(s64 unused); | 44 | Result BeginBlockingHomeButtonShortAndLongPressed(s64 unused); |
| 44 | Result EndBlockingHomeButtonShortAndLongPressed(); | 45 | Result EndBlockingHomeButtonShortAndLongPressed(); |
| 45 | Result BeginBlockingHomeButton(s64 timeout_ns); | 46 | Result BeginBlockingHomeButton(s64 timeout_ns); |
diff --git a/src/core/hle/service/am/service/application_proxy.cpp b/src/core/hle/service/am/service/application_proxy.cpp index 776f4552b..19d6a3b89 100644 --- a/src/core/hle/service/am/service/application_proxy.cpp +++ b/src/core/hle/service/am/service/application_proxy.cpp | |||
| @@ -17,9 +17,9 @@ | |||
| 17 | namespace Service::AM { | 17 | namespace Service::AM { |
| 18 | 18 | ||
| 19 | IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet, | 19 | IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet, |
| 20 | Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger) | 20 | Kernel::KProcess* process) |
| 21 | : ServiceFramework{system_, "IApplicationProxy"}, | 21 | : ServiceFramework{system_, "IApplicationProxy"}, m_process{process}, m_applet{ |
| 22 | m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} { | 22 | std::move(applet)} { |
| 23 | // clang-format off | 23 | // clang-format off |
| 24 | static const FunctionInfo functions[] = { | 24 | static const FunctionInfo functions[] = { |
| 25 | {0, D<&IApplicationProxy::GetCommonStateGetter>, "GetCommonStateGetter"}, | 25 | {0, D<&IApplicationProxy::GetCommonStateGetter>, "GetCommonStateGetter"}, |
| @@ -77,8 +77,7 @@ Result IApplicationProxy::GetWindowController( | |||
| 77 | Result IApplicationProxy::GetSelfController( | 77 | Result IApplicationProxy::GetSelfController( |
| 78 | Out<SharedPointer<ISelfController>> out_self_controller) { | 78 | Out<SharedPointer<ISelfController>> out_self_controller) { |
| 79 | LOG_DEBUG(Service_AM, "called"); | 79 | LOG_DEBUG(Service_AM, "called"); |
| 80 | *out_self_controller = | 80 | *out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process); |
| 81 | std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger); | ||
| 82 | R_SUCCEED(); | 81 | R_SUCCEED(); |
| 83 | } | 82 | } |
| 84 | 83 | ||
diff --git a/src/core/hle/service/am/service/application_proxy.h b/src/core/hle/service/am/service/application_proxy.h index 1ebc593ba..6da350df7 100644 --- a/src/core/hle/service/am/service/application_proxy.h +++ b/src/core/hle/service/am/service/application_proxy.h | |||
| @@ -22,7 +22,7 @@ class IWindowController; | |||
| 22 | class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { | 22 | class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { |
| 23 | public: | 23 | public: |
| 24 | explicit IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet, | 24 | explicit IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet, |
| 25 | Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger); | 25 | Kernel::KProcess* process); |
| 26 | ~IApplicationProxy(); | 26 | ~IApplicationProxy(); |
| 27 | 27 | ||
| 28 | private: | 28 | private: |
| @@ -40,7 +40,6 @@ private: | |||
| 40 | Out<SharedPointer<IApplicationFunctions>> out_application_functions); | 40 | Out<SharedPointer<IApplicationFunctions>> out_application_functions); |
| 41 | 41 | ||
| 42 | private: | 42 | private: |
| 43 | Nvnflinger::Nvnflinger& m_nvnflinger; | ||
| 44 | Kernel::KProcess* const m_process; | 43 | Kernel::KProcess* const m_process; |
| 45 | const std::shared_ptr<Applet> m_applet; | 44 | const std::shared_ptr<Applet> m_applet; |
| 46 | }; | 45 | }; |
diff --git a/src/core/hle/service/am/service/application_proxy_service.cpp b/src/core/hle/service/am/service/application_proxy_service.cpp index 36d4478df..fd66e77b9 100644 --- a/src/core/hle/service/am/service/application_proxy_service.cpp +++ b/src/core/hle/service/am/service/application_proxy_service.cpp | |||
| @@ -10,9 +10,8 @@ | |||
| 10 | 10 | ||
| 11 | namespace Service::AM { | 11 | namespace Service::AM { |
| 12 | 12 | ||
| 13 | IApplicationProxyService::IApplicationProxyService(Core::System& system_, | 13 | IApplicationProxyService::IApplicationProxyService(Core::System& system_) |
| 14 | Nvnflinger::Nvnflinger& nvnflinger) | 14 | : ServiceFramework{system_, "appletOE"} { |
| 15 | : ServiceFramework{system_, "appletOE"}, m_nvnflinger{nvnflinger} { | ||
| 16 | static const FunctionInfo functions[] = { | 15 | static const FunctionInfo functions[] = { |
| 17 | {0, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy"}, | 16 | {0, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy"}, |
| 18 | }; | 17 | }; |
| @@ -28,7 +27,7 @@ Result IApplicationProxyService::OpenApplicationProxy( | |||
| 28 | 27 | ||
| 29 | if (const auto applet = this->GetAppletFromProcessId(pid)) { | 28 | if (const auto applet = this->GetAppletFromProcessId(pid)) { |
| 30 | *out_application_proxy = | 29 | *out_application_proxy = |
| 31 | std::make_shared<IApplicationProxy>(system, applet, process_handle.Get(), m_nvnflinger); | 30 | std::make_shared<IApplicationProxy>(system, applet, process_handle.Get()); |
| 32 | R_SUCCEED(); | 31 | R_SUCCEED(); |
| 33 | } else { | 32 | } else { |
| 34 | UNIMPLEMENTED(); | 33 | UNIMPLEMENTED(); |
diff --git a/src/core/hle/service/am/service/application_proxy_service.h b/src/core/hle/service/am/service/application_proxy_service.h index 1c1d32d0b..8efafa31a 100644 --- a/src/core/hle/service/am/service/application_proxy_service.h +++ b/src/core/hle/service/am/service/application_proxy_service.h | |||
| @@ -8,10 +8,6 @@ | |||
| 8 | 8 | ||
| 9 | namespace Service { | 9 | namespace Service { |
| 10 | 10 | ||
| 11 | namespace Nvnflinger { | ||
| 12 | class Nvnflinger; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace AM { | 11 | namespace AM { |
| 16 | 12 | ||
| 17 | struct Applet; | 13 | struct Applet; |
| @@ -19,7 +15,7 @@ class IApplicationProxy; | |||
| 19 | 15 | ||
| 20 | class IApplicationProxyService final : public ServiceFramework<IApplicationProxyService> { | 16 | class IApplicationProxyService final : public ServiceFramework<IApplicationProxyService> { |
| 21 | public: | 17 | public: |
| 22 | explicit IApplicationProxyService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger); | 18 | explicit IApplicationProxyService(Core::System& system_); |
| 23 | ~IApplicationProxyService() override; | 19 | ~IApplicationProxyService() override; |
| 24 | 20 | ||
| 25 | private: | 21 | private: |
| @@ -28,7 +24,6 @@ private: | |||
| 28 | 24 | ||
| 29 | private: | 25 | private: |
| 30 | std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid); | 26 | std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid); |
| 31 | Nvnflinger::Nvnflinger& m_nvnflinger; | ||
| 32 | }; | 27 | }; |
| 33 | 28 | ||
| 34 | } // namespace AM | 29 | } // namespace AM |
diff --git a/src/core/hle/service/am/service/display_controller.cpp b/src/core/hle/service/am/service/display_controller.cpp index 249c73dfb..ed71f9093 100644 --- a/src/core/hle/service/am/service/display_controller.cpp +++ b/src/core/hle/service/am/service/display_controller.cpp | |||
| @@ -69,7 +69,7 @@ Result IDisplayController::ClearCaptureBuffer(bool unknown0, s32 fbshare_layer_i | |||
| 69 | Result IDisplayController::AcquireLastForegroundCaptureSharedBuffer( | 69 | Result IDisplayController::AcquireLastForegroundCaptureSharedBuffer( |
| 70 | Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) { | 70 | Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) { |
| 71 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 71 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 72 | R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written, | 72 | R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written, |
| 73 | out_fbshare_layer_index)); | 73 | out_fbshare_layer_index)); |
| 74 | } | 74 | } |
| 75 | 75 | ||
| @@ -81,7 +81,7 @@ Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() { | |||
| 81 | Result IDisplayController::AcquireCallerAppletCaptureSharedBuffer( | 81 | Result IDisplayController::AcquireCallerAppletCaptureSharedBuffer( |
| 82 | Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) { | 82 | Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) { |
| 83 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 83 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 84 | R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written, | 84 | R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written, |
| 85 | out_fbshare_layer_index)); | 85 | out_fbshare_layer_index)); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| @@ -93,7 +93,7 @@ Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() { | |||
| 93 | Result IDisplayController::AcquireLastApplicationCaptureSharedBuffer( | 93 | Result IDisplayController::AcquireLastApplicationCaptureSharedBuffer( |
| 94 | Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) { | 94 | Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) { |
| 95 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 95 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 96 | R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written, | 96 | R_RETURN(applet->display_layer_manager.WriteAppletCaptureBuffer(out_was_written, |
| 97 | out_fbshare_layer_index)); | 97 | out_fbshare_layer_index)); |
| 98 | } | 98 | } |
| 99 | 99 | ||
diff --git a/src/core/hle/service/am/service/library_applet_creator.cpp b/src/core/hle/service/am/service/library_applet_creator.cpp index 166637d60..c97358d81 100644 --- a/src/core/hle/service/am/service/library_applet_creator.cpp +++ b/src/core/hle/service/am/service/library_applet_creator.cpp | |||
| @@ -135,7 +135,7 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system, | |||
| 135 | case LibraryAppletMode::AllForegroundInitiallyHidden: | 135 | case LibraryAppletMode::AllForegroundInitiallyHidden: |
| 136 | applet->hid_registration.EnableAppletToGetInput(false); | 136 | applet->hid_registration.EnableAppletToGetInput(false); |
| 137 | applet->focus_state = FocusState::NotInFocus; | 137 | applet->focus_state = FocusState::NotInFocus; |
| 138 | applet->system_buffer_manager.SetWindowVisibility(false); | 138 | applet->display_layer_manager.SetWindowVisibility(false); |
| 139 | applet->message_queue.PushMessage(AppletMessage::ChangeIntoBackground); | 139 | applet->message_queue.PushMessage(AppletMessage::ChangeIntoBackground); |
| 140 | break; | 140 | break; |
| 141 | } | 141 | } |
diff --git a/src/core/hle/service/am/service/library_applet_proxy.cpp b/src/core/hle/service/am/service/library_applet_proxy.cpp index bcb44a71c..58e709347 100644 --- a/src/core/hle/service/am/service/library_applet_proxy.cpp +++ b/src/core/hle/service/am/service/library_applet_proxy.cpp | |||
| @@ -19,10 +19,9 @@ | |||
| 19 | namespace Service::AM { | 19 | namespace Service::AM { |
| 20 | 20 | ||
| 21 | ILibraryAppletProxy::ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet, | 21 | ILibraryAppletProxy::ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet, |
| 22 | Kernel::KProcess* process, | 22 | Kernel::KProcess* process) |
| 23 | Nvnflinger::Nvnflinger& nvnflinger) | 23 | : ServiceFramework{system_, "ILibraryAppletProxy"}, m_process{process}, m_applet{ |
| 24 | : ServiceFramework{system_, "ILibraryAppletProxy"}, | 24 | std::move(applet)} { |
| 25 | m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} { | ||
| 26 | // clang-format off | 25 | // clang-format off |
| 27 | static const FunctionInfo functions[] = { | 26 | static const FunctionInfo functions[] = { |
| 28 | {0, D<&ILibraryAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"}, | 27 | {0, D<&ILibraryAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"}, |
| @@ -83,8 +82,7 @@ Result ILibraryAppletProxy::GetWindowController( | |||
| 83 | Result ILibraryAppletProxy::GetSelfController( | 82 | Result ILibraryAppletProxy::GetSelfController( |
| 84 | Out<SharedPointer<ISelfController>> out_self_controller) { | 83 | Out<SharedPointer<ISelfController>> out_self_controller) { |
| 85 | LOG_DEBUG(Service_AM, "called"); | 84 | LOG_DEBUG(Service_AM, "called"); |
| 86 | *out_self_controller = | 85 | *out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process); |
| 87 | std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger); | ||
| 88 | R_SUCCEED(); | 86 | R_SUCCEED(); |
| 89 | } | 87 | } |
| 90 | 88 | ||
diff --git a/src/core/hle/service/am/service/library_applet_proxy.h b/src/core/hle/service/am/service/library_applet_proxy.h index 23e64e295..7d0714b85 100644 --- a/src/core/hle/service/am/service/library_applet_proxy.h +++ b/src/core/hle/service/am/service/library_applet_proxy.h | |||
| @@ -25,7 +25,7 @@ class IWindowController; | |||
| 25 | class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { | 25 | class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { |
| 26 | public: | 26 | public: |
| 27 | explicit ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet, | 27 | explicit ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet, |
| 28 | Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger); | 28 | Kernel::KProcess* process); |
| 29 | ~ILibraryAppletProxy(); | 29 | ~ILibraryAppletProxy(); |
| 30 | 30 | ||
| 31 | private: | 31 | private: |
| @@ -47,7 +47,6 @@ private: | |||
| 47 | Result GetGlobalStateController( | 47 | Result GetGlobalStateController( |
| 48 | Out<SharedPointer<IGlobalStateController>> out_global_state_controller); | 48 | Out<SharedPointer<IGlobalStateController>> out_global_state_controller); |
| 49 | 49 | ||
| 50 | Nvnflinger::Nvnflinger& m_nvnflinger; | ||
| 51 | Kernel::KProcess* const m_process; | 50 | Kernel::KProcess* const m_process; |
| 52 | const std::shared_ptr<Applet> m_applet; | 51 | const std::shared_ptr<Applet> m_applet; |
| 53 | }; | 52 | }; |
diff --git a/src/core/hle/service/am/service/library_applet_self_accessor.cpp b/src/core/hle/service/am/service/library_applet_self_accessor.cpp index 7a3a86e88..330eb26f0 100644 --- a/src/core/hle/service/am/service/library_applet_self_accessor.cpp +++ b/src/core/hle/service/am/service/library_applet_self_accessor.cpp | |||
| @@ -14,7 +14,8 @@ | |||
| 14 | #include "core/hle/service/cmif_serialization.h" | 14 | #include "core/hle/service/cmif_serialization.h" |
| 15 | #include "core/hle/service/filesystem/filesystem.h" | 15 | #include "core/hle/service/filesystem/filesystem.h" |
| 16 | #include "core/hle/service/glue/glue_manager.h" | 16 | #include "core/hle/service/glue/glue_manager.h" |
| 17 | #include "core/hle/service/ns/ns.h" | 17 | #include "core/hle/service/ns/application_manager_interface.h" |
| 18 | #include "core/hle/service/ns/service_getter_interface.h" | ||
| 18 | #include "core/hle/service/sm/sm.h" | 19 | #include "core/hle/service/sm/sm.h" |
| 19 | 20 | ||
| 20 | namespace Service::AM { | 21 | namespace Service::AM { |
| @@ -256,11 +257,13 @@ Result ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage( | |||
| 256 | 257 | ||
| 257 | // Call IApplicationManagerInterface implementation. | 258 | // Call IApplicationManagerInterface implementation. |
| 258 | auto& service_manager = system.ServiceManager(); | 259 | auto& service_manager = system.ServiceManager(); |
| 259 | auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2"); | 260 | auto ns_am2 = service_manager.GetService<NS::IServiceGetterInterface>("ns:am2"); |
| 260 | auto app_man = ns_am2->GetApplicationManagerInterface(); | 261 | |
| 262 | std::shared_ptr<NS::IApplicationManagerInterface> app_man; | ||
| 263 | R_TRY(ns_am2->GetApplicationManagerInterface(&app_man)); | ||
| 261 | 264 | ||
| 262 | // Get desired application language | 265 | // Get desired application language |
| 263 | u8 desired_language{}; | 266 | NS::ApplicationLanguage desired_language{}; |
| 264 | R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages)); | 267 | R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages)); |
| 265 | 268 | ||
| 266 | // Convert to settings language code. | 269 | // Convert to settings language code. |
| @@ -284,17 +287,17 @@ Result ILibraryAppletSelfAccessor::GetCurrentApplicationId(Out<u64> out_applicat | |||
| 284 | } | 287 | } |
| 285 | 288 | ||
| 286 | Result ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers( | 289 | Result ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers( |
| 287 | Out<bool> out_no_users_available, Out<s32> out_users_count, | 290 | Out<bool> out_can_select_any_user, Out<s32> out_users_count, |
| 288 | OutArray<Common::UUID, BufferAttr_HipcMapAlias> out_users) { | 291 | OutArray<Common::UUID, BufferAttr_HipcMapAlias> out_users) { |
| 289 | const Service::Account::ProfileManager manager{}; | 292 | const Service::Account::ProfileManager manager{}; |
| 290 | 293 | ||
| 291 | *out_no_users_available = true; | 294 | *out_can_select_any_user = false; |
| 292 | *out_users_count = -1; | 295 | *out_users_count = -1; |
| 293 | 296 | ||
| 294 | LOG_INFO(Service_AM, "called"); | 297 | LOG_INFO(Service_AM, "called"); |
| 295 | 298 | ||
| 296 | if (manager.GetUserCount() > 0) { | 299 | if (manager.GetUserCount() > 0) { |
| 297 | *out_no_users_available = false; | 300 | *out_can_select_any_user = true; |
| 298 | *out_users_count = static_cast<s32>(manager.GetUserCount()); | 301 | *out_users_count = static_cast<s32>(manager.GetUserCount()); |
| 299 | 302 | ||
| 300 | const auto users = manager.GetAllUsers(); | 303 | const auto users = manager.GetAllUsers(); |
diff --git a/src/core/hle/service/am/service/library_applet_self_accessor.h b/src/core/hle/service/am/service/library_applet_self_accessor.h index a9743569f..3e60393c2 100644 --- a/src/core/hle/service/am/service/library_applet_self_accessor.h +++ b/src/core/hle/service/am/service/library_applet_self_accessor.h | |||
| @@ -71,7 +71,7 @@ private: | |||
| 71 | ErrorCode error_code, InLargeData<ErrorContext, BufferAttr_HipcMapAlias> error_context); | 71 | ErrorCode error_code, InLargeData<ErrorContext, BufferAttr_HipcMapAlias> error_context); |
| 72 | Result GetMainAppletApplicationDesiredLanguage(Out<u64> out_desired_language); | 72 | Result GetMainAppletApplicationDesiredLanguage(Out<u64> out_desired_language); |
| 73 | Result GetCurrentApplicationId(Out<u64> out_application_id); | 73 | Result GetCurrentApplicationId(Out<u64> out_application_id); |
| 74 | Result GetMainAppletAvailableUsers(Out<bool> out_no_users_available, Out<s32> out_users_count, | 74 | Result GetMainAppletAvailableUsers(Out<bool> out_can_select_any_user, Out<s32> out_users_count, |
| 75 | OutArray<Common::UUID, BufferAttr_HipcMapAlias> out_users); | 75 | OutArray<Common::UUID, BufferAttr_HipcMapAlias> out_users); |
| 76 | Result ShouldSetGpuTimeSliceManually(Out<bool> out_should_set_gpu_time_slice_manually); | 76 | Result ShouldSetGpuTimeSliceManually(Out<bool> out_should_set_gpu_time_slice_manually); |
| 77 | Result Cmd160(Out<u64> out_unknown0); | 77 | Result Cmd160(Out<u64> out_unknown0); |
diff --git a/src/core/hle/service/am/service/self_controller.cpp b/src/core/hle/service/am/service/self_controller.cpp index 5c4c13de1..06314407c 100644 --- a/src/core/hle/service/am/service/self_controller.cpp +++ b/src/core/hle/service/am/service/self_controller.cpp | |||
| @@ -15,9 +15,9 @@ | |||
| 15 | namespace Service::AM { | 15 | namespace Service::AM { |
| 16 | 16 | ||
| 17 | ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet> applet, | 17 | ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet> applet, |
| 18 | Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger) | 18 | Kernel::KProcess* process) |
| 19 | : ServiceFramework{system_, "ISelfController"}, | 19 | : ServiceFramework{system_, "ISelfController"}, m_process{process}, m_applet{ |
| 20 | m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} { | 20 | std::move(applet)} { |
| 21 | // clang-format off | 21 | // clang-format off |
| 22 | static const FunctionInfo functions[] = { | 22 | static const FunctionInfo functions[] = { |
| 23 | {0, D<&ISelfController::Exit>, "Exit"}, | 23 | {0, D<&ISelfController::Exit>, "Exit"}, |
| @@ -72,9 +72,16 @@ ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet> | |||
| 72 | // clang-format on | 72 | // clang-format on |
| 73 | 73 | ||
| 74 | RegisterHandlers(functions); | 74 | RegisterHandlers(functions); |
| 75 | |||
| 76 | std::scoped_lock lk{m_applet->lock}; | ||
| 77 | m_applet->display_layer_manager.Initialize(system, m_process, m_applet->applet_id, | ||
| 78 | m_applet->library_applet_mode); | ||
| 75 | } | 79 | } |
| 76 | 80 | ||
| 77 | ISelfController::~ISelfController() = default; | 81 | ISelfController::~ISelfController() { |
| 82 | std::scoped_lock lk{m_applet->lock}; | ||
| 83 | m_applet->display_layer_manager.Finalize(); | ||
| 84 | } | ||
| 78 | 85 | ||
| 79 | Result ISelfController::Exit() { | 86 | Result ISelfController::Exit() { |
| 80 | LOG_DEBUG(Service_AM, "called"); | 87 | LOG_DEBUG(Service_AM, "called"); |
| @@ -212,48 +219,42 @@ Result ISelfController::SetAlbumImageOrientation( | |||
| 212 | 219 | ||
| 213 | Result ISelfController::IsSystemBufferSharingEnabled() { | 220 | Result ISelfController::IsSystemBufferSharingEnabled() { |
| 214 | LOG_INFO(Service_AM, "called"); | 221 | LOG_INFO(Service_AM, "called"); |
| 215 | R_SUCCEED_IF(m_applet->system_buffer_manager.Initialize( | 222 | |
| 216 | &m_nvnflinger, m_process, m_applet->applet_id, m_applet->library_applet_mode)); | 223 | std::scoped_lock lk{m_applet->lock}; |
| 217 | R_THROW(VI::ResultOperationFailed); | 224 | R_RETURN(m_applet->display_layer_manager.IsSystemBufferSharingEnabled()); |
| 218 | } | 225 | } |
| 219 | 226 | ||
| 220 | Result ISelfController::GetSystemSharedBufferHandle(Out<u64> out_buffer_id) { | 227 | Result ISelfController::GetSystemSharedBufferHandle(Out<u64> out_buffer_id) { |
| 221 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 228 | LOG_INFO(Service_AM, "called"); |
| 222 | |||
| 223 | R_TRY(this->IsSystemBufferSharingEnabled()); | ||
| 224 | 229 | ||
| 225 | u64 layer_id; | 230 | u64 layer_id; |
| 226 | m_applet->system_buffer_manager.GetSystemSharedLayerHandle(out_buffer_id, &layer_id); | 231 | |
| 227 | R_SUCCEED(); | 232 | std::scoped_lock lk{m_applet->lock}; |
| 233 | R_RETURN(m_applet->display_layer_manager.GetSystemSharedLayerHandle(out_buffer_id, &layer_id)); | ||
| 228 | } | 234 | } |
| 229 | 235 | ||
| 230 | Result ISelfController::GetSystemSharedLayerHandle(Out<u64> out_buffer_id, Out<u64> out_layer_id) { | 236 | Result ISelfController::GetSystemSharedLayerHandle(Out<u64> out_buffer_id, Out<u64> out_layer_id) { |
| 231 | LOG_INFO(Service_AM, "(STUBBED) called"); | 237 | LOG_INFO(Service_AM, "called"); |
| 232 | |||
| 233 | R_TRY(this->IsSystemBufferSharingEnabled()); | ||
| 234 | 238 | ||
| 235 | m_applet->system_buffer_manager.GetSystemSharedLayerHandle(out_buffer_id, out_layer_id); | 239 | std::scoped_lock lk{m_applet->lock}; |
| 236 | R_SUCCEED(); | 240 | R_RETURN( |
| 241 | m_applet->display_layer_manager.GetSystemSharedLayerHandle(out_buffer_id, out_layer_id)); | ||
| 237 | } | 242 | } |
| 238 | 243 | ||
| 239 | Result ISelfController::CreateManagedDisplayLayer(Out<u64> out_layer_id) { | 244 | Result ISelfController::CreateManagedDisplayLayer(Out<u64> out_layer_id) { |
| 240 | LOG_INFO(Service_AM, "called"); | 245 | LOG_INFO(Service_AM, "called"); |
| 241 | 246 | ||
| 242 | m_applet->managed_layer_holder.Initialize(&m_nvnflinger); | 247 | std::scoped_lock lk{m_applet->lock}; |
| 243 | m_applet->managed_layer_holder.CreateManagedDisplayLayer(out_layer_id); | 248 | R_RETURN(m_applet->display_layer_manager.CreateManagedDisplayLayer(out_layer_id)); |
| 244 | |||
| 245 | R_SUCCEED(); | ||
| 246 | } | 249 | } |
| 247 | 250 | ||
| 248 | Result ISelfController::CreateManagedDisplaySeparableLayer(Out<u64> out_layer_id, | 251 | Result ISelfController::CreateManagedDisplaySeparableLayer(Out<u64> out_layer_id, |
| 249 | Out<u64> out_recording_layer_id) { | 252 | Out<u64> out_recording_layer_id) { |
| 250 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 253 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 251 | 254 | ||
| 252 | m_applet->managed_layer_holder.Initialize(&m_nvnflinger); | 255 | std::scoped_lock lk{m_applet->lock}; |
| 253 | m_applet->managed_layer_holder.CreateManagedDisplaySeparableLayer(out_layer_id, | 256 | R_RETURN(m_applet->display_layer_manager.CreateManagedDisplaySeparableLayer( |
| 254 | out_recording_layer_id); | 257 | out_layer_id, out_recording_layer_id)); |
| 255 | |||
| 256 | R_SUCCEED(); | ||
| 257 | } | 258 | } |
| 258 | 259 | ||
| 259 | Result ISelfController::SetHandlesRequestToDisplay(bool enable) { | 260 | Result ISelfController::SetHandlesRequestToDisplay(bool enable) { |
diff --git a/src/core/hle/service/am/service/self_controller.h b/src/core/hle/service/am/service/self_controller.h index 01fa381a3..eca083cfe 100644 --- a/src/core/hle/service/am/service/self_controller.h +++ b/src/core/hle/service/am/service/self_controller.h | |||
| @@ -23,7 +23,7 @@ struct Applet; | |||
| 23 | class ISelfController final : public ServiceFramework<ISelfController> { | 23 | class ISelfController final : public ServiceFramework<ISelfController> { |
| 24 | public: | 24 | public: |
| 25 | explicit ISelfController(Core::System& system_, std::shared_ptr<Applet> applet, | 25 | explicit ISelfController(Core::System& system_, std::shared_ptr<Applet> applet, |
| 26 | Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger); | 26 | Kernel::KProcess* process); |
| 27 | ~ISelfController() override; | 27 | ~ISelfController() override; |
| 28 | 28 | ||
| 29 | private: | 29 | private: |
| @@ -64,7 +64,6 @@ private: | |||
| 64 | Result SaveCurrentScreenshot(Capture::AlbumReportOption album_report_option); | 64 | Result SaveCurrentScreenshot(Capture::AlbumReportOption album_report_option); |
| 65 | Result SetRecordVolumeMuted(bool muted); | 65 | Result SetRecordVolumeMuted(bool muted); |
| 66 | 66 | ||
| 67 | Nvnflinger::Nvnflinger& m_nvnflinger; | ||
| 68 | Kernel::KProcess* const m_process; | 67 | Kernel::KProcess* const m_process; |
| 69 | const std::shared_ptr<Applet> m_applet; | 68 | const std::shared_ptr<Applet> m_applet; |
| 70 | }; | 69 | }; |
diff --git a/src/core/hle/service/am/service/system_applet_proxy.cpp b/src/core/hle/service/am/service/system_applet_proxy.cpp index 5ec509d2e..d1871ef9b 100644 --- a/src/core/hle/service/am/service/system_applet_proxy.cpp +++ b/src/core/hle/service/am/service/system_applet_proxy.cpp | |||
| @@ -19,10 +19,9 @@ | |||
| 19 | namespace Service::AM { | 19 | namespace Service::AM { |
| 20 | 20 | ||
| 21 | ISystemAppletProxy::ISystemAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet, | 21 | ISystemAppletProxy::ISystemAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet, |
| 22 | Kernel::KProcess* process, | 22 | Kernel::KProcess* process) |
| 23 | Nvnflinger::Nvnflinger& nvnflinger) | 23 | : ServiceFramework{system_, "ISystemAppletProxy"}, m_process{process}, m_applet{ |
| 24 | : ServiceFramework{system_, "ISystemAppletProxy"}, | 24 | std::move(applet)} { |
| 25 | m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} { | ||
| 26 | // clang-format off | 25 | // clang-format off |
| 27 | static const FunctionInfo functions[] = { | 26 | static const FunctionInfo functions[] = { |
| 28 | {0, D<&ISystemAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"}, | 27 | {0, D<&ISystemAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"}, |
| @@ -83,8 +82,7 @@ Result ISystemAppletProxy::GetWindowController( | |||
| 83 | Result ISystemAppletProxy::GetSelfController( | 82 | Result ISystemAppletProxy::GetSelfController( |
| 84 | Out<SharedPointer<ISelfController>> out_self_controller) { | 83 | Out<SharedPointer<ISelfController>> out_self_controller) { |
| 85 | LOG_DEBUG(Service_AM, "called"); | 84 | LOG_DEBUG(Service_AM, "called"); |
| 86 | *out_self_controller = | 85 | *out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process); |
| 87 | std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger); | ||
| 88 | R_SUCCEED(); | 86 | R_SUCCEED(); |
| 89 | } | 87 | } |
| 90 | 88 | ||
diff --git a/src/core/hle/service/am/service/system_applet_proxy.h b/src/core/hle/service/am/service/system_applet_proxy.h index 3d5040315..67cd50e03 100644 --- a/src/core/hle/service/am/service/system_applet_proxy.h +++ b/src/core/hle/service/am/service/system_applet_proxy.h | |||
| @@ -25,7 +25,7 @@ class IWindowController; | |||
| 25 | class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { | 25 | class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { |
| 26 | public: | 26 | public: |
| 27 | explicit ISystemAppletProxy(Core::System& system, std::shared_ptr<Applet> applet, | 27 | explicit ISystemAppletProxy(Core::System& system, std::shared_ptr<Applet> applet, |
| 28 | Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger); | 28 | Kernel::KProcess* process); |
| 29 | ~ISystemAppletProxy(); | 29 | ~ISystemAppletProxy(); |
| 30 | 30 | ||
| 31 | private: | 31 | private: |
| @@ -46,7 +46,6 @@ private: | |||
| 46 | Result GetGlobalStateController( | 46 | Result GetGlobalStateController( |
| 47 | Out<SharedPointer<IGlobalStateController>> out_global_state_controller); | 47 | Out<SharedPointer<IGlobalStateController>> out_global_state_controller); |
| 48 | 48 | ||
| 49 | Nvnflinger::Nvnflinger& m_nvnflinger; | ||
| 50 | Kernel::KProcess* const m_process; | 49 | Kernel::KProcess* const m_process; |
| 51 | const std::shared_ptr<Applet> m_applet; | 50 | const std::shared_ptr<Applet> m_applet; |
| 52 | }; | 51 | }; |
diff --git a/src/core/hle/service/am/service/window_controller.cpp b/src/core/hle/service/am/service/window_controller.cpp index b874ecb91..99a4f50a2 100644 --- a/src/core/hle/service/am/service/window_controller.cpp +++ b/src/core/hle/service/am/service/window_controller.cpp | |||
| @@ -63,7 +63,7 @@ Result IWindowController::RejectToChangeIntoBackground() { | |||
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | Result IWindowController::SetAppletWindowVisibility(bool visible) { | 65 | Result IWindowController::SetAppletWindowVisibility(bool visible) { |
| 66 | m_applet->system_buffer_manager.SetWindowVisibility(visible); | 66 | m_applet->display_layer_manager.SetWindowVisibility(visible); |
| 67 | m_applet->hid_registration.EnableAppletToGetInput(visible); | 67 | m_applet->hid_registration.EnableAppletToGetInput(visible); |
| 68 | 68 | ||
| 69 | if (visible) { | 69 | if (visible) { |
diff --git a/src/core/hle/service/am/system_buffer_manager.cpp b/src/core/hle/service/am/system_buffer_manager.cpp deleted file mode 100644 index 48923fe41..000000000 --- a/src/core/hle/service/am/system_buffer_manager.cpp +++ /dev/null | |||
| @@ -1,80 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/am/system_buffer_manager.h" | ||
| 5 | #include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" | ||
| 6 | #include "core/hle/service/nvnflinger/nvnflinger.h" | ||
| 7 | #include "core/hle/service/vi/vi_results.h" | ||
| 8 | |||
| 9 | namespace Service::AM { | ||
| 10 | |||
| 11 | SystemBufferManager::SystemBufferManager() = default; | ||
| 12 | |||
| 13 | SystemBufferManager::~SystemBufferManager() { | ||
| 14 | if (!m_nvnflinger) { | ||
| 15 | return; | ||
| 16 | } | ||
| 17 | |||
| 18 | // Clean up shared layers. | ||
| 19 | if (m_buffer_sharing_enabled) { | ||
| 20 | m_nvnflinger->GetSystemBufferManager().Finalize(m_process); | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 24 | bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process, | ||
| 25 | AppletId applet_id, LibraryAppletMode mode) { | ||
| 26 | if (m_nvnflinger) { | ||
| 27 | return m_buffer_sharing_enabled; | ||
| 28 | } | ||
| 29 | |||
| 30 | m_process = process; | ||
| 31 | m_nvnflinger = nvnflinger; | ||
| 32 | m_buffer_sharing_enabled = false; | ||
| 33 | m_system_shared_buffer_id = 0; | ||
| 34 | m_system_shared_layer_id = 0; | ||
| 35 | |||
| 36 | if (applet_id <= AppletId::Application) { | ||
| 37 | return false; | ||
| 38 | } | ||
| 39 | |||
| 40 | Nvnflinger::LayerBlending blending = Nvnflinger::LayerBlending::None; | ||
| 41 | if (mode == LibraryAppletMode::PartialForeground || | ||
| 42 | mode == LibraryAppletMode::PartialForegroundIndirectDisplay) { | ||
| 43 | blending = Nvnflinger::LayerBlending::Coverage; | ||
| 44 | } | ||
| 45 | |||
| 46 | const auto display_id = m_nvnflinger->OpenDisplay("Default").value(); | ||
| 47 | const auto res = m_nvnflinger->GetSystemBufferManager().Initialize( | ||
| 48 | m_process, &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id, blending); | ||
| 49 | |||
| 50 | if (res.IsSuccess()) { | ||
| 51 | m_buffer_sharing_enabled = true; | ||
| 52 | m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible); | ||
| 53 | } | ||
| 54 | |||
| 55 | return m_buffer_sharing_enabled; | ||
| 56 | } | ||
| 57 | |||
| 58 | void SystemBufferManager::SetWindowVisibility(bool visible) { | ||
| 59 | if (m_visible == visible) { | ||
| 60 | return; | ||
| 61 | } | ||
| 62 | |||
| 63 | m_visible = visible; | ||
| 64 | |||
| 65 | if (m_nvnflinger) { | ||
| 66 | m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | Result SystemBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, | ||
| 71 | s32* out_fbshare_layer_index) { | ||
| 72 | if (!m_buffer_sharing_enabled) { | ||
| 73 | return VI::ResultPermissionDenied; | ||
| 74 | } | ||
| 75 | |||
| 76 | return m_nvnflinger->GetSystemBufferManager().WriteAppletCaptureBuffer(out_was_written, | ||
| 77 | out_fbshare_layer_index); | ||
| 78 | } | ||
| 79 | |||
| 80 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/am/system_buffer_manager.h b/src/core/hle/service/am/system_buffer_manager.h deleted file mode 100644 index 0690f68b6..000000000 --- a/src/core/hle/service/am/system_buffer_manager.h +++ /dev/null | |||
| @@ -1,52 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <set> | ||
| 7 | |||
| 8 | #include "common/common_funcs.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | #include "core/hle/service/am/am_types.h" | ||
| 12 | |||
| 13 | namespace Kernel { | ||
| 14 | class KProcess; | ||
| 15 | } | ||
| 16 | |||
| 17 | namespace Service::Nvnflinger { | ||
| 18 | class Nvnflinger; | ||
| 19 | } | ||
| 20 | |||
| 21 | union Result; | ||
| 22 | |||
| 23 | namespace Service::AM { | ||
| 24 | |||
| 25 | class SystemBufferManager { | ||
| 26 | public: | ||
| 27 | SystemBufferManager(); | ||
| 28 | ~SystemBufferManager(); | ||
| 29 | |||
| 30 | bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id, | ||
| 31 | LibraryAppletMode mode); | ||
| 32 | |||
| 33 | void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id, | ||
| 34 | u64* out_system_shared_layer_id) { | ||
| 35 | *out_system_shared_buffer_id = m_system_shared_buffer_id; | ||
| 36 | *out_system_shared_layer_id = m_system_shared_layer_id; | ||
| 37 | } | ||
| 38 | |||
| 39 | void SetWindowVisibility(bool visible); | ||
| 40 | |||
| 41 | Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index); | ||
| 42 | |||
| 43 | private: | ||
| 44 | Kernel::KProcess* m_process{}; | ||
| 45 | Nvnflinger::Nvnflinger* m_nvnflinger{}; | ||
| 46 | bool m_buffer_sharing_enabled{}; | ||
| 47 | bool m_visible{true}; | ||
| 48 | u64 m_system_shared_buffer_id{}; | ||
| 49 | u64 m_system_shared_layer_id{}; | ||
| 50 | }; | ||
| 51 | |||
| 52 | } // namespace Service::AM | ||
diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp deleted file mode 100644 index cf4bb4034..000000000 --- a/src/core/hle/service/audio/audctl.cpp +++ /dev/null | |||
| @@ -1,201 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/logging/log.h" | ||
| 5 | #include "core/hle/service/audio/audctl.h" | ||
| 6 | #include "core/hle/service/ipc_helpers.h" | ||
| 7 | #include "core/hle/service/set/system_settings_server.h" | ||
| 8 | #include "core/hle/service/sm/sm.h" | ||
| 9 | |||
| 10 | namespace Service::Audio { | ||
| 11 | |||
| 12 | AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} { | ||
| 13 | // clang-format off | ||
| 14 | static const FunctionInfo functions[] = { | ||
| 15 | {0, nullptr, "GetTargetVolume"}, | ||
| 16 | {1, nullptr, "SetTargetVolume"}, | ||
| 17 | {2, &AudCtl::GetTargetVolumeMin, "GetTargetVolumeMin"}, | ||
| 18 | {3, &AudCtl::GetTargetVolumeMax, "GetTargetVolumeMax"}, | ||
| 19 | {4, nullptr, "IsTargetMute"}, | ||
| 20 | {5, nullptr, "SetTargetMute"}, | ||
| 21 | {6, nullptr, "IsTargetConnected"}, | ||
| 22 | {7, nullptr, "SetDefaultTarget"}, | ||
| 23 | {8, nullptr, "GetDefaultTarget"}, | ||
| 24 | {9, &AudCtl::GetAudioOutputMode, "GetAudioOutputMode"}, | ||
| 25 | {10, &AudCtl::SetAudioOutputMode, "SetAudioOutputMode"}, | ||
| 26 | {11, nullptr, "SetForceMutePolicy"}, | ||
| 27 | {12, &AudCtl::GetForceMutePolicy, "GetForceMutePolicy"}, | ||
| 28 | {13, &AudCtl::GetOutputModeSetting, "GetOutputModeSetting"}, | ||
| 29 | {14, &AudCtl::SetOutputModeSetting, "SetOutputModeSetting"}, | ||
| 30 | {15, nullptr, "SetOutputTarget"}, | ||
| 31 | {16, nullptr, "SetInputTargetForceEnabled"}, | ||
| 32 | {17, &AudCtl::SetHeadphoneOutputLevelMode, "SetHeadphoneOutputLevelMode"}, | ||
| 33 | {18, &AudCtl::GetHeadphoneOutputLevelMode, "GetHeadphoneOutputLevelMode"}, | ||
| 34 | {19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"}, | ||
| 35 | {20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"}, | ||
| 36 | {21, nullptr, "GetAudioOutputTargetForPlayReport"}, | ||
| 37 | {22, nullptr, "NotifyHeadphoneVolumeWarningDisplayedEvent"}, | ||
| 38 | {23, nullptr, "SetSystemOutputMasterVolume"}, | ||
| 39 | {24, nullptr, "GetSystemOutputMasterVolume"}, | ||
| 40 | {25, nullptr, "GetAudioVolumeDataForPlayReport"}, | ||
| 41 | {26, nullptr, "UpdateHeadphoneSettings"}, | ||
| 42 | {27, nullptr, "SetVolumeMappingTableForDev"}, | ||
| 43 | {28, nullptr, "GetAudioOutputChannelCountForPlayReport"}, | ||
| 44 | {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"}, | ||
| 45 | {30, &AudCtl::SetSpeakerAutoMuteEnabled, "SetSpeakerAutoMuteEnabled"}, | ||
| 46 | {31, &AudCtl::IsSpeakerAutoMuteEnabled, "IsSpeakerAutoMuteEnabled"}, | ||
| 47 | {32, nullptr, "GetActiveOutputTarget"}, | ||
| 48 | {33, nullptr, "GetTargetDeviceInfo"}, | ||
| 49 | {34, nullptr, "AcquireTargetNotification"}, | ||
| 50 | {35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"}, | ||
| 51 | {36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"}, | ||
| 52 | {37, nullptr, "SetHearingProtectionSafeguardEnabled"}, | ||
| 53 | {38, nullptr, "IsHearingProtectionSafeguardEnabled"}, | ||
| 54 | {39, nullptr, "IsHearingProtectionSafeguardMonitoringOutputForDebug"}, | ||
| 55 | {40, nullptr, "GetSystemInformationForDebug"}, | ||
| 56 | {41, nullptr, "SetVolumeButtonLongPressTime"}, | ||
| 57 | {42, nullptr, "SetNativeVolumeForDebug"}, | ||
| 58 | {10000, nullptr, "NotifyAudioOutputTargetForPlayReport"}, | ||
| 59 | {10001, nullptr, "NotifyAudioOutputChannelCountForPlayReport"}, | ||
| 60 | {10002, nullptr, "NotifyUnsupportedUsbOutputDeviceAttachedForPlayReport"}, | ||
| 61 | {10100, nullptr, "GetAudioVolumeDataForPlayReport"}, | ||
| 62 | {10101, nullptr, "BindAudioVolumeUpdateEventForPlayReport"}, | ||
| 63 | {10102, nullptr, "BindAudioOutputTargetUpdateEventForPlayReport"}, | ||
| 64 | {10103, nullptr, "GetAudioOutputTargetForPlayReport"}, | ||
| 65 | {10104, nullptr, "GetAudioOutputChannelCountForPlayReport"}, | ||
| 66 | {10105, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"}, | ||
| 67 | {10106, nullptr, "GetDefaultAudioOutputTargetForPlayReport"}, | ||
| 68 | {50000, nullptr, "SetAnalogInputBoostGainForPrototyping"}, | ||
| 69 | }; | ||
| 70 | // clang-format on | ||
| 71 | |||
| 72 | RegisterHandlers(functions); | ||
| 73 | |||
| 74 | m_set_sys = | ||
| 75 | system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); | ||
| 76 | } | ||
| 77 | |||
| 78 | AudCtl::~AudCtl() = default; | ||
| 79 | |||
| 80 | void AudCtl::GetTargetVolumeMin(HLERequestContext& ctx) { | ||
| 81 | LOG_DEBUG(Audio, "called."); | ||
| 82 | |||
| 83 | // This service function is currently hardcoded on the | ||
| 84 | // actual console to this value (as of 8.0.0). | ||
| 85 | constexpr s32 target_min_volume = 0; | ||
| 86 | |||
| 87 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 88 | rb.Push(ResultSuccess); | ||
| 89 | rb.Push(target_min_volume); | ||
| 90 | } | ||
| 91 | |||
| 92 | void AudCtl::GetTargetVolumeMax(HLERequestContext& ctx) { | ||
| 93 | LOG_DEBUG(Audio, "called."); | ||
| 94 | |||
| 95 | // This service function is currently hardcoded on the | ||
| 96 | // actual console to this value (as of 8.0.0). | ||
| 97 | constexpr s32 target_max_volume = 15; | ||
| 98 | |||
| 99 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 100 | rb.Push(ResultSuccess); | ||
| 101 | rb.Push(target_max_volume); | ||
| 102 | } | ||
| 103 | |||
| 104 | void AudCtl::GetAudioOutputMode(HLERequestContext& ctx) { | ||
| 105 | IPC::RequestParser rp{ctx}; | ||
| 106 | const auto target{rp.PopEnum<Set::AudioOutputModeTarget>()}; | ||
| 107 | |||
| 108 | Set::AudioOutputMode output_mode{}; | ||
| 109 | const auto result = m_set_sys->GetAudioOutputMode(&output_mode, target); | ||
| 110 | |||
| 111 | LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode); | ||
| 112 | |||
| 113 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 114 | rb.Push(result); | ||
| 115 | rb.PushEnum(output_mode); | ||
| 116 | } | ||
| 117 | |||
| 118 | void AudCtl::SetAudioOutputMode(HLERequestContext& ctx) { | ||
| 119 | IPC::RequestParser rp{ctx}; | ||
| 120 | const auto target{rp.PopEnum<Set::AudioOutputModeTarget>()}; | ||
| 121 | const auto output_mode{rp.PopEnum<Set::AudioOutputMode>()}; | ||
| 122 | |||
| 123 | const auto result = m_set_sys->SetAudioOutputMode(target, output_mode); | ||
| 124 | |||
| 125 | LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode); | ||
| 126 | |||
| 127 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 128 | rb.Push(result); | ||
| 129 | } | ||
| 130 | |||
| 131 | void AudCtl::GetForceMutePolicy(HLERequestContext& ctx) { | ||
| 132 | LOG_WARNING(Audio, "(STUBBED) called"); | ||
| 133 | |||
| 134 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 135 | rb.Push(ResultSuccess); | ||
| 136 | rb.PushEnum(ForceMutePolicy::Disable); | ||
| 137 | } | ||
| 138 | |||
| 139 | void AudCtl::GetOutputModeSetting(HLERequestContext& ctx) { | ||
| 140 | IPC::RequestParser rp{ctx}; | ||
| 141 | const auto target{rp.PopEnum<Set::AudioOutputModeTarget>()}; | ||
| 142 | |||
| 143 | LOG_WARNING(Audio, "(STUBBED) called, target={}", target); | ||
| 144 | |||
| 145 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 146 | rb.Push(ResultSuccess); | ||
| 147 | rb.PushEnum(Set::AudioOutputMode::ch_7_1); | ||
| 148 | } | ||
| 149 | |||
| 150 | void AudCtl::SetOutputModeSetting(HLERequestContext& ctx) { | ||
| 151 | IPC::RequestParser rp{ctx}; | ||
| 152 | const auto target{rp.PopEnum<Set::AudioOutputModeTarget>()}; | ||
| 153 | const auto output_mode{rp.PopEnum<Set::AudioOutputMode>()}; | ||
| 154 | |||
| 155 | LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode); | ||
| 156 | |||
| 157 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 158 | rb.Push(ResultSuccess); | ||
| 159 | } | ||
| 160 | |||
| 161 | void AudCtl::SetHeadphoneOutputLevelMode(HLERequestContext& ctx) { | ||
| 162 | LOG_WARNING(Audio, "(STUBBED) called"); | ||
| 163 | |||
| 164 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 165 | rb.Push(ResultSuccess); | ||
| 166 | } | ||
| 167 | |||
| 168 | void AudCtl::GetHeadphoneOutputLevelMode(HLERequestContext& ctx) { | ||
| 169 | LOG_WARNING(Audio, "(STUBBED) called"); | ||
| 170 | |||
| 171 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 172 | rb.Push(ResultSuccess); | ||
| 173 | rb.PushEnum(HeadphoneOutputLevelMode::Normal); | ||
| 174 | } | ||
| 175 | |||
| 176 | void AudCtl::SetSpeakerAutoMuteEnabled(HLERequestContext& ctx) { | ||
| 177 | IPC::RequestParser rp{ctx}; | ||
| 178 | const auto is_speaker_auto_mute_enabled{rp.Pop<bool>()}; | ||
| 179 | |||
| 180 | LOG_WARNING(Audio, "(STUBBED) called, is_speaker_auto_mute_enabled={}", | ||
| 181 | is_speaker_auto_mute_enabled); | ||
| 182 | |||
| 183 | const auto result = m_set_sys->SetSpeakerAutoMuteFlag(is_speaker_auto_mute_enabled); | ||
| 184 | |||
| 185 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 186 | rb.Push(result); | ||
| 187 | } | ||
| 188 | |||
| 189 | void AudCtl::IsSpeakerAutoMuteEnabled(HLERequestContext& ctx) { | ||
| 190 | bool is_speaker_auto_mute_enabled{}; | ||
| 191 | const auto result = m_set_sys->GetSpeakerAutoMuteFlag(&is_speaker_auto_mute_enabled); | ||
| 192 | |||
| 193 | LOG_WARNING(Audio, "(STUBBED) called, is_speaker_auto_mute_enabled={}", | ||
| 194 | is_speaker_auto_mute_enabled); | ||
| 195 | |||
| 196 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 197 | rb.Push(result); | ||
| 198 | rb.Push<u8>(is_speaker_auto_mute_enabled); | ||
| 199 | } | ||
| 200 | |||
| 201 | } // namespace Service::Audio | ||
diff --git a/src/core/hle/service/audio/audctl.h b/src/core/hle/service/audio/audctl.h deleted file mode 100644 index 4c90ead70..000000000 --- a/src/core/hle/service/audio/audctl.h +++ /dev/null | |||
| @@ -1,50 +0,0 @@ | |||
| 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/service.h" | ||
| 7 | |||
| 8 | namespace Core { | ||
| 9 | class System; | ||
| 10 | } | ||
| 11 | |||
| 12 | namespace Service::Set { | ||
| 13 | class ISystemSettingsServer; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service::Audio { | ||
| 17 | |||
| 18 | class AudCtl final : public ServiceFramework<AudCtl> { | ||
| 19 | public: | ||
| 20 | explicit AudCtl(Core::System& system_); | ||
| 21 | ~AudCtl() override; | ||
| 22 | |||
| 23 | private: | ||
| 24 | enum class ForceMutePolicy { | ||
| 25 | Disable, | ||
| 26 | SpeakerMuteOnHeadphoneUnplugged, | ||
| 27 | }; | ||
| 28 | |||
| 29 | enum class HeadphoneOutputLevelMode { | ||
| 30 | Normal, | ||
| 31 | HighPower, | ||
| 32 | }; | ||
| 33 | |||
| 34 | void GetTargetVolumeMin(HLERequestContext& ctx); | ||
| 35 | void GetTargetVolumeMax(HLERequestContext& ctx); | ||
| 36 | void GetAudioOutputMode(HLERequestContext& ctx); | ||
| 37 | void SetAudioOutputMode(HLERequestContext& ctx); | ||
| 38 | void GetForceMutePolicy(HLERequestContext& ctx); | ||
| 39 | void GetOutputModeSetting(HLERequestContext& ctx); | ||
| 40 | void SetOutputModeSetting(HLERequestContext& ctx); | ||
| 41 | void SetHeadphoneOutputLevelMode(HLERequestContext& ctx); | ||
| 42 | void GetHeadphoneOutputLevelMode(HLERequestContext& ctx); | ||
| 43 | void SetSpeakerAutoMuteEnabled(HLERequestContext& ctx); | ||
| 44 | void IsSpeakerAutoMuteEnabled(HLERequestContext& ctx); | ||
| 45 | void AcquireTargetNotification(HLERequestContext& ctx); | ||
| 46 | |||
| 47 | std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; | ||
| 48 | }; | ||
| 49 | |||
| 50 | } // namespace Service::Audio | ||
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp index dccd16309..44af030eb 100644 --- a/src/core/hle/service/audio/audio.cpp +++ b/src/core/hle/service/audio/audio.cpp | |||
| @@ -2,9 +2,9 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "core/core.h" | 4 | #include "core/core.h" |
| 5 | #include "core/hle/service/audio/audctl.h" | ||
| 6 | #include "core/hle/service/audio/audin_u.h" | 5 | #include "core/hle/service/audio/audin_u.h" |
| 7 | #include "core/hle/service/audio/audio.h" | 6 | #include "core/hle/service/audio/audio.h" |
| 7 | #include "core/hle/service/audio/audio_controller.h" | ||
| 8 | #include "core/hle/service/audio/audout_u.h" | 8 | #include "core/hle/service/audio/audout_u.h" |
| 9 | #include "core/hle/service/audio/audrec_a.h" | 9 | #include "core/hle/service/audio/audrec_a.h" |
| 10 | #include "core/hle/service/audio/audrec_u.h" | 10 | #include "core/hle/service/audio/audrec_u.h" |
| @@ -18,7 +18,7 @@ namespace Service::Audio { | |||
| 18 | void LoopProcess(Core::System& system) { | 18 | void LoopProcess(Core::System& system) { |
| 19 | auto server_manager = std::make_unique<ServerManager>(system); | 19 | auto server_manager = std::make_unique<ServerManager>(system); |
| 20 | 20 | ||
| 21 | server_manager->RegisterNamedService("audctl", std::make_shared<AudCtl>(system)); | 21 | server_manager->RegisterNamedService("audctl", std::make_shared<IAudioController>(system)); |
| 22 | server_manager->RegisterNamedService("audout:u", std::make_shared<AudOutU>(system)); | 22 | server_manager->RegisterNamedService("audout:u", std::make_shared<AudOutU>(system)); |
| 23 | server_manager->RegisterNamedService("audin:u", std::make_shared<AudInU>(system)); | 23 | server_manager->RegisterNamedService("audin:u", std::make_shared<AudInU>(system)); |
| 24 | server_manager->RegisterNamedService("audrec:a", std::make_shared<AudRecA>(system)); | 24 | server_manager->RegisterNamedService("audrec:a", std::make_shared<AudRecA>(system)); |
diff --git a/src/core/hle/service/audio/audio_controller.cpp b/src/core/hle/service/audio/audio_controller.cpp new file mode 100644 index 000000000..a6da66d0f --- /dev/null +++ b/src/core/hle/service/audio/audio_controller.cpp | |||
| @@ -0,0 +1,174 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/logging/log.h" | ||
| 5 | #include "core/hle/service/audio/audio_controller.h" | ||
| 6 | #include "core/hle/service/cmif_serialization.h" | ||
| 7 | #include "core/hle/service/ipc_helpers.h" | ||
| 8 | #include "core/hle/service/set/system_settings_server.h" | ||
| 9 | #include "core/hle/service/sm/sm.h" | ||
| 10 | |||
| 11 | namespace Service::Audio { | ||
| 12 | |||
| 13 | IAudioController::IAudioController(Core::System& system_) | ||
| 14 | : ServiceFramework{system_, "audctl"}, service_context{system, "audctl"} { | ||
| 15 | // clang-format off | ||
| 16 | static const FunctionInfo functions[] = { | ||
| 17 | {0, nullptr, "GetTargetVolume"}, | ||
| 18 | {1, nullptr, "SetTargetVolume"}, | ||
| 19 | {2, C<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"}, | ||
| 20 | {3, C<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"}, | ||
| 21 | {4, nullptr, "IsTargetMute"}, | ||
| 22 | {5, nullptr, "SetTargetMute"}, | ||
| 23 | {6, nullptr, "IsTargetConnected"}, | ||
| 24 | {7, nullptr, "SetDefaultTarget"}, | ||
| 25 | {8, nullptr, "GetDefaultTarget"}, | ||
| 26 | {9, C<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"}, | ||
| 27 | {10, C<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"}, | ||
| 28 | {11, nullptr, "SetForceMutePolicy"}, | ||
| 29 | {12, C<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"}, | ||
| 30 | {13, C<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"}, | ||
| 31 | {14, C<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"}, | ||
| 32 | {15, nullptr, "SetOutputTarget"}, | ||
| 33 | {16, nullptr, "SetInputTargetForceEnabled"}, | ||
| 34 | {17, C<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"}, | ||
| 35 | {18, C<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"}, | ||
| 36 | {19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"}, | ||
| 37 | {20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"}, | ||
| 38 | {21, nullptr, "GetAudioOutputTargetForPlayReport"}, | ||
| 39 | {22, nullptr, "NotifyHeadphoneVolumeWarningDisplayedEvent"}, | ||
| 40 | {23, nullptr, "SetSystemOutputMasterVolume"}, | ||
| 41 | {24, nullptr, "GetSystemOutputMasterVolume"}, | ||
| 42 | {25, nullptr, "GetAudioVolumeDataForPlayReport"}, | ||
| 43 | {26, nullptr, "UpdateHeadphoneSettings"}, | ||
| 44 | {27, nullptr, "SetVolumeMappingTableForDev"}, | ||
| 45 | {28, nullptr, "GetAudioOutputChannelCountForPlayReport"}, | ||
| 46 | {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"}, | ||
| 47 | {30, C<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"}, | ||
| 48 | {31, C<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"}, | ||
| 49 | {32, nullptr, "GetActiveOutputTarget"}, | ||
| 50 | {33, nullptr, "GetTargetDeviceInfo"}, | ||
| 51 | {34, C<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"}, | ||
| 52 | {35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"}, | ||
| 53 | {36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"}, | ||
| 54 | {37, nullptr, "SetHearingProtectionSafeguardEnabled"}, | ||
| 55 | {38, nullptr, "IsHearingProtectionSafeguardEnabled"}, | ||
| 56 | {39, nullptr, "IsHearingProtectionSafeguardMonitoringOutputForDebug"}, | ||
| 57 | {40, nullptr, "GetSystemInformationForDebug"}, | ||
| 58 | {41, nullptr, "SetVolumeButtonLongPressTime"}, | ||
| 59 | {42, nullptr, "SetNativeVolumeForDebug"}, | ||
| 60 | {10000, nullptr, "NotifyAudioOutputTargetForPlayReport"}, | ||
| 61 | {10001, nullptr, "NotifyAudioOutputChannelCountForPlayReport"}, | ||
| 62 | {10002, nullptr, "NotifyUnsupportedUsbOutputDeviceAttachedForPlayReport"}, | ||
| 63 | {10100, nullptr, "GetAudioVolumeDataForPlayReport"}, | ||
| 64 | {10101, nullptr, "BindAudioVolumeUpdateEventForPlayReport"}, | ||
| 65 | {10102, nullptr, "BindAudioOutputTargetUpdateEventForPlayReport"}, | ||
| 66 | {10103, nullptr, "GetAudioOutputTargetForPlayReport"}, | ||
| 67 | {10104, nullptr, "GetAudioOutputChannelCountForPlayReport"}, | ||
| 68 | {10105, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"}, | ||
| 69 | {10106, nullptr, "GetDefaultAudioOutputTargetForPlayReport"}, | ||
| 70 | {50000, nullptr, "SetAnalogInputBoostGainForPrototyping"}, | ||
| 71 | }; | ||
| 72 | // clang-format on | ||
| 73 | |||
| 74 | RegisterHandlers(functions); | ||
| 75 | |||
| 76 | m_set_sys = | ||
| 77 | system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); | ||
| 78 | notification_event = service_context.CreateEvent("IAudioController:NotificationEvent"); | ||
| 79 | } | ||
| 80 | |||
| 81 | IAudioController::~IAudioController() { | ||
| 82 | service_context.CloseEvent(notification_event); | ||
| 83 | }; | ||
| 84 | |||
| 85 | Result IAudioController::GetTargetVolumeMin(Out<s32> out_target_min_volume) { | ||
| 86 | LOG_DEBUG(Audio, "called."); | ||
| 87 | |||
| 88 | // This service function is currently hardcoded on the | ||
| 89 | // actual console to this value (as of 8.0.0). | ||
| 90 | *out_target_min_volume = 0; | ||
| 91 | R_SUCCEED(); | ||
| 92 | } | ||
| 93 | |||
| 94 | Result IAudioController::GetTargetVolumeMax(Out<s32> out_target_max_volume) { | ||
| 95 | LOG_DEBUG(Audio, "called."); | ||
| 96 | |||
| 97 | // This service function is currently hardcoded on the | ||
| 98 | // actual console to this value (as of 8.0.0). | ||
| 99 | *out_target_max_volume = 15; | ||
| 100 | R_SUCCEED(); | ||
| 101 | } | ||
| 102 | |||
| 103 | Result IAudioController::GetAudioOutputMode(Out<Set::AudioOutputMode> out_output_mode, | ||
| 104 | Set::AudioOutputModeTarget target) { | ||
| 105 | const auto result = m_set_sys->GetAudioOutputMode(out_output_mode, target); | ||
| 106 | |||
| 107 | LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, *out_output_mode); | ||
| 108 | R_RETURN(result); | ||
| 109 | } | ||
| 110 | |||
| 111 | Result IAudioController::SetAudioOutputMode(Set::AudioOutputModeTarget target, | ||
| 112 | Set::AudioOutputMode output_mode) { | ||
| 113 | LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode); | ||
| 114 | |||
| 115 | R_RETURN(m_set_sys->SetAudioOutputMode(target, output_mode)); | ||
| 116 | } | ||
| 117 | |||
| 118 | Result IAudioController::GetForceMutePolicy(Out<ForceMutePolicy> out_mute_policy) { | ||
| 119 | LOG_WARNING(Audio, "(STUBBED) called"); | ||
| 120 | |||
| 121 | // Removed on FW 13.2.1+ | ||
| 122 | *out_mute_policy = ForceMutePolicy::Disable; | ||
| 123 | R_SUCCEED(); | ||
| 124 | } | ||
| 125 | |||
| 126 | Result IAudioController::GetOutputModeSetting(Out<Set::AudioOutputMode> out_output_mode, | ||
| 127 | Set::AudioOutputModeTarget target) { | ||
| 128 | LOG_WARNING(Audio, "(STUBBED) called, target={}", target); | ||
| 129 | |||
| 130 | *out_output_mode = Set::AudioOutputMode::ch_7_1; | ||
| 131 | R_SUCCEED(); | ||
| 132 | } | ||
| 133 | |||
| 134 | Result IAudioController::SetOutputModeSetting(Set::AudioOutputModeTarget target, | ||
| 135 | Set::AudioOutputMode output_mode) { | ||
| 136 | LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode); | ||
| 137 | R_SUCCEED(); | ||
| 138 | } | ||
| 139 | |||
| 140 | Result IAudioController::SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode) { | ||
| 141 | LOG_WARNING(Audio, "(STUBBED) called"); | ||
| 142 | R_SUCCEED(); | ||
| 143 | } | ||
| 144 | |||
| 145 | Result IAudioController::GetHeadphoneOutputLevelMode( | ||
| 146 | Out<HeadphoneOutputLevelMode> out_output_level_mode) { | ||
| 147 | LOG_INFO(Audio, "called"); | ||
| 148 | |||
| 149 | *out_output_level_mode = HeadphoneOutputLevelMode::Normal; | ||
| 150 | R_SUCCEED(); | ||
| 151 | } | ||
| 152 | |||
| 153 | Result IAudioController::SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled) { | ||
| 154 | LOG_INFO(Audio, "called, is_speaker_auto_mute_enabled={}", is_speaker_auto_mute_enabled); | ||
| 155 | |||
| 156 | R_RETURN(m_set_sys->SetSpeakerAutoMuteFlag(is_speaker_auto_mute_enabled)); | ||
| 157 | } | ||
| 158 | |||
| 159 | Result IAudioController::IsSpeakerAutoMuteEnabled(Out<bool> out_is_speaker_auto_mute_enabled) { | ||
| 160 | const auto result = m_set_sys->GetSpeakerAutoMuteFlag(out_is_speaker_auto_mute_enabled); | ||
| 161 | |||
| 162 | LOG_INFO(Audio, "called, is_speaker_auto_mute_enabled={}", *out_is_speaker_auto_mute_enabled); | ||
| 163 | R_RETURN(result); | ||
| 164 | } | ||
| 165 | |||
| 166 | Result IAudioController::AcquireTargetNotification( | ||
| 167 | OutCopyHandle<Kernel::KReadableEvent> out_notification_event) { | ||
| 168 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 169 | |||
| 170 | *out_notification_event = ¬ification_event->GetReadableEvent(); | ||
| 171 | R_SUCCEED(); | ||
| 172 | } | ||
| 173 | |||
| 174 | } // namespace Service::Audio | ||
diff --git a/src/core/hle/service/audio/audio_controller.h b/src/core/hle/service/audio/audio_controller.h new file mode 100644 index 000000000..9e8514373 --- /dev/null +++ b/src/core/hle/service/audio/audio_controller.h | |||
| @@ -0,0 +1,58 @@ | |||
| 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/cmif_types.h" | ||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | #include "core/hle/service/set/settings_types.h" | ||
| 9 | |||
| 10 | namespace Core { | ||
| 11 | class System; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace Service::Set { | ||
| 15 | class ISystemSettingsServer; | ||
| 16 | } | ||
| 17 | |||
| 18 | namespace Service::Audio { | ||
| 19 | |||
| 20 | class IAudioController final : public ServiceFramework<IAudioController> { | ||
| 21 | public: | ||
| 22 | explicit IAudioController(Core::System& system_); | ||
| 23 | ~IAudioController() override; | ||
| 24 | |||
| 25 | private: | ||
| 26 | enum class ForceMutePolicy { | ||
| 27 | Disable, | ||
| 28 | SpeakerMuteOnHeadphoneUnplugged, | ||
| 29 | }; | ||
| 30 | |||
| 31 | enum class HeadphoneOutputLevelMode { | ||
| 32 | Normal, | ||
| 33 | HighPower, | ||
| 34 | }; | ||
| 35 | |||
| 36 | Result GetTargetVolumeMin(Out<s32> out_target_min_volume); | ||
| 37 | Result GetTargetVolumeMax(Out<s32> out_target_max_volume); | ||
| 38 | Result GetAudioOutputMode(Out<Set::AudioOutputMode> out_output_mode, | ||
| 39 | Set::AudioOutputModeTarget target); | ||
| 40 | Result SetAudioOutputMode(Set::AudioOutputModeTarget target, Set::AudioOutputMode output_mode); | ||
| 41 | Result GetForceMutePolicy(Out<ForceMutePolicy> out_mute_policy); | ||
| 42 | Result GetOutputModeSetting(Out<Set::AudioOutputMode> out_output_mode, | ||
| 43 | Set::AudioOutputModeTarget target); | ||
| 44 | Result SetOutputModeSetting(Set::AudioOutputModeTarget target, | ||
| 45 | Set::AudioOutputMode output_mode); | ||
| 46 | Result SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode); | ||
| 47 | Result GetHeadphoneOutputLevelMode(Out<HeadphoneOutputLevelMode> out_output_level_mode); | ||
| 48 | Result SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled); | ||
| 49 | Result IsSpeakerAutoMuteEnabled(Out<bool> out_is_speaker_auto_mute_enabled); | ||
| 50 | Result AcquireTargetNotification(OutCopyHandle<Kernel::KReadableEvent> out_notification_event); | ||
| 51 | |||
| 52 | KernelHelpers::ServiceContext service_context; | ||
| 53 | |||
| 54 | Kernel::KEvent* notification_event; | ||
| 55 | std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; | ||
| 56 | }; | ||
| 57 | |||
| 58 | } // namespace Service::Audio | ||
diff --git a/src/core/hle/service/caps/caps_a.cpp b/src/core/hle/service/caps/caps_a.cpp index 47ff072c5..52228b830 100644 --- a/src/core/hle/service/caps/caps_a.cpp +++ b/src/core/hle/service/caps/caps_a.cpp | |||
| @@ -16,7 +16,7 @@ IAlbumAccessorService::IAlbumAccessorService(Core::System& system_, | |||
| 16 | // clang-format off | 16 | // clang-format off |
| 17 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 18 | {0, nullptr, "GetAlbumFileCount"}, | 18 | {0, nullptr, "GetAlbumFileCount"}, |
| 19 | {1, nullptr, "GetAlbumFileList"}, | 19 | {1, C<&IAlbumAccessorService::GetAlbumFileList>, "GetAlbumFileList"}, |
| 20 | {2, nullptr, "LoadAlbumFile"}, | 20 | {2, nullptr, "LoadAlbumFile"}, |
| 21 | {3, C<&IAlbumAccessorService::DeleteAlbumFile>, "DeleteAlbumFile"}, | 21 | {3, C<&IAlbumAccessorService::DeleteAlbumFile>, "DeleteAlbumFile"}, |
| 22 | {4, nullptr, "StorageCopyAlbumFile"}, | 22 | {4, nullptr, "StorageCopyAlbumFile"}, |
| @@ -62,6 +62,15 @@ IAlbumAccessorService::IAlbumAccessorService(Core::System& system_, | |||
| 62 | 62 | ||
| 63 | IAlbumAccessorService::~IAlbumAccessorService() = default; | 63 | IAlbumAccessorService::~IAlbumAccessorService() = default; |
| 64 | 64 | ||
| 65 | Result IAlbumAccessorService::GetAlbumFileList( | ||
| 66 | Out<u64> out_count, AlbumStorage storage, | ||
| 67 | OutArray<AlbumEntry, BufferAttr_HipcMapAlias> out_entries) { | ||
| 68 | LOG_INFO(Service_Capture, "called, storage={}", storage); | ||
| 69 | |||
| 70 | const Result result = manager->GetAlbumFileList(out_entries, *out_count, storage, 0); | ||
| 71 | R_RETURN(TranslateResult(result)); | ||
| 72 | } | ||
| 73 | |||
| 65 | Result IAlbumAccessorService::DeleteAlbumFile(AlbumFileId file_id) { | 74 | Result IAlbumAccessorService::DeleteAlbumFile(AlbumFileId file_id) { |
| 66 | LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}", | 75 | LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}", |
| 67 | file_id.application_id, file_id.storage, file_id.type); | 76 | file_id.application_id, file_id.storage, file_id.type); |
diff --git a/src/core/hle/service/caps/caps_a.h b/src/core/hle/service/caps/caps_a.h index 2cb9b4547..c7a5208e3 100644 --- a/src/core/hle/service/caps/caps_a.h +++ b/src/core/hle/service/caps/caps_a.h | |||
| @@ -21,6 +21,9 @@ public: | |||
| 21 | ~IAlbumAccessorService() override; | 21 | ~IAlbumAccessorService() override; |
| 22 | 22 | ||
| 23 | private: | 23 | private: |
| 24 | Result GetAlbumFileList(Out<u64> out_count, AlbumStorage storage, | ||
| 25 | OutArray<AlbumEntry, BufferAttr_HipcMapAlias> out_entries); | ||
| 26 | |||
| 24 | Result DeleteAlbumFile(AlbumFileId file_id); | 27 | Result DeleteAlbumFile(AlbumFileId file_id); |
| 25 | 28 | ||
| 26 | Result IsAlbumMounted(Out<bool> out_is_mounted, AlbumStorage storage); | 29 | Result IsAlbumMounted(Out<bool> out_is_mounted, AlbumStorage storage); |
diff --git a/src/core/hle/service/erpt/erpt.cpp b/src/core/hle/service/erpt/erpt.cpp index 3ea862fad..39ae3a723 100644 --- a/src/core/hle/service/erpt/erpt.cpp +++ b/src/core/hle/service/erpt/erpt.cpp | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | 3 | ||
| 4 | #include <memory> | 4 | #include <memory> |
| 5 | 5 | ||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "core/hle/service/cmif_serialization.h" | ||
| 6 | #include "core/hle/service/erpt/erpt.h" | 8 | #include "core/hle/service/erpt/erpt.h" |
| 7 | #include "core/hle/service/server_manager.h" | 9 | #include "core/hle/service/server_manager.h" |
| 8 | #include "core/hle/service/service.h" | 10 | #include "core/hle/service/service.h" |
| @@ -15,7 +17,7 @@ public: | |||
| 15 | explicit ErrorReportContext(Core::System& system_) : ServiceFramework{system_, "erpt:c"} { | 17 | explicit ErrorReportContext(Core::System& system_) : ServiceFramework{system_, "erpt:c"} { |
| 16 | // clang-format off | 18 | // clang-format off |
| 17 | static const FunctionInfo functions[] = { | 19 | static const FunctionInfo functions[] = { |
| 18 | {0, nullptr, "SubmitContext"}, | 20 | {0, C<&ErrorReportContext::SubmitContext>, "SubmitContext"}, |
| 19 | {1, nullptr, "CreateReportV0"}, | 21 | {1, nullptr, "CreateReportV0"}, |
| 20 | {2, nullptr, "SetInitialLaunchSettingsCompletionTime"}, | 22 | {2, nullptr, "SetInitialLaunchSettingsCompletionTime"}, |
| 21 | {3, nullptr, "ClearInitialLaunchSettingsCompletionTime"}, | 23 | {3, nullptr, "ClearInitialLaunchSettingsCompletionTime"}, |
| @@ -36,6 +38,14 @@ public: | |||
| 36 | 38 | ||
| 37 | RegisterHandlers(functions); | 39 | RegisterHandlers(functions); |
| 38 | } | 40 | } |
| 41 | |||
| 42 | private: | ||
| 43 | Result SubmitContext(InBuffer<BufferAttr_HipcMapAlias> buffer_a, | ||
| 44 | InBuffer<BufferAttr_HipcMapAlias> buffer_b) { | ||
| 45 | LOG_WARNING(Service_SET, "(STUBBED) called, buffer_a_size={}, buffer_b_size={}", | ||
| 46 | buffer_a.size(), buffer_b.size()); | ||
| 47 | R_SUCCEED(); | ||
| 48 | } | ||
| 39 | }; | 49 | }; |
| 40 | 50 | ||
| 41 | class ErrorReportSession final : public ServiceFramework<ErrorReportSession> { | 51 | class ErrorReportSession final : public ServiceFramework<ErrorReportSession> { |
diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp index 63c2d3a58..2d49f30c8 100644 --- a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp | |||
| @@ -336,7 +336,7 @@ FSP_SRV::FSP_SRV(Core::System& system_) | |||
| 336 | {1012, nullptr, "GetFsStackUsage"}, | 336 | {1012, nullptr, "GetFsStackUsage"}, |
| 337 | {1013, nullptr, "UnsetSaveDataRootPath"}, | 337 | {1013, nullptr, "UnsetSaveDataRootPath"}, |
| 338 | {1014, nullptr, "OutputMultiProgramTagAccessLog"}, | 338 | {1014, nullptr, "OutputMultiProgramTagAccessLog"}, |
| 339 | {1016, nullptr, "FlushAccessLogOnSdCard"}, | 339 | {1016, &FSP_SRV::FlushAccessLogOnSdCard, "FlushAccessLogOnSdCard"}, |
| 340 | {1017, nullptr, "OutputApplicationInfoAccessLog"}, | 340 | {1017, nullptr, "OutputApplicationInfoAccessLog"}, |
| 341 | {1018, nullptr, "SetDebugOption"}, | 341 | {1018, nullptr, "SetDebugOption"}, |
| 342 | {1019, nullptr, "UnsetDebugOption"}, | 342 | {1019, nullptr, "UnsetDebugOption"}, |
| @@ -706,6 +706,13 @@ void FSP_SRV::GetProgramIndexForAccessLog(HLERequestContext& ctx) { | |||
| 706 | rb.Push(access_log_program_index); | 706 | rb.Push(access_log_program_index); |
| 707 | } | 707 | } |
| 708 | 708 | ||
| 709 | void FSP_SRV::FlushAccessLogOnSdCard(HLERequestContext& ctx) { | ||
| 710 | LOG_DEBUG(Service_FS, "(STUBBED) called"); | ||
| 711 | |||
| 712 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 713 | rb.Push(ResultSuccess); | ||
| 714 | } | ||
| 715 | |||
| 709 | void FSP_SRV::GetCacheStorageSize(HLERequestContext& ctx) { | 716 | void FSP_SRV::GetCacheStorageSize(HLERequestContext& ctx) { |
| 710 | IPC::RequestParser rp{ctx}; | 717 | IPC::RequestParser rp{ctx}; |
| 711 | const auto index{rp.Pop<s32>()}; | 718 | const auto index{rp.Pop<s32>()}; |
diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.h b/src/core/hle/service/filesystem/fsp/fsp_srv.h index 26980af99..59406e6f9 100644 --- a/src/core/hle/service/filesystem/fsp/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp/fsp_srv.h | |||
| @@ -58,6 +58,7 @@ private: | |||
| 58 | void SetGlobalAccessLogMode(HLERequestContext& ctx); | 58 | void SetGlobalAccessLogMode(HLERequestContext& ctx); |
| 59 | void GetGlobalAccessLogMode(HLERequestContext& ctx); | 59 | void GetGlobalAccessLogMode(HLERequestContext& ctx); |
| 60 | void OutputAccessLogToSdCard(HLERequestContext& ctx); | 60 | void OutputAccessLogToSdCard(HLERequestContext& ctx); |
| 61 | void FlushAccessLogOnSdCard(HLERequestContext& ctx); | ||
| 61 | void GetProgramIndexForAccessLog(HLERequestContext& ctx); | 62 | void GetProgramIndexForAccessLog(HLERequestContext& ctx); |
| 62 | void OpenMultiCommitManager(HLERequestContext& ctx); | 63 | void OpenMultiCommitManager(HLERequestContext& ctx); |
| 63 | void GetCacheStorageSize(HLERequestContext& ctx); | 64 | void GetCacheStorageSize(HLERequestContext& ctx); |
diff --git a/src/core/hle/service/glue/time/manager.cpp b/src/core/hle/service/glue/time/manager.cpp index cad755fa7..059ac3fc9 100644 --- a/src/core/hle/service/glue/time/manager.cpp +++ b/src/core/hle/service/glue/time/manager.cpp | |||
| @@ -186,6 +186,10 @@ TimeManager::TimeManager(Core::System& system) | |||
| 186 | } | 186 | } |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | TimeManager::~TimeManager() { | ||
| 190 | ResetTimeZoneBinary(); | ||
| 191 | } | ||
| 192 | |||
| 189 | Result TimeManager::SetupStandardSteadyClockCore() { | 193 | Result TimeManager::SetupStandardSteadyClockCore() { |
| 190 | Common::UUID external_clock_source_id{}; | 194 | Common::UUID external_clock_source_id{}; |
| 191 | auto res = m_set_sys->GetExternalSteadyClockSourceId(&external_clock_source_id); | 195 | auto res = m_set_sys->GetExternalSteadyClockSourceId(&external_clock_source_id); |
diff --git a/src/core/hle/service/glue/time/manager.h b/src/core/hle/service/glue/time/manager.h index 1de93f8f9..bb4b65049 100644 --- a/src/core/hle/service/glue/time/manager.h +++ b/src/core/hle/service/glue/time/manager.h | |||
| @@ -26,6 +26,7 @@ namespace Service::Glue::Time { | |||
| 26 | class TimeManager { | 26 | class TimeManager { |
| 27 | public: | 27 | public: |
| 28 | explicit TimeManager(Core::System& system); | 28 | explicit TimeManager(Core::System& system); |
| 29 | ~TimeManager(); | ||
| 29 | 30 | ||
| 30 | std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; | 31 | std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; |
| 31 | 32 | ||
diff --git a/src/core/hle/service/glue/time/static.cpp b/src/core/hle/service/glue/time/static.cpp index ec9b0efb1..b801faef2 100644 --- a/src/core/hle/service/glue/time/static.cpp +++ b/src/core/hle/service/glue/time/static.cpp | |||
| @@ -142,16 +142,18 @@ Result StaticService::SetStandardSteadyClockInternalOffset(s64 offset_ns) { | |||
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | Result StaticService::GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value) { | 144 | Result StaticService::GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value) { |
| 145 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value); }); | 145 | SCOPE_EXIT { |
| 146 | LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value); | ||
| 147 | }; | ||
| 146 | 148 | ||
| 147 | R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(*out_rtc_value)); | 149 | R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(*out_rtc_value)); |
| 148 | } | 150 | } |
| 149 | 151 | ||
| 150 | Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled( | 152 | Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled( |
| 151 | Out<bool> out_automatic_correction) { | 153 | Out<bool> out_automatic_correction) { |
| 152 | SCOPE_EXIT({ | 154 | SCOPE_EXIT { |
| 153 | LOG_DEBUG(Service_Time, "called. out_automatic_correction={}", *out_automatic_correction); | 155 | LOG_DEBUG(Service_Time, "called. out_automatic_correction={}", *out_automatic_correction); |
| 154 | }); | 156 | }; |
| 155 | 157 | ||
| 156 | R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled( | 158 | R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled( |
| 157 | out_automatic_correction)); | 159 | out_automatic_correction)); |
| @@ -166,21 +168,27 @@ Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled( | |||
| 166 | } | 168 | } |
| 167 | 169 | ||
| 168 | Result StaticService::GetStandardUserSystemClockInitialYear(Out<s32> out_year) { | 170 | Result StaticService::GetStandardUserSystemClockInitialYear(Out<s32> out_year) { |
| 169 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_year={}", *out_year); }); | 171 | SCOPE_EXIT { |
| 172 | LOG_DEBUG(Service_Time, "called. out_year={}", *out_year); | ||
| 173 | }; | ||
| 170 | 174 | ||
| 171 | R_RETURN(m_set_sys->GetSettingsItemValueImpl<s32>(*out_year, "time", | 175 | R_RETURN(m_set_sys->GetSettingsItemValueImpl<s32>(*out_year, "time", |
| 172 | "standard_user_clock_initial_year")); | 176 | "standard_user_clock_initial_year")); |
| 173 | } | 177 | } |
| 174 | 178 | ||
| 175 | Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) { | 179 | Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) { |
| 176 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient); }); | 180 | SCOPE_EXIT { |
| 181 | LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient); | ||
| 182 | }; | ||
| 177 | 183 | ||
| 178 | R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient)); | 184 | R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient)); |
| 179 | } | 185 | } |
| 180 | 186 | ||
| 181 | Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( | 187 | Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( |
| 182 | Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) { | 188 | Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) { |
| 183 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); }); | 189 | SCOPE_EXIT { |
| 190 | LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); | ||
| 191 | }; | ||
| 184 | 192 | ||
| 185 | R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( | 193 | R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( |
| 186 | out_time_point)); | 194 | out_time_point)); |
| @@ -188,15 +196,18 @@ Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( | |||
| 188 | 196 | ||
| 189 | Result StaticService::CalculateMonotonicSystemClockBaseTimePoint( | 197 | Result StaticService::CalculateMonotonicSystemClockBaseTimePoint( |
| 190 | Out<s64> out_time, const Service::PSC::Time::SystemClockContext& context) { | 198 | Out<s64> out_time, const Service::PSC::Time::SystemClockContext& context) { |
| 191 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); }); | 199 | SCOPE_EXIT { |
| 200 | LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); | ||
| 201 | }; | ||
| 192 | 202 | ||
| 193 | R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context)); | 203 | R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context)); |
| 194 | } | 204 | } |
| 195 | 205 | ||
| 196 | Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, | 206 | Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, |
| 197 | Service::PSC::Time::TimeType type) { | 207 | Service::PSC::Time::TimeType type) { |
| 198 | SCOPE_EXIT( | 208 | SCOPE_EXIT { |
| 199 | { LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot); }); | 209 | LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot); |
| 210 | }; | ||
| 200 | 211 | ||
| 201 | R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type)); | 212 | R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type)); |
| 202 | } | 213 | } |
| @@ -205,11 +216,11 @@ Result StaticService::GetClockSnapshotFromSystemClockContext( | |||
| 205 | Service::PSC::Time::TimeType type, OutClockSnapshot out_snapshot, | 216 | Service::PSC::Time::TimeType type, OutClockSnapshot out_snapshot, |
| 206 | const Service::PSC::Time::SystemClockContext& user_context, | 217 | const Service::PSC::Time::SystemClockContext& user_context, |
| 207 | const Service::PSC::Time::SystemClockContext& network_context) { | 218 | const Service::PSC::Time::SystemClockContext& network_context) { |
| 208 | SCOPE_EXIT({ | 219 | SCOPE_EXIT { |
| 209 | LOG_DEBUG(Service_Time, | 220 | LOG_DEBUG(Service_Time, |
| 210 | "called. type={} out_snapshot={} user_context={} network_context={}", type, | 221 | "called. type={} out_snapshot={} user_context={} network_context={}", type, |
| 211 | *out_snapshot, user_context, network_context); | 222 | *out_snapshot, user_context, network_context); |
| 212 | }); | 223 | }; |
| 213 | 224 | ||
| 214 | R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext( | 225 | R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext( |
| 215 | type, out_snapshot, user_context, network_context)); | 226 | type, out_snapshot, user_context, network_context)); |
| @@ -218,14 +229,18 @@ Result StaticService::GetClockSnapshotFromSystemClockContext( | |||
| 218 | Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_time, | 229 | Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_time, |
| 219 | InClockSnapshot a, | 230 | InClockSnapshot a, |
| 220 | InClockSnapshot b) { | 231 | InClockSnapshot b) { |
| 221 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); }); | 232 | SCOPE_EXIT { |
| 233 | LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); | ||
| 234 | }; | ||
| 222 | 235 | ||
| 223 | R_RETURN(m_wrapped_service->CalculateStandardUserSystemClockDifferenceByUser(out_time, a, b)); | 236 | R_RETURN(m_wrapped_service->CalculateStandardUserSystemClockDifferenceByUser(out_time, a, b)); |
| 224 | } | 237 | } |
| 225 | 238 | ||
| 226 | Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a, | 239 | Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a, |
| 227 | InClockSnapshot b) { | 240 | InClockSnapshot b) { |
| 228 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); }); | 241 | SCOPE_EXIT { |
| 242 | LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); | ||
| 243 | }; | ||
| 229 | 244 | ||
| 230 | R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b)); | 245 | R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b)); |
| 231 | } | 246 | } |
diff --git a/src/core/hle/service/glue/time/time_zone.cpp b/src/core/hle/service/glue/time/time_zone.cpp index 36f163419..f4d0c87d5 100644 --- a/src/core/hle/service/glue/time/time_zone.cpp +++ b/src/core/hle/service/glue/time/time_zone.cpp | |||
| @@ -57,7 +57,9 @@ TimeZoneService::~TimeZoneService() = default; | |||
| 57 | 57 | ||
| 58 | Result TimeZoneService::GetDeviceLocationName( | 58 | Result TimeZoneService::GetDeviceLocationName( |
| 59 | Out<Service::PSC::Time::LocationName> out_location_name) { | 59 | Out<Service::PSC::Time::LocationName> out_location_name) { |
| 60 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name); }); | 60 | SCOPE_EXIT { |
| 61 | LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name); | ||
| 62 | }; | ||
| 61 | 63 | ||
| 62 | R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name)); | 64 | R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name)); |
| 63 | } | 65 | } |
| @@ -94,7 +96,9 @@ Result TimeZoneService::SetDeviceLocationName( | |||
| 94 | } | 96 | } |
| 95 | 97 | ||
| 96 | Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) { | 98 | Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) { |
| 97 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_count={}", *out_count); }); | 99 | SCOPE_EXIT { |
| 100 | LOG_DEBUG(Service_Time, "called. out_count={}", *out_count); | ||
| 101 | }; | ||
| 98 | 102 | ||
| 99 | R_RETURN(m_wrapped_service->GetTotalLocationNameCount(out_count)); | 103 | R_RETURN(m_wrapped_service->GetTotalLocationNameCount(out_count)); |
| 100 | } | 104 | } |
| @@ -102,10 +106,10 @@ Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) { | |||
| 102 | Result TimeZoneService::LoadLocationNameList( | 106 | Result TimeZoneService::LoadLocationNameList( |
| 103 | Out<u32> out_count, | 107 | Out<u32> out_count, |
| 104 | OutArray<Service::PSC::Time::LocationName, BufferAttr_HipcMapAlias> out_names, u32 index) { | 108 | OutArray<Service::PSC::Time::LocationName, BufferAttr_HipcMapAlias> out_names, u32 index) { |
| 105 | SCOPE_EXIT({ | 109 | SCOPE_EXIT { |
| 106 | LOG_DEBUG(Service_Time, "called. index={} out_count={} out_names[0]={} out_names[1]={}", | 110 | LOG_DEBUG(Service_Time, "called. index={} out_count={} out_names[0]={} out_names[1]={}", |
| 107 | index, *out_count, out_names[0], out_names[1]); | 111 | index, *out_count, out_names[0], out_names[1]); |
| 108 | }); | 112 | }; |
| 109 | 113 | ||
| 110 | std::scoped_lock l{m_mutex}; | 114 | std::scoped_lock l{m_mutex}; |
| 111 | R_RETURN(GetTimeZoneLocationList(*out_count, out_names, out_names.size(), index)); | 115 | R_RETURN(GetTimeZoneLocationList(*out_count, out_names, out_names.size(), index)); |
| @@ -124,7 +128,9 @@ Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule, | |||
| 124 | 128 | ||
| 125 | Result TimeZoneService::GetTimeZoneRuleVersion( | 129 | Result TimeZoneService::GetTimeZoneRuleVersion( |
| 126 | Out<Service::PSC::Time::RuleVersion> out_rule_version) { | 130 | Out<Service::PSC::Time::RuleVersion> out_rule_version) { |
| 127 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version); }); | 131 | SCOPE_EXIT { |
| 132 | LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version); | ||
| 133 | }; | ||
| 128 | 134 | ||
| 129 | R_RETURN(m_wrapped_service->GetTimeZoneRuleVersion(out_rule_version)); | 135 | R_RETURN(m_wrapped_service->GetTimeZoneRuleVersion(out_rule_version)); |
| 130 | } | 136 | } |
| @@ -132,10 +138,10 @@ Result TimeZoneService::GetTimeZoneRuleVersion( | |||
| 132 | Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime( | 138 | Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime( |
| 133 | Out<Service::PSC::Time::LocationName> location_name, | 139 | Out<Service::PSC::Time::LocationName> location_name, |
| 134 | Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) { | 140 | Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) { |
| 135 | SCOPE_EXIT({ | 141 | SCOPE_EXIT { |
| 136 | LOG_DEBUG(Service_Time, "called. location_name={} out_time_point={}", *location_name, | 142 | LOG_DEBUG(Service_Time, "called. location_name={} out_time_point={}", *location_name, |
| 137 | *out_time_point); | 143 | *out_time_point); |
| 138 | }); | 144 | }; |
| 139 | 145 | ||
| 140 | R_RETURN(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(location_name, out_time_point)); | 146 | R_RETURN(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(location_name, out_time_point)); |
| 141 | } | 147 | } |
| @@ -178,10 +184,10 @@ Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle( | |||
| 178 | Result TimeZoneService::ToCalendarTime( | 184 | Result TimeZoneService::ToCalendarTime( |
| 179 | Out<Service::PSC::Time::CalendarTime> out_calendar_time, | 185 | Out<Service::PSC::Time::CalendarTime> out_calendar_time, |
| 180 | Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time, InRule rule) { | 186 | Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time, InRule rule) { |
| 181 | SCOPE_EXIT({ | 187 | SCOPE_EXIT { |
| 182 | LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, | 188 | LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, |
| 183 | *out_calendar_time, *out_additional_info); | 189 | *out_calendar_time, *out_additional_info); |
| 184 | }); | 190 | }; |
| 185 | 191 | ||
| 186 | R_RETURN(m_wrapped_service->ToCalendarTime(out_calendar_time, out_additional_info, time, rule)); | 192 | R_RETURN(m_wrapped_service->ToCalendarTime(out_calendar_time, out_additional_info, time, rule)); |
| 187 | } | 193 | } |
| @@ -189,10 +195,10 @@ Result TimeZoneService::ToCalendarTime( | |||
| 189 | Result TimeZoneService::ToCalendarTimeWithMyRule( | 195 | Result TimeZoneService::ToCalendarTimeWithMyRule( |
| 190 | Out<Service::PSC::Time::CalendarTime> out_calendar_time, | 196 | Out<Service::PSC::Time::CalendarTime> out_calendar_time, |
| 191 | Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time) { | 197 | Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time) { |
| 192 | SCOPE_EXIT({ | 198 | SCOPE_EXIT { |
| 193 | LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, | 199 | LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, |
| 194 | *out_calendar_time, *out_additional_info); | 200 | *out_calendar_time, *out_additional_info); |
| 195 | }); | 201 | }; |
| 196 | 202 | ||
| 197 | R_RETURN( | 203 | R_RETURN( |
| 198 | m_wrapped_service->ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time)); | 204 | m_wrapped_service->ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time)); |
| @@ -202,11 +208,11 @@ Result TimeZoneService::ToPosixTime(Out<u32> out_count, | |||
| 202 | OutArray<s64, BufferAttr_HipcPointer> out_times, | 208 | OutArray<s64, BufferAttr_HipcPointer> out_times, |
| 203 | const Service::PSC::Time::CalendarTime& calendar_time, | 209 | const Service::PSC::Time::CalendarTime& calendar_time, |
| 204 | InRule rule) { | 210 | InRule rule) { |
| 205 | SCOPE_EXIT({ | 211 | SCOPE_EXIT { |
| 206 | LOG_DEBUG(Service_Time, | 212 | LOG_DEBUG(Service_Time, |
| 207 | "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}", | 213 | "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}", |
| 208 | calendar_time, *out_count, out_times[0], out_times[1]); | 214 | calendar_time, *out_count, out_times[0], out_times[1]); |
| 209 | }); | 215 | }; |
| 210 | 216 | ||
| 211 | R_RETURN(m_wrapped_service->ToPosixTime(out_count, out_times, calendar_time, rule)); | 217 | R_RETURN(m_wrapped_service->ToPosixTime(out_count, out_times, calendar_time, rule)); |
| 212 | } | 218 | } |
| @@ -214,11 +220,11 @@ Result TimeZoneService::ToPosixTime(Out<u32> out_count, | |||
| 214 | Result TimeZoneService::ToPosixTimeWithMyRule( | 220 | Result TimeZoneService::ToPosixTimeWithMyRule( |
| 215 | Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times, | 221 | Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times, |
| 216 | const Service::PSC::Time::CalendarTime& calendar_time) { | 222 | const Service::PSC::Time::CalendarTime& calendar_time) { |
| 217 | SCOPE_EXIT({ | 223 | SCOPE_EXIT { |
| 218 | LOG_DEBUG(Service_Time, | 224 | LOG_DEBUG(Service_Time, |
| 219 | "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}", | 225 | "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}", |
| 220 | calendar_time, *out_count, out_times[0], out_times[1]); | 226 | calendar_time, *out_count, out_times[0], out_times[1]); |
| 221 | }); | 227 | }; |
| 222 | 228 | ||
| 223 | R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, calendar_time)); | 229 | R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, calendar_time)); |
| 224 | } | 230 | } |
diff --git a/src/core/hle/service/ns/account_proxy_interface.cpp b/src/core/hle/service/ns/account_proxy_interface.cpp new file mode 100644 index 000000000..e5041af66 --- /dev/null +++ b/src/core/hle/service/ns/account_proxy_interface.cpp | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/ns/account_proxy_interface.h" | ||
| 5 | |||
| 6 | namespace Service::NS { | ||
| 7 | |||
| 8 | IAccountProxyInterface::IAccountProxyInterface(Core::System& system_) | ||
| 9 | : ServiceFramework{system_, "IAccountProxyInterface"} { | ||
| 10 | // clang-format off | ||
| 11 | static const FunctionInfo functions[] = { | ||
| 12 | {0, nullptr, "CreateUserAccount"}, | ||
| 13 | }; | ||
| 14 | // clang-format on | ||
| 15 | |||
| 16 | RegisterHandlers(functions); | ||
| 17 | } | ||
| 18 | |||
| 19 | IAccountProxyInterface::~IAccountProxyInterface() = default; | ||
| 20 | |||
| 21 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/account_proxy_interface.h b/src/core/hle/service/ns/account_proxy_interface.h new file mode 100644 index 000000000..e944d2a75 --- /dev/null +++ b/src/core/hle/service/ns/account_proxy_interface.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/service.h" | ||
| 7 | |||
| 8 | namespace Service::NS { | ||
| 9 | |||
| 10 | class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> { | ||
| 11 | public: | ||
| 12 | explicit IAccountProxyInterface(Core::System& system_); | ||
| 13 | ~IAccountProxyInterface() override; | ||
| 14 | }; | ||
| 15 | |||
| 16 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/application_manager_interface.cpp b/src/core/hle/service/ns/application_manager_interface.cpp new file mode 100644 index 000000000..2e3a44c0d --- /dev/null +++ b/src/core/hle/service/ns/application_manager_interface.cpp | |||
| @@ -0,0 +1,519 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/file_sys/nca_metadata.h" | ||
| 5 | #include "core/file_sys/registered_cache.h" | ||
| 6 | #include "core/hle/service/cmif_serialization.h" | ||
| 7 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 8 | #include "core/hle/service/ns/application_manager_interface.h" | ||
| 9 | #include "core/hle/service/ns/content_management_interface.h" | ||
| 10 | #include "core/hle/service/ns/read_only_application_control_data_interface.h" | ||
| 11 | |||
| 12 | namespace Service::NS { | ||
| 13 | |||
| 14 | IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_) | ||
| 15 | : ServiceFramework{system_, "IApplicationManagerInterface"}, | ||
| 16 | service_context{system, "IApplicationManagerInterface"}, | ||
| 17 | record_update_system_event{service_context}, sd_card_mount_status_event{service_context}, | ||
| 18 | gamecard_update_detection_event{service_context}, | ||
| 19 | gamecard_mount_status_event{service_context}, gamecard_mount_failure_event{service_context} { | ||
| 20 | // clang-format off | ||
| 21 | static const FunctionInfo functions[] = { | ||
| 22 | {0, D<&IApplicationManagerInterface::ListApplicationRecord>, "ListApplicationRecord"}, | ||
| 23 | {1, nullptr, "GenerateApplicationRecordCount"}, | ||
| 24 | {2, D<&IApplicationManagerInterface::GetApplicationRecordUpdateSystemEvent>, "GetApplicationRecordUpdateSystemEvent"}, | ||
| 25 | {3, nullptr, "GetApplicationViewDeprecated"}, | ||
| 26 | {4, nullptr, "DeleteApplicationEntity"}, | ||
| 27 | {5, nullptr, "DeleteApplicationCompletely"}, | ||
| 28 | {6, nullptr, "IsAnyApplicationEntityRedundant"}, | ||
| 29 | {7, nullptr, "DeleteRedundantApplicationEntity"}, | ||
| 30 | {8, nullptr, "IsApplicationEntityMovable"}, | ||
| 31 | {9, nullptr, "MoveApplicationEntity"}, | ||
| 32 | {11, nullptr, "CalculateApplicationOccupiedSize"}, | ||
| 33 | {16, nullptr, "PushApplicationRecord"}, | ||
| 34 | {17, nullptr, "ListApplicationRecordContentMeta"}, | ||
| 35 | {19, nullptr, "LaunchApplicationOld"}, | ||
| 36 | {21, nullptr, "GetApplicationContentPath"}, | ||
| 37 | {22, nullptr, "TerminateApplication"}, | ||
| 38 | {23, nullptr, "ResolveApplicationContentPath"}, | ||
| 39 | {26, nullptr, "BeginInstallApplication"}, | ||
| 40 | {27, nullptr, "DeleteApplicationRecord"}, | ||
| 41 | {30, nullptr, "RequestApplicationUpdateInfo"}, | ||
| 42 | {31, nullptr, "Unknown31"}, | ||
| 43 | {32, nullptr, "CancelApplicationDownload"}, | ||
| 44 | {33, nullptr, "ResumeApplicationDownload"}, | ||
| 45 | {35, nullptr, "UpdateVersionList"}, | ||
| 46 | {36, nullptr, "PushLaunchVersion"}, | ||
| 47 | {37, nullptr, "ListRequiredVersion"}, | ||
| 48 | {38, D<&IApplicationManagerInterface::CheckApplicationLaunchVersion>, "CheckApplicationLaunchVersion"}, | ||
| 49 | {39, nullptr, "CheckApplicationLaunchRights"}, | ||
| 50 | {40, nullptr, "GetApplicationLogoData"}, | ||
| 51 | {41, nullptr, "CalculateApplicationDownloadRequiredSize"}, | ||
| 52 | {42, nullptr, "CleanupSdCard"}, | ||
| 53 | {43, D<&IApplicationManagerInterface::CheckSdCardMountStatus>, "CheckSdCardMountStatus"}, | ||
| 54 | {44, D<&IApplicationManagerInterface::GetSdCardMountStatusChangedEvent>, "GetSdCardMountStatusChangedEvent"}, | ||
| 55 | {45, nullptr, "GetGameCardAttachmentEvent"}, | ||
| 56 | {46, nullptr, "GetGameCardAttachmentInfo"}, | ||
| 57 | {47, nullptr, "GetTotalSpaceSize"}, | ||
| 58 | {48, D<&IApplicationManagerInterface::GetFreeSpaceSize>, "GetFreeSpaceSize"}, | ||
| 59 | {49, nullptr, "GetSdCardRemovedEvent"}, | ||
| 60 | {52, D<&IApplicationManagerInterface::GetGameCardUpdateDetectionEvent>, "GetGameCardUpdateDetectionEvent"}, | ||
| 61 | {53, nullptr, "DisableApplicationAutoDelete"}, | ||
| 62 | {54, nullptr, "EnableApplicationAutoDelete"}, | ||
| 63 | {55, D<&IApplicationManagerInterface::GetApplicationDesiredLanguage>, "GetApplicationDesiredLanguage"}, | ||
| 64 | {56, nullptr, "SetApplicationTerminateResult"}, | ||
| 65 | {57, nullptr, "ClearApplicationTerminateResult"}, | ||
| 66 | {58, nullptr, "GetLastSdCardMountUnexpectedResult"}, | ||
| 67 | {59, D<&IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode>, "ConvertApplicationLanguageToLanguageCode"}, | ||
| 68 | {60, nullptr, "ConvertLanguageCodeToApplicationLanguage"}, | ||
| 69 | {61, nullptr, "GetBackgroundDownloadStressTaskInfo"}, | ||
| 70 | {62, nullptr, "GetGameCardStopper"}, | ||
| 71 | {63, nullptr, "IsSystemProgramInstalled"}, | ||
| 72 | {64, nullptr, "StartApplyDeltaTask"}, | ||
| 73 | {65, nullptr, "GetRequestServerStopper"}, | ||
| 74 | {66, nullptr, "GetBackgroundApplyDeltaStressTaskInfo"}, | ||
| 75 | {67, nullptr, "CancelApplicationApplyDelta"}, | ||
| 76 | {68, nullptr, "ResumeApplicationApplyDelta"}, | ||
| 77 | {69, nullptr, "CalculateApplicationApplyDeltaRequiredSize"}, | ||
| 78 | {70, D<&IApplicationManagerInterface::ResumeAll>, "ResumeAll"}, | ||
| 79 | {71, D<&IApplicationManagerInterface::GetStorageSize>, "GetStorageSize"}, | ||
| 80 | {80, nullptr, "RequestDownloadApplication"}, | ||
| 81 | {81, nullptr, "RequestDownloadAddOnContent"}, | ||
| 82 | {82, nullptr, "DownloadApplication"}, | ||
| 83 | {83, nullptr, "CheckApplicationResumeRights"}, | ||
| 84 | {84, nullptr, "GetDynamicCommitEvent"}, | ||
| 85 | {85, nullptr, "RequestUpdateApplication2"}, | ||
| 86 | {86, nullptr, "EnableApplicationCrashReport"}, | ||
| 87 | {87, nullptr, "IsApplicationCrashReportEnabled"}, | ||
| 88 | {90, nullptr, "BoostSystemMemoryResourceLimit"}, | ||
| 89 | {91, nullptr, "DeprecatedLaunchApplication"}, | ||
| 90 | {92, nullptr, "GetRunningApplicationProgramId"}, | ||
| 91 | {93, nullptr, "GetMainApplicationProgramIndex"}, | ||
| 92 | {94, nullptr, "LaunchApplication"}, | ||
| 93 | {95, nullptr, "GetApplicationLaunchInfo"}, | ||
| 94 | {96, nullptr, "AcquireApplicationLaunchInfo"}, | ||
| 95 | {97, nullptr, "GetMainApplicationProgramIndexByApplicationLaunchInfo"}, | ||
| 96 | {98, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, | ||
| 97 | {99, nullptr, "LaunchDevMenu"}, | ||
| 98 | {100, nullptr, "ResetToFactorySettings"}, | ||
| 99 | {101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"}, | ||
| 100 | {102, nullptr, "ResetToFactorySettingsForRefurbishment"}, | ||
| 101 | {103, nullptr, "ResetToFactorySettingsWithPlatformRegion"}, | ||
| 102 | {104, nullptr, "ResetToFactorySettingsWithPlatformRegionAuthentication"}, | ||
| 103 | {105, nullptr, "RequestResetToFactorySettingsSecurely"}, | ||
| 104 | {106, nullptr, "RequestResetToFactorySettingsWithPlatformRegionAuthenticationSecurely"}, | ||
| 105 | {200, nullptr, "CalculateUserSaveDataStatistics"}, | ||
| 106 | {201, nullptr, "DeleteUserSaveDataAll"}, | ||
| 107 | {210, nullptr, "DeleteUserSystemSaveData"}, | ||
| 108 | {211, nullptr, "DeleteSaveData"}, | ||
| 109 | {220, nullptr, "UnregisterNetworkServiceAccount"}, | ||
| 110 | {221, nullptr, "UnregisterNetworkServiceAccountWithUserSaveDataDeletion"}, | ||
| 111 | {300, nullptr, "GetApplicationShellEvent"}, | ||
| 112 | {301, nullptr, "PopApplicationShellEventInfo"}, | ||
| 113 | {302, nullptr, "LaunchLibraryApplet"}, | ||
| 114 | {303, nullptr, "TerminateLibraryApplet"}, | ||
| 115 | {304, nullptr, "LaunchSystemApplet"}, | ||
| 116 | {305, nullptr, "TerminateSystemApplet"}, | ||
| 117 | {306, nullptr, "LaunchOverlayApplet"}, | ||
| 118 | {307, nullptr, "TerminateOverlayApplet"}, | ||
| 119 | {400, D<&IApplicationManagerInterface::GetApplicationControlData>, "GetApplicationControlData"}, | ||
| 120 | {401, nullptr, "InvalidateAllApplicationControlCache"}, | ||
| 121 | {402, nullptr, "RequestDownloadApplicationControlData"}, | ||
| 122 | {403, nullptr, "GetMaxApplicationControlCacheCount"}, | ||
| 123 | {404, nullptr, "InvalidateApplicationControlCache"}, | ||
| 124 | {405, nullptr, "ListApplicationControlCacheEntryInfo"}, | ||
| 125 | {406, nullptr, "GetApplicationControlProperty"}, | ||
| 126 | {407, nullptr, "ListApplicationTitle"}, | ||
| 127 | {408, nullptr, "ListApplicationIcon"}, | ||
| 128 | {502, nullptr, "RequestCheckGameCardRegistration"}, | ||
| 129 | {503, nullptr, "RequestGameCardRegistrationGoldPoint"}, | ||
| 130 | {504, nullptr, "RequestRegisterGameCard"}, | ||
| 131 | {505, D<&IApplicationManagerInterface::GetGameCardMountFailureEvent>, "GetGameCardMountFailureEvent"}, | ||
| 132 | {506, nullptr, "IsGameCardInserted"}, | ||
| 133 | {507, nullptr, "EnsureGameCardAccess"}, | ||
| 134 | {508, nullptr, "GetLastGameCardMountFailureResult"}, | ||
| 135 | {509, nullptr, "ListApplicationIdOnGameCard"}, | ||
| 136 | {510, nullptr, "GetGameCardPlatformRegion"}, | ||
| 137 | {600, nullptr, "CountApplicationContentMeta"}, | ||
| 138 | {601, nullptr, "ListApplicationContentMetaStatus"}, | ||
| 139 | {602, nullptr, "ListAvailableAddOnContent"}, | ||
| 140 | {603, nullptr, "GetOwnedApplicationContentMetaStatus"}, | ||
| 141 | {604, nullptr, "RegisterContentsExternalKey"}, | ||
| 142 | {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"}, | ||
| 143 | {606, nullptr, "GetContentMetaStorage"}, | ||
| 144 | {607, nullptr, "ListAvailableAddOnContent"}, | ||
| 145 | {609, nullptr, "ListAvailabilityAssuredAddOnContent"}, | ||
| 146 | {610, nullptr, "GetInstalledContentMetaStorage"}, | ||
| 147 | {611, nullptr, "PrepareAddOnContent"}, | ||
| 148 | {700, nullptr, "PushDownloadTaskList"}, | ||
| 149 | {701, nullptr, "ClearTaskStatusList"}, | ||
| 150 | {702, nullptr, "RequestDownloadTaskList"}, | ||
| 151 | {703, nullptr, "RequestEnsureDownloadTask"}, | ||
| 152 | {704, nullptr, "ListDownloadTaskStatus"}, | ||
| 153 | {705, nullptr, "RequestDownloadTaskListData"}, | ||
| 154 | {800, nullptr, "RequestVersionList"}, | ||
| 155 | {801, nullptr, "ListVersionList"}, | ||
| 156 | {802, nullptr, "RequestVersionListData"}, | ||
| 157 | {900, nullptr, "GetApplicationRecord"}, | ||
| 158 | {901, nullptr, "GetApplicationRecordProperty"}, | ||
| 159 | {902, nullptr, "EnableApplicationAutoUpdate"}, | ||
| 160 | {903, nullptr, "DisableApplicationAutoUpdate"}, | ||
| 161 | {904, nullptr, "TouchApplication"}, | ||
| 162 | {905, nullptr, "RequestApplicationUpdate"}, | ||
| 163 | {906, D<&IApplicationManagerInterface::IsApplicationUpdateRequested>, "IsApplicationUpdateRequested"}, | ||
| 164 | {907, nullptr, "WithdrawApplicationUpdateRequest"}, | ||
| 165 | {908, nullptr, "ListApplicationRecordInstalledContentMeta"}, | ||
| 166 | {909, nullptr, "WithdrawCleanupAddOnContentsWithNoRightsRecommendation"}, | ||
| 167 | {910, nullptr, "HasApplicationRecord"}, | ||
| 168 | {911, nullptr, "SetPreInstalledApplication"}, | ||
| 169 | {912, nullptr, "ClearPreInstalledApplicationFlag"}, | ||
| 170 | {913, nullptr, "ListAllApplicationRecord"}, | ||
| 171 | {914, nullptr, "HideApplicationRecord"}, | ||
| 172 | {915, nullptr, "ShowApplicationRecord"}, | ||
| 173 | {916, nullptr, "IsApplicationAutoDeleteDisabled"}, | ||
| 174 | {1000, nullptr, "RequestVerifyApplicationDeprecated"}, | ||
| 175 | {1001, nullptr, "CorruptApplicationForDebug"}, | ||
| 176 | {1002, nullptr, "RequestVerifyAddOnContentsRights"}, | ||
| 177 | {1003, nullptr, "RequestVerifyApplication"}, | ||
| 178 | {1004, nullptr, "CorruptContentForDebug"}, | ||
| 179 | {1200, nullptr, "NeedsUpdateVulnerability"}, | ||
| 180 | {1300, D<&IApplicationManagerInterface::IsAnyApplicationEntityInstalled>, "IsAnyApplicationEntityInstalled"}, | ||
| 181 | {1301, nullptr, "DeleteApplicationContentEntities"}, | ||
| 182 | {1302, nullptr, "CleanupUnrecordedApplicationEntity"}, | ||
| 183 | {1303, nullptr, "CleanupAddOnContentsWithNoRights"}, | ||
| 184 | {1304, nullptr, "DeleteApplicationContentEntity"}, | ||
| 185 | {1305, nullptr, "TryDeleteRunningApplicationEntity"}, | ||
| 186 | {1306, nullptr, "TryDeleteRunningApplicationCompletely"}, | ||
| 187 | {1307, nullptr, "TryDeleteRunningApplicationContentEntities"}, | ||
| 188 | {1308, nullptr, "DeleteApplicationCompletelyForDebug"}, | ||
| 189 | {1309, nullptr, "CleanupUnavailableAddOnContents"}, | ||
| 190 | {1310, nullptr, "RequestMoveApplicationEntity"}, | ||
| 191 | {1311, nullptr, "EstimateSizeToMove"}, | ||
| 192 | {1312, nullptr, "HasMovableEntity"}, | ||
| 193 | {1313, nullptr, "CleanupOrphanContents"}, | ||
| 194 | {1314, nullptr, "CheckPreconditionSatisfiedToMove"}, | ||
| 195 | {1400, nullptr, "PrepareShutdown"}, | ||
| 196 | {1500, nullptr, "FormatSdCard"}, | ||
| 197 | {1501, nullptr, "NeedsSystemUpdateToFormatSdCard"}, | ||
| 198 | {1502, nullptr, "GetLastSdCardFormatUnexpectedResult"}, | ||
| 199 | {1504, nullptr, "InsertSdCard"}, | ||
| 200 | {1505, nullptr, "RemoveSdCard"}, | ||
| 201 | {1506, nullptr, "GetSdCardStartupStatus"}, | ||
| 202 | {1600, nullptr, "GetSystemSeedForPseudoDeviceId"}, | ||
| 203 | {1601, nullptr, "ResetSystemSeedForPseudoDeviceId"}, | ||
| 204 | {1700, nullptr, "ListApplicationDownloadingContentMeta"}, | ||
| 205 | {1701, D<&IApplicationManagerInterface::GetApplicationView>, "GetApplicationView"}, | ||
| 206 | {1702, nullptr, "GetApplicationDownloadTaskStatus"}, | ||
| 207 | {1703, nullptr, "GetApplicationViewDownloadErrorContext"}, | ||
| 208 | {1704, D<&IApplicationManagerInterface::GetApplicationViewWithPromotionInfo>, "GetApplicationViewWithPromotionInfo"}, | ||
| 209 | {1705, nullptr, "IsPatchAutoDeletableApplication"}, | ||
| 210 | {1800, nullptr, "IsNotificationSetupCompleted"}, | ||
| 211 | {1801, nullptr, "GetLastNotificationInfoCount"}, | ||
| 212 | {1802, nullptr, "ListLastNotificationInfo"}, | ||
| 213 | {1803, nullptr, "ListNotificationTask"}, | ||
| 214 | {1900, nullptr, "IsActiveAccount"}, | ||
| 215 | {1901, nullptr, "RequestDownloadApplicationPrepurchasedRights"}, | ||
| 216 | {1902, nullptr, "GetApplicationTicketInfo"}, | ||
| 217 | {1903, nullptr, "RequestDownloadApplicationPrepurchasedRightsForAccount"}, | ||
| 218 | {2000, nullptr, "GetSystemDeliveryInfo"}, | ||
| 219 | {2001, nullptr, "SelectLatestSystemDeliveryInfo"}, | ||
| 220 | {2002, nullptr, "VerifyDeliveryProtocolVersion"}, | ||
| 221 | {2003, nullptr, "GetApplicationDeliveryInfo"}, | ||
| 222 | {2004, nullptr, "HasAllContentsToDeliver"}, | ||
| 223 | {2005, nullptr, "CompareApplicationDeliveryInfo"}, | ||
| 224 | {2006, nullptr, "CanDeliverApplication"}, | ||
| 225 | {2007, nullptr, "ListContentMetaKeyToDeliverApplication"}, | ||
| 226 | {2008, nullptr, "NeedsSystemUpdateToDeliverApplication"}, | ||
| 227 | {2009, nullptr, "EstimateRequiredSize"}, | ||
| 228 | {2010, nullptr, "RequestReceiveApplication"}, | ||
| 229 | {2011, nullptr, "CommitReceiveApplication"}, | ||
| 230 | {2012, nullptr, "GetReceiveApplicationProgress"}, | ||
| 231 | {2013, nullptr, "RequestSendApplication"}, | ||
| 232 | {2014, nullptr, "GetSendApplicationProgress"}, | ||
| 233 | {2015, nullptr, "CompareSystemDeliveryInfo"}, | ||
| 234 | {2016, nullptr, "ListNotCommittedContentMeta"}, | ||
| 235 | {2017, nullptr, "CreateDownloadTask"}, | ||
| 236 | {2018, nullptr, "GetApplicationDeliveryInfoHash"}, | ||
| 237 | {2050, D<&IApplicationManagerInterface::GetApplicationRightsOnClient>, "GetApplicationRightsOnClient"}, | ||
| 238 | {2051, nullptr, "InvalidateRightsIdCache"}, | ||
| 239 | {2100, D<&IApplicationManagerInterface::GetApplicationTerminateResult>, "GetApplicationTerminateResult"}, | ||
| 240 | {2101, nullptr, "GetRawApplicationTerminateResult"}, | ||
| 241 | {2150, nullptr, "CreateRightsEnvironment"}, | ||
| 242 | {2151, nullptr, "DestroyRightsEnvironment"}, | ||
| 243 | {2152, nullptr, "ActivateRightsEnvironment"}, | ||
| 244 | {2153, nullptr, "DeactivateRightsEnvironment"}, | ||
| 245 | {2154, nullptr, "ForceActivateRightsContextForExit"}, | ||
| 246 | {2155, nullptr, "UpdateRightsEnvironmentStatus"}, | ||
| 247 | {2156, nullptr, "CreateRightsEnvironmentForMicroApplication"}, | ||
| 248 | {2160, nullptr, "AddTargetApplicationToRightsEnvironment"}, | ||
| 249 | {2161, nullptr, "SetUsersToRightsEnvironment"}, | ||
| 250 | {2170, nullptr, "GetRightsEnvironmentStatus"}, | ||
| 251 | {2171, nullptr, "GetRightsEnvironmentStatusChangedEvent"}, | ||
| 252 | {2180, nullptr, "RequestExtendRightsInRightsEnvironment"}, | ||
| 253 | {2181, nullptr, "GetResultOfExtendRightsInRightsEnvironment"}, | ||
| 254 | {2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"}, | ||
| 255 | {2190, nullptr, "GetRightsEnvironmentHandleForApplication"}, | ||
| 256 | {2199, nullptr, "GetRightsEnvironmentCountForDebug"}, | ||
| 257 | {2200, nullptr, "GetGameCardApplicationCopyIdentifier"}, | ||
| 258 | {2201, nullptr, "GetInstalledApplicationCopyIdentifier"}, | ||
| 259 | {2250, nullptr, "RequestReportActiveELicence"}, | ||
| 260 | {2300, nullptr, "ListEventLog"}, | ||
| 261 | {2350, nullptr, "PerformAutoUpdateByApplicationId"}, | ||
| 262 | {2351, nullptr, "RequestNoDownloadRightsErrorResolution"}, | ||
| 263 | {2352, nullptr, "RequestResolveNoDownloadRightsError"}, | ||
| 264 | {2353, nullptr, "GetApplicationDownloadTaskInfo"}, | ||
| 265 | {2354, nullptr, "PrioritizeApplicationBackgroundTask"}, | ||
| 266 | {2355, nullptr, "PreferStorageEfficientUpdate"}, | ||
| 267 | {2356, nullptr, "RequestStorageEfficientUpdatePreferable"}, | ||
| 268 | {2357, nullptr, "EnableMultiCoreDownload"}, | ||
| 269 | {2358, nullptr, "DisableMultiCoreDownload"}, | ||
| 270 | {2359, nullptr, "IsMultiCoreDownloadEnabled"}, | ||
| 271 | {2400, nullptr, "GetPromotionInfo"}, | ||
| 272 | {2401, nullptr, "CountPromotionInfo"}, | ||
| 273 | {2402, nullptr, "ListPromotionInfo"}, | ||
| 274 | {2403, nullptr, "ImportPromotionJsonForDebug"}, | ||
| 275 | {2404, nullptr, "ClearPromotionInfoForDebug"}, | ||
| 276 | {2500, nullptr, "ConfirmAvailableTime"}, | ||
| 277 | {2510, nullptr, "CreateApplicationResource"}, | ||
| 278 | {2511, nullptr, "GetApplicationResource"}, | ||
| 279 | {2513, nullptr, "LaunchMicroApplication"}, | ||
| 280 | {2514, nullptr, "ClearTaskOfAsyncTaskManager"}, | ||
| 281 | {2515, nullptr, "CleanupAllPlaceHolderAndFragmentsIfNoTask"}, | ||
| 282 | {2516, nullptr, "EnsureApplicationCertificate"}, | ||
| 283 | {2517, nullptr, "CreateApplicationInstance"}, | ||
| 284 | {2518, nullptr, "UpdateQualificationForDebug"}, | ||
| 285 | {2519, nullptr, "IsQualificationTransitionSupported"}, | ||
| 286 | {2520, nullptr, "IsQualificationTransitionSupportedByProcessId"}, | ||
| 287 | {2521, nullptr, "GetRightsUserChangedEvent"}, | ||
| 288 | {2522, nullptr, "IsRomRedirectionAvailable"}, | ||
| 289 | {2800, nullptr, "GetApplicationIdOfPreomia"}, | ||
| 290 | {3000, nullptr, "RegisterDeviceLockKey"}, | ||
| 291 | {3001, nullptr, "UnregisterDeviceLockKey"}, | ||
| 292 | {3002, nullptr, "VerifyDeviceLockKey"}, | ||
| 293 | {3003, nullptr, "HideApplicationIcon"}, | ||
| 294 | {3004, nullptr, "ShowApplicationIcon"}, | ||
| 295 | {3005, nullptr, "HideApplicationTitle"}, | ||
| 296 | {3006, nullptr, "ShowApplicationTitle"}, | ||
| 297 | {3007, nullptr, "EnableGameCard"}, | ||
| 298 | {3008, nullptr, "DisableGameCard"}, | ||
| 299 | {3009, nullptr, "EnableLocalContentShare"}, | ||
| 300 | {3010, nullptr, "DisableLocalContentShare"}, | ||
| 301 | {3011, nullptr, "IsApplicationIconHidden"}, | ||
| 302 | {3012, nullptr, "IsApplicationTitleHidden"}, | ||
| 303 | {3013, nullptr, "IsGameCardEnabled"}, | ||
| 304 | {3014, nullptr, "IsLocalContentShareEnabled"}, | ||
| 305 | {3050, nullptr, "ListAssignELicenseTaskResult"}, | ||
| 306 | {9999, nullptr, "GetApplicationCertificate"}, | ||
| 307 | }; | ||
| 308 | // clang-format on | ||
| 309 | |||
| 310 | RegisterHandlers(functions); | ||
| 311 | } | ||
| 312 | |||
| 313 | IApplicationManagerInterface::~IApplicationManagerInterface() = default; | ||
| 314 | |||
| 315 | Result IApplicationManagerInterface::GetApplicationControlData( | ||
| 316 | OutBuffer<BufferAttr_HipcMapAlias> out_buffer, Out<u32> out_actual_size, | ||
| 317 | ApplicationControlSource application_control_source, u64 application_id) { | ||
| 318 | LOG_DEBUG(Service_NS, "called"); | ||
| 319 | R_RETURN(IReadOnlyApplicationControlDataInterface(system).GetApplicationControlData( | ||
| 320 | out_buffer, out_actual_size, application_control_source, application_id)); | ||
| 321 | } | ||
| 322 | |||
| 323 | Result IApplicationManagerInterface::GetApplicationDesiredLanguage( | ||
| 324 | Out<ApplicationLanguage> out_desired_language, u32 supported_languages) { | ||
| 325 | LOG_DEBUG(Service_NS, "called"); | ||
| 326 | R_RETURN(IReadOnlyApplicationControlDataInterface(system).GetApplicationDesiredLanguage( | ||
| 327 | out_desired_language, supported_languages)); | ||
| 328 | } | ||
| 329 | |||
| 330 | Result IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode( | ||
| 331 | Out<u64> out_language_code, ApplicationLanguage application_language) { | ||
| 332 | LOG_DEBUG(Service_NS, "called"); | ||
| 333 | R_RETURN( | ||
| 334 | IReadOnlyApplicationControlDataInterface(system).ConvertApplicationLanguageToLanguageCode( | ||
| 335 | out_language_code, application_language)); | ||
| 336 | } | ||
| 337 | |||
| 338 | Result IApplicationManagerInterface::ListApplicationRecord( | ||
| 339 | OutArray<ApplicationRecord, BufferAttr_HipcMapAlias> out_records, Out<s32> out_count, | ||
| 340 | s32 offset) { | ||
| 341 | const auto limit = out_records.size(); | ||
| 342 | |||
| 343 | LOG_WARNING(Service_NS, "(STUBBED) called"); | ||
| 344 | const auto& cache = system.GetContentProviderUnion(); | ||
| 345 | const auto installed_games = cache.ListEntriesFilterOrigin( | ||
| 346 | std::nullopt, FileSys::TitleType::Application, FileSys::ContentRecordType::Program); | ||
| 347 | |||
| 348 | size_t i = 0; | ||
| 349 | u8 ii = 24; | ||
| 350 | |||
| 351 | for (const auto& [slot, game] : installed_games) { | ||
| 352 | if (i >= limit) { | ||
| 353 | break; | ||
| 354 | } | ||
| 355 | if (game.title_id == 0 || game.title_id < 0x0100000000001FFFull) { | ||
| 356 | continue; | ||
| 357 | } | ||
| 358 | if (offset > 0) { | ||
| 359 | offset--; | ||
| 360 | continue; | ||
| 361 | } | ||
| 362 | |||
| 363 | ApplicationRecord record{}; | ||
| 364 | record.application_id = game.title_id; | ||
| 365 | record.type = ApplicationRecordType::Installed; | ||
| 366 | record.unknown = 0; // 2 = needs update | ||
| 367 | record.unknown2 = ii++; | ||
| 368 | |||
| 369 | out_records[i++] = record; | ||
| 370 | } | ||
| 371 | |||
| 372 | *out_count = static_cast<s32>(i); | ||
| 373 | R_SUCCEED(); | ||
| 374 | } | ||
| 375 | |||
| 376 | Result IApplicationManagerInterface::GetApplicationRecordUpdateSystemEvent( | ||
| 377 | OutCopyHandle<Kernel::KReadableEvent> out_event) { | ||
| 378 | LOG_WARNING(Service_NS, "(STUBBED) called"); | ||
| 379 | |||
| 380 | record_update_system_event.Signal(); | ||
| 381 | *out_event = record_update_system_event.GetHandle(); | ||
| 382 | |||
| 383 | R_SUCCEED(); | ||
| 384 | } | ||
| 385 | |||
| 386 | Result IApplicationManagerInterface::GetGameCardMountFailureEvent( | ||
| 387 | OutCopyHandle<Kernel::KReadableEvent> out_event) { | ||
| 388 | LOG_WARNING(Service_NS, "(STUBBED) called"); | ||
| 389 | *out_event = gamecard_mount_failure_event.GetHandle(); | ||
| 390 | R_SUCCEED(); | ||
| 391 | } | ||
| 392 | |||
| 393 | Result IApplicationManagerInterface::IsAnyApplicationEntityInstalled( | ||
| 394 | Out<bool> out_is_any_application_entity_installed) { | ||
| 395 | LOG_WARNING(Service_NS, "(STUBBED) called"); | ||
| 396 | *out_is_any_application_entity_installed = true; | ||
| 397 | R_SUCCEED(); | ||
| 398 | } | ||
| 399 | |||
| 400 | Result IApplicationManagerInterface::GetApplicationView( | ||
| 401 | OutArray<ApplicationView, BufferAttr_HipcMapAlias> out_application_views, | ||
| 402 | InArray<u64, BufferAttr_HipcMapAlias> application_ids) { | ||
| 403 | const auto size = std::min(out_application_views.size(), application_ids.size()); | ||
| 404 | LOG_WARNING(Service_NS, "(STUBBED) called, size={}", application_ids.size()); | ||
| 405 | |||
| 406 | for (size_t i = 0; i < size; i++) { | ||
| 407 | ApplicationView view{}; | ||
| 408 | view.application_id = application_ids[i]; | ||
| 409 | view.unk = 0x70000; | ||
| 410 | view.flags = 0x401f17; | ||
| 411 | |||
| 412 | out_application_views[i] = view; | ||
| 413 | } | ||
| 414 | |||
| 415 | R_SUCCEED(); | ||
| 416 | } | ||
| 417 | |||
| 418 | Result IApplicationManagerInterface::GetApplicationViewWithPromotionInfo( | ||
| 419 | OutArray<ApplicationViewWithPromotionInfo, BufferAttr_HipcMapAlias> out_application_views, | ||
| 420 | InArray<u64, BufferAttr_HipcMapAlias> application_ids) { | ||
| 421 | const auto size = std::min(out_application_views.size(), application_ids.size()); | ||
| 422 | LOG_WARNING(Service_NS, "(STUBBED) called, size={}", application_ids.size()); | ||
| 423 | |||
| 424 | for (size_t i = 0; i < size; i++) { | ||
| 425 | ApplicationViewWithPromotionInfo view{}; | ||
| 426 | view.view.application_id = application_ids[i]; | ||
| 427 | view.view.unk = 0x70000; | ||
| 428 | view.view.flags = 0x401f17; | ||
| 429 | view.promotion = {}; | ||
| 430 | |||
| 431 | out_application_views[i] = view; | ||
| 432 | } | ||
| 433 | |||
| 434 | R_SUCCEED(); | ||
| 435 | } | ||
| 436 | |||
| 437 | Result IApplicationManagerInterface::GetApplicationRightsOnClient( | ||
| 438 | OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count, | ||
| 439 | Common::UUID account_id, u32 flags, u64 application_id) { | ||
| 440 | LOG_WARNING(Service_NS, "(STUBBED) called, flags={}, application_id={:016X}, account_id={}", | ||
| 441 | flags, application_id, account_id.FormattedString()); | ||
| 442 | |||
| 443 | if (!out_rights.empty()) { | ||
| 444 | ApplicationRightsOnClient rights{}; | ||
| 445 | rights.application_id = application_id; | ||
| 446 | rights.uid = account_id; | ||
| 447 | rights.flags = 0; | ||
| 448 | rights.flags2 = 0; | ||
| 449 | |||
| 450 | out_rights[0] = rights; | ||
| 451 | *out_count = 1; | ||
| 452 | } else { | ||
| 453 | *out_count = 0; | ||
| 454 | } | ||
| 455 | |||
| 456 | R_SUCCEED(); | ||
| 457 | } | ||
| 458 | |||
| 459 | Result IApplicationManagerInterface::CheckSdCardMountStatus() { | ||
| 460 | LOG_DEBUG(Service_NS, "called"); | ||
| 461 | R_RETURN(IContentManagementInterface(system).CheckSdCardMountStatus()); | ||
| 462 | } | ||
| 463 | |||
| 464 | Result IApplicationManagerInterface::GetSdCardMountStatusChangedEvent( | ||
| 465 | OutCopyHandle<Kernel::KReadableEvent> out_event) { | ||
| 466 | LOG_WARNING(Service_NS, "(STUBBED) called"); | ||
| 467 | *out_event = sd_card_mount_status_event.GetHandle(); | ||
| 468 | R_SUCCEED(); | ||
| 469 | } | ||
| 470 | |||
| 471 | Result IApplicationManagerInterface::GetFreeSpaceSize(Out<s64> out_free_space_size, | ||
| 472 | FileSys::StorageId storage_id) { | ||
| 473 | LOG_DEBUG(Service_NS, "called"); | ||
| 474 | R_RETURN(IContentManagementInterface(system).GetFreeSpaceSize(out_free_space_size, storage_id)); | ||
| 475 | } | ||
| 476 | |||
| 477 | Result IApplicationManagerInterface::GetGameCardUpdateDetectionEvent( | ||
| 478 | OutCopyHandle<Kernel::KReadableEvent> out_event) { | ||
| 479 | LOG_WARNING(Service_NS, "(STUBBED) called"); | ||
| 480 | *out_event = gamecard_update_detection_event.GetHandle(); | ||
| 481 | R_SUCCEED(); | ||
| 482 | } | ||
| 483 | |||
| 484 | Result IApplicationManagerInterface::ResumeAll() { | ||
| 485 | LOG_WARNING(Service_NS, "(STUBBED) called"); | ||
| 486 | R_SUCCEED(); | ||
| 487 | } | ||
| 488 | |||
| 489 | Result IApplicationManagerInterface::GetStorageSize(Out<s64> out_total_space_size, | ||
| 490 | Out<s64> out_free_space_size, | ||
| 491 | FileSys::StorageId storage_id) { | ||
| 492 | LOG_INFO(Service_NS, "called, storage_id={}", storage_id); | ||
| 493 | *out_total_space_size = system.GetFileSystemController().GetTotalSpaceSize(storage_id); | ||
| 494 | *out_free_space_size = system.GetFileSystemController().GetFreeSpaceSize(storage_id); | ||
| 495 | R_SUCCEED(); | ||
| 496 | } | ||
| 497 | |||
| 498 | Result IApplicationManagerInterface::IsApplicationUpdateRequested(Out<bool> out_update_required, | ||
| 499 | Out<u32> out_update_version, | ||
| 500 | u64 application_id) { | ||
| 501 | LOG_WARNING(Service_NS, "(STUBBED) called. application_id={:016X}", application_id); | ||
| 502 | *out_update_required = false; | ||
| 503 | *out_update_version = 0; | ||
| 504 | R_SUCCEED(); | ||
| 505 | } | ||
| 506 | |||
| 507 | Result IApplicationManagerInterface::CheckApplicationLaunchVersion(u64 application_id) { | ||
| 508 | LOG_WARNING(Service_NS, "(STUBBED) called. application_id={:016X}", application_id); | ||
| 509 | R_SUCCEED(); | ||
| 510 | } | ||
| 511 | |||
| 512 | Result IApplicationManagerInterface::GetApplicationTerminateResult(Out<Result> out_result, | ||
| 513 | u64 application_id) { | ||
| 514 | LOG_WARNING(Service_NS, "(STUBBED) called. application_id={:016X}", application_id); | ||
| 515 | *out_result = ResultSuccess; | ||
| 516 | R_SUCCEED(); | ||
| 517 | } | ||
| 518 | |||
| 519 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/application_manager_interface.h b/src/core/hle/service/ns/application_manager_interface.h new file mode 100644 index 000000000..350ec37ce --- /dev/null +++ b/src/core/hle/service/ns/application_manager_interface.h | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/cmif_types.h" | ||
| 7 | #include "core/hle/service/ns/language.h" | ||
| 8 | #include "core/hle/service/ns/ns_types.h" | ||
| 9 | #include "core/hle/service/os/event.h" | ||
| 10 | #include "core/hle/service/service.h" | ||
| 11 | |||
| 12 | namespace Service::NS { | ||
| 13 | |||
| 14 | class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> { | ||
| 15 | public: | ||
| 16 | explicit IApplicationManagerInterface(Core::System& system_); | ||
| 17 | ~IApplicationManagerInterface() override; | ||
| 18 | |||
| 19 | Result GetApplicationControlData(OutBuffer<BufferAttr_HipcMapAlias> out_buffer, | ||
| 20 | Out<u32> out_actual_size, | ||
| 21 | ApplicationControlSource application_control_source, | ||
| 22 | u64 application_id); | ||
| 23 | Result GetApplicationDesiredLanguage(Out<ApplicationLanguage> out_desired_language, | ||
| 24 | u32 supported_languages); | ||
| 25 | Result ConvertApplicationLanguageToLanguageCode(Out<u64> out_language_code, | ||
| 26 | ApplicationLanguage application_language); | ||
| 27 | Result ListApplicationRecord(OutArray<ApplicationRecord, BufferAttr_HipcMapAlias> out_records, | ||
| 28 | Out<s32> out_count, s32 offset); | ||
| 29 | Result GetApplicationRecordUpdateSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); | ||
| 30 | Result GetGameCardMountFailureEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); | ||
| 31 | Result IsAnyApplicationEntityInstalled(Out<bool> out_is_any_application_entity_installed); | ||
| 32 | Result GetApplicationView( | ||
| 33 | OutArray<ApplicationView, BufferAttr_HipcMapAlias> out_application_views, | ||
| 34 | InArray<u64, BufferAttr_HipcMapAlias> application_ids); | ||
| 35 | Result GetApplicationViewWithPromotionInfo( | ||
| 36 | OutArray<ApplicationViewWithPromotionInfo, BufferAttr_HipcMapAlias> out_application_views, | ||
| 37 | InArray<u64, BufferAttr_HipcMapAlias> application_ids); | ||
| 38 | Result GetApplicationRightsOnClient( | ||
| 39 | OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count, | ||
| 40 | Common::UUID account_id, u32 flags, u64 application_id); | ||
| 41 | Result CheckSdCardMountStatus(); | ||
| 42 | Result GetSdCardMountStatusChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); | ||
| 43 | Result GetFreeSpaceSize(Out<s64> out_free_space_size, FileSys::StorageId storage_id); | ||
| 44 | Result GetGameCardUpdateDetectionEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); | ||
| 45 | Result ResumeAll(); | ||
| 46 | Result GetStorageSize(Out<s64> out_total_space_size, Out<s64> out_free_space_size, | ||
| 47 | FileSys::StorageId storage_id); | ||
| 48 | Result IsApplicationUpdateRequested(Out<bool> out_update_required, Out<u32> out_update_version, | ||
| 49 | u64 application_id); | ||
| 50 | Result CheckApplicationLaunchVersion(u64 application_id); | ||
| 51 | Result GetApplicationTerminateResult(Out<Result> out_result, u64 application_id); | ||
| 52 | |||
| 53 | private: | ||
| 54 | KernelHelpers::ServiceContext service_context; | ||
| 55 | Event record_update_system_event; | ||
| 56 | Event sd_card_mount_status_event; | ||
| 57 | Event gamecard_update_detection_event; | ||
| 58 | Event gamecard_mount_status_event; | ||
| 59 | Event gamecard_mount_failure_event; | ||
| 60 | }; | ||
| 61 | |||
| 62 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/application_version_interface.cpp b/src/core/hle/service/ns/application_version_interface.cpp new file mode 100644 index 000000000..b89e127db --- /dev/null +++ b/src/core/hle/service/ns/application_version_interface.cpp | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/ns/application_version_interface.h" | ||
| 5 | |||
| 6 | namespace Service::NS { | ||
| 7 | |||
| 8 | IApplicationVersionInterface::IApplicationVersionInterface(Core::System& system_) | ||
| 9 | : ServiceFramework{system_, "IApplicationVersionInterface"} { | ||
| 10 | // clang-format off | ||
| 11 | static const FunctionInfo functions[] = { | ||
| 12 | {0, nullptr, "GetLaunchRequiredVersion"}, | ||
| 13 | {1, nullptr, "UpgradeLaunchRequiredVersion"}, | ||
| 14 | {35, nullptr, "UpdateVersionList"}, | ||
| 15 | {36, nullptr, "PushLaunchVersion"}, | ||
| 16 | {37, nullptr, "ListRequiredVersion"}, | ||
| 17 | {800, nullptr, "RequestVersionList"}, | ||
| 18 | {801, nullptr, "ListVersionList"}, | ||
| 19 | {802, nullptr, "RequestVersionListData"}, | ||
| 20 | {900, nullptr, "ImportAutoUpdatePolicyJsonForDebug"}, | ||
| 21 | {901, nullptr, "ListDefaultAutoUpdatePolicy"}, | ||
| 22 | {902, nullptr, "ListAutoUpdatePolicyForSpecificApplication"}, | ||
| 23 | {1000, nullptr, "PerformAutoUpdate"}, | ||
| 24 | {1001, nullptr, "ListAutoUpdateSchedule"}, | ||
| 25 | }; | ||
| 26 | // clang-format on | ||
| 27 | |||
| 28 | RegisterHandlers(functions); | ||
| 29 | } | ||
| 30 | |||
| 31 | IApplicationVersionInterface::~IApplicationVersionInterface() = default; | ||
| 32 | |||
| 33 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/application_version_interface.h b/src/core/hle/service/ns/application_version_interface.h new file mode 100644 index 000000000..b288cff1b --- /dev/null +++ b/src/core/hle/service/ns/application_version_interface.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/service.h" | ||
| 7 | |||
| 8 | namespace Service::NS { | ||
| 9 | |||
| 10 | class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> { | ||
| 11 | public: | ||
| 12 | explicit IApplicationVersionInterface(Core::System& system_); | ||
| 13 | ~IApplicationVersionInterface() override; | ||
| 14 | }; | ||
| 15 | |||
| 16 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/content_management_interface.cpp b/src/core/hle/service/ns/content_management_interface.cpp new file mode 100644 index 000000000..69bb3f6e4 --- /dev/null +++ b/src/core/hle/service/ns/content_management_interface.cpp | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/common_funcs.h" | ||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/hle/service/cmif_serialization.h" | ||
| 7 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 8 | #include "core/hle/service/ns/content_management_interface.h" | ||
| 9 | #include "core/hle/service/ns/ns_types.h" | ||
| 10 | |||
| 11 | namespace Service::NS { | ||
| 12 | |||
| 13 | IContentManagementInterface::IContentManagementInterface(Core::System& system_) | ||
| 14 | : ServiceFramework{system_, "IContentManagementInterface"} { | ||
| 15 | // clang-format off | ||
| 16 | static const FunctionInfo functions[] = { | ||
| 17 | {11, D<&IContentManagementInterface::CalculateApplicationOccupiedSize>, "CalculateApplicationOccupiedSize"}, | ||
| 18 | {43, D<&IContentManagementInterface::CheckSdCardMountStatus>, "CheckSdCardMountStatus"}, | ||
| 19 | {47, D<&IContentManagementInterface::GetTotalSpaceSize>, "GetTotalSpaceSize"}, | ||
| 20 | {48, D<&IContentManagementInterface::GetFreeSpaceSize>, "GetFreeSpaceSize"}, | ||
| 21 | {600, nullptr, "CountApplicationContentMeta"}, | ||
| 22 | {601, nullptr, "ListApplicationContentMetaStatus"}, | ||
| 23 | {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"}, | ||
| 24 | {607, nullptr, "IsAnyApplicationRunning"}, | ||
| 25 | }; | ||
| 26 | // clang-format on | ||
| 27 | |||
| 28 | RegisterHandlers(functions); | ||
| 29 | } | ||
| 30 | |||
| 31 | IContentManagementInterface::~IContentManagementInterface() = default; | ||
| 32 | |||
| 33 | Result IContentManagementInterface::CalculateApplicationOccupiedSize( | ||
| 34 | Out<ApplicationOccupiedSize> out_size, u64 application_id) { | ||
| 35 | LOG_WARNING(Service_NS, "(STUBBED) called, application_id={:016X}", application_id); | ||
| 36 | |||
| 37 | using namespace Common::Literals; | ||
| 38 | |||
| 39 | constexpr ApplicationOccupiedSizeEntity stub_entity{ | ||
| 40 | .storage_id = FileSys::StorageId::SdCard, | ||
| 41 | .app_size = 8_GiB, | ||
| 42 | .patch_size = 2_GiB, | ||
| 43 | .aoc_size = 12_MiB, | ||
| 44 | }; | ||
| 45 | |||
| 46 | for (auto& entity : out_size->entities) { | ||
| 47 | entity = stub_entity; | ||
| 48 | } | ||
| 49 | |||
| 50 | R_SUCCEED(); | ||
| 51 | } | ||
| 52 | |||
| 53 | Result IContentManagementInterface::CheckSdCardMountStatus() { | ||
| 54 | LOG_WARNING(Service_NS, "(STUBBED) called"); | ||
| 55 | R_SUCCEED(); | ||
| 56 | } | ||
| 57 | |||
| 58 | Result IContentManagementInterface::GetTotalSpaceSize(Out<s64> out_total_space_size, | ||
| 59 | FileSys::StorageId storage_id) { | ||
| 60 | LOG_INFO(Service_NS, "(STUBBED) called, storage_id={}", storage_id); | ||
| 61 | *out_total_space_size = system.GetFileSystemController().GetTotalSpaceSize(storage_id); | ||
| 62 | R_SUCCEED(); | ||
| 63 | } | ||
| 64 | |||
| 65 | Result IContentManagementInterface::GetFreeSpaceSize(Out<s64> out_free_space_size, | ||
| 66 | FileSys::StorageId storage_id) { | ||
| 67 | LOG_INFO(Service_NS, "(STUBBED) called, storage_id={}", storage_id); | ||
| 68 | *out_free_space_size = system.GetFileSystemController().GetFreeSpaceSize(storage_id); | ||
| 69 | R_SUCCEED(); | ||
| 70 | } | ||
| 71 | |||
| 72 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/content_management_interface.h b/src/core/hle/service/ns/content_management_interface.h new file mode 100644 index 000000000..2894628e5 --- /dev/null +++ b/src/core/hle/service/ns/content_management_interface.h | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/cmif_types.h" | ||
| 7 | #include "core/hle/service/ns/ns_types.h" | ||
| 8 | #include "core/hle/service/service.h" | ||
| 9 | |||
| 10 | namespace Service::NS { | ||
| 11 | |||
| 12 | class IContentManagementInterface final : public ServiceFramework<IContentManagementInterface> { | ||
| 13 | public: | ||
| 14 | explicit IContentManagementInterface(Core::System& system_); | ||
| 15 | ~IContentManagementInterface() override; | ||
| 16 | |||
| 17 | public: | ||
| 18 | Result CalculateApplicationOccupiedSize(Out<ApplicationOccupiedSize> out_size, | ||
| 19 | u64 application_id); | ||
| 20 | Result CheckSdCardMountStatus(); | ||
| 21 | Result GetTotalSpaceSize(Out<s64> out_total_space_size, FileSys::StorageId storage_id); | ||
| 22 | Result GetFreeSpaceSize(Out<s64> out_free_space_size, FileSys::StorageId storage_id); | ||
| 23 | }; | ||
| 24 | |||
| 25 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/develop_interface.cpp b/src/core/hle/service/ns/develop_interface.cpp new file mode 100644 index 000000000..880bdbebb --- /dev/null +++ b/src/core/hle/service/ns/develop_interface.cpp | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/ns/develop_interface.h" | ||
| 5 | |||
| 6 | namespace Service::NS { | ||
| 7 | |||
| 8 | IDevelopInterface::IDevelopInterface(Core::System& system_) : ServiceFramework{system_, "ns:dev"} { | ||
| 9 | // clang-format off | ||
| 10 | static const FunctionInfo functions[] = { | ||
| 11 | {0, nullptr, "LaunchProgram"}, | ||
| 12 | {1, nullptr, "TerminateProcess"}, | ||
| 13 | {2, nullptr, "TerminateProgram"}, | ||
| 14 | {4, nullptr, "GetShellEvent"}, | ||
| 15 | {5, nullptr, "GetShellEventInfo"}, | ||
| 16 | {6, nullptr, "TerminateApplication"}, | ||
| 17 | {7, nullptr, "PrepareLaunchProgramFromHost"}, | ||
| 18 | {8, nullptr, "LaunchApplicationFromHost"}, | ||
| 19 | {9, nullptr, "LaunchApplicationWithStorageIdForDevelop"}, | ||
| 20 | {10, nullptr, "IsSystemMemoryResourceLimitBoosted"}, | ||
| 21 | {11, nullptr, "GetRunningApplicationProcessIdForDevelop"}, | ||
| 22 | {12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActiveForDevelop"}, | ||
| 23 | {13, nullptr, "CreateApplicationResourceForDevelop"}, | ||
| 24 | {14, nullptr, "IsPreomiaForDevelop"}, | ||
| 25 | {15, nullptr, "GetApplicationProgramIdFromHost"}, | ||
| 26 | {16, nullptr, "RefreshCachedDebugValues"}, | ||
| 27 | {17, nullptr, "PrepareLaunchApplicationFromHost"}, | ||
| 28 | {18, nullptr, "GetLaunchEvent"}, | ||
| 29 | {19, nullptr, "GetLaunchResult"}, | ||
| 30 | }; | ||
| 31 | // clang-format on | ||
| 32 | |||
| 33 | RegisterHandlers(functions); | ||
| 34 | } | ||
| 35 | |||
| 36 | IDevelopInterface::~IDevelopInterface() = default; | ||
| 37 | |||
| 38 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/develop_interface.h b/src/core/hle/service/ns/develop_interface.h new file mode 100644 index 000000000..a9f81ccd6 --- /dev/null +++ b/src/core/hle/service/ns/develop_interface.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/service.h" | ||
| 7 | |||
| 8 | namespace Service::NS { | ||
| 9 | |||
| 10 | class IDevelopInterface final : public ServiceFramework<IDevelopInterface> { | ||
| 11 | public: | ||
| 12 | explicit IDevelopInterface(Core::System& system_); | ||
| 13 | ~IDevelopInterface() override; | ||
| 14 | }; | ||
| 15 | |||
| 16 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/document_interface.cpp b/src/core/hle/service/ns/document_interface.cpp new file mode 100644 index 000000000..51a1e46c0 --- /dev/null +++ b/src/core/hle/service/ns/document_interface.cpp | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/hle/service/cmif_serialization.h" | ||
| 6 | #include "core/hle/service/ns/document_interface.h" | ||
| 7 | |||
| 8 | namespace Service::NS { | ||
| 9 | |||
| 10 | IDocumentInterface::IDocumentInterface(Core::System& system_) | ||
| 11 | : ServiceFramework{system_, "IDocumentInterface"} { | ||
| 12 | // clang-format off | ||
| 13 | static const FunctionInfo functions[] = { | ||
| 14 | {21, nullptr, "GetApplicationContentPath"}, | ||
| 15 | {23, D<&IDocumentInterface::ResolveApplicationContentPath>, "ResolveApplicationContentPath"}, | ||
| 16 | {92, D<&IDocumentInterface::GetRunningApplicationProgramId>, "GetRunningApplicationProgramId"}, | ||
| 17 | }; | ||
| 18 | // clang-format on | ||
| 19 | |||
| 20 | RegisterHandlers(functions); | ||
| 21 | } | ||
| 22 | |||
| 23 | IDocumentInterface::~IDocumentInterface() = default; | ||
| 24 | |||
| 25 | Result IDocumentInterface::ResolveApplicationContentPath(ContentPath content_path) { | ||
| 26 | LOG_WARNING(Service_NS, "(STUBBED) called, file_system_proxy_type={}, program_id={:016X}", | ||
| 27 | content_path.file_system_proxy_type, content_path.program_id); | ||
| 28 | R_SUCCEED(); | ||
| 29 | } | ||
| 30 | |||
| 31 | Result IDocumentInterface::GetRunningApplicationProgramId(Out<u64> out_program_id, | ||
| 32 | u64 caller_program_id) { | ||
| 33 | LOG_WARNING(Service_NS, "(STUBBED) called, caller_program_id={:016X}", caller_program_id); | ||
| 34 | *out_program_id = system.GetApplicationProcessProgramID(); | ||
| 35 | R_SUCCEED(); | ||
| 36 | } | ||
| 37 | |||
| 38 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/document_interface.h b/src/core/hle/service/ns/document_interface.h new file mode 100644 index 000000000..cd461652c --- /dev/null +++ b/src/core/hle/service/ns/document_interface.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/cmif_types.h" | ||
| 7 | #include "core/hle/service/ns/ns_types.h" | ||
| 8 | #include "core/hle/service/service.h" | ||
| 9 | |||
| 10 | namespace Service::NS { | ||
| 11 | |||
| 12 | class IDocumentInterface final : public ServiceFramework<IDocumentInterface> { | ||
| 13 | public: | ||
| 14 | explicit IDocumentInterface(Core::System& system_); | ||
| 15 | ~IDocumentInterface() override; | ||
| 16 | |||
| 17 | private: | ||
| 18 | Result ResolveApplicationContentPath(ContentPath content_path); | ||
| 19 | Result GetRunningApplicationProgramId(Out<u64> out_program_id, u64 caller_program_id); | ||
| 20 | }; | ||
| 21 | |||
| 22 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/download_task_interface.cpp b/src/core/hle/service/ns/download_task_interface.cpp new file mode 100644 index 000000000..62dc7f187 --- /dev/null +++ b/src/core/hle/service/ns/download_task_interface.cpp | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/cmif_serialization.h" | ||
| 5 | #include "core/hle/service/ns/download_task_interface.h" | ||
| 6 | |||
| 7 | namespace Service::NS { | ||
| 8 | |||
| 9 | IDownloadTaskInterface::IDownloadTaskInterface(Core::System& system_) | ||
| 10 | : ServiceFramework{system_, "IDownloadTaskInterface"} { | ||
| 11 | // clang-format off | ||
| 12 | static const FunctionInfo functions[] = { | ||
| 13 | {701, nullptr, "ClearTaskStatusList"}, | ||
| 14 | {702, nullptr, "RequestDownloadTaskList"}, | ||
| 15 | {703, nullptr, "RequestEnsureDownloadTask"}, | ||
| 16 | {704, nullptr, "ListDownloadTaskStatus"}, | ||
| 17 | {705, nullptr, "RequestDownloadTaskListData"}, | ||
| 18 | {706, nullptr, "TryCommitCurrentApplicationDownloadTask"}, | ||
| 19 | {707, D<&IDownloadTaskInterface::EnableAutoCommit>, "EnableAutoCommit"}, | ||
| 20 | {708, D<&IDownloadTaskInterface::DisableAutoCommit>, "DisableAutoCommit"}, | ||
| 21 | {709, nullptr, "TriggerDynamicCommitEvent"}, | ||
| 22 | }; | ||
| 23 | // clang-format on | ||
| 24 | |||
| 25 | RegisterHandlers(functions); | ||
| 26 | } | ||
| 27 | |||
| 28 | IDownloadTaskInterface::~IDownloadTaskInterface() = default; | ||
| 29 | |||
| 30 | Result IDownloadTaskInterface::EnableAutoCommit() { | ||
| 31 | LOG_WARNING(Service_NS, "(STUBBED) called"); | ||
| 32 | R_SUCCEED(); | ||
| 33 | } | ||
| 34 | Result IDownloadTaskInterface::DisableAutoCommit() { | ||
| 35 | LOG_WARNING(Service_NS, "(STUBBED) called"); | ||
| 36 | R_SUCCEED(); | ||
| 37 | } | ||
| 38 | |||
| 39 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/download_task_interface.h b/src/core/hle/service/ns/download_task_interface.h new file mode 100644 index 000000000..b1cb69cb8 --- /dev/null +++ b/src/core/hle/service/ns/download_task_interface.h | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/service.h" | ||
| 7 | |||
| 8 | namespace Service::NS { | ||
| 9 | |||
| 10 | class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> { | ||
| 11 | public: | ||
| 12 | explicit IDownloadTaskInterface(Core::System& system_); | ||
| 13 | ~IDownloadTaskInterface() override; | ||
| 14 | |||
| 15 | private: | ||
| 16 | Result EnableAutoCommit(); | ||
| 17 | Result DisableAutoCommit(); | ||
| 18 | }; | ||
| 19 | |||
| 20 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/dynamic_rights_interface.cpp b/src/core/hle/service/ns/dynamic_rights_interface.cpp new file mode 100644 index 000000000..ce81e203f --- /dev/null +++ b/src/core/hle/service/ns/dynamic_rights_interface.cpp | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/cmif_serialization.h" | ||
| 5 | #include "core/hle/service/ns/dynamic_rights_interface.h" | ||
| 6 | |||
| 7 | namespace Service::NS { | ||
| 8 | |||
| 9 | IDynamicRightsInterface::IDynamicRightsInterface(Core::System& system_) | ||
| 10 | : ServiceFramework{system_, "DynamicRightsInterface"} { | ||
| 11 | // clang-format off | ||
| 12 | static const FunctionInfo functions[] = { | ||
| 13 | {0, nullptr, "RequestApplicationRightsOnServer"}, | ||
| 14 | {1, nullptr, "RequestAssignRights"}, | ||
| 15 | {4, nullptr, "DeprecatedRequestAssignRightsToResume"}, | ||
| 16 | {5, D<&IDynamicRightsInterface::VerifyActivatedRightsOwners>, "VerifyActivatedRightsOwners"}, | ||
| 17 | {6, nullptr, "DeprecatedGetApplicationRightsStatus"}, | ||
| 18 | {7, nullptr, "RequestPrefetchForDynamicRights"}, | ||
| 19 | {8, nullptr, "GetDynamicRightsState"}, | ||
| 20 | {9, nullptr, "RequestApplicationRightsOnServerToResume"}, | ||
| 21 | {10, nullptr, "RequestAssignRightsToResume"}, | ||
| 22 | {11, nullptr, "GetActivatedRightsUsers"}, | ||
| 23 | {12, nullptr, "GetApplicationRightsStatus"}, | ||
| 24 | {13, D<&IDynamicRightsInterface::GetRunningApplicationStatus>, "GetRunningApplicationStatus"}, | ||
| 25 | {14, nullptr, "SelectApplicationLicense"}, | ||
| 26 | {15, nullptr, "RequestContentsAuthorizationToken"}, | ||
| 27 | {16, nullptr, "QualifyUser"}, | ||
| 28 | {17, nullptr, "QualifyUserWithProcessId"}, | ||
| 29 | {18, D<&IDynamicRightsInterface::NotifyApplicationRightsCheckStart>, "NotifyApplicationRightsCheckStart"}, | ||
| 30 | {19, nullptr, "UpdateUserList"}, | ||
| 31 | {20, nullptr, "IsRightsLostUser"}, | ||
| 32 | {21, nullptr, "SetRequiredAddOnContentsOnContentsAvailabilityTransition"}, | ||
| 33 | {22, nullptr, "GetLimitedApplicationLicense"}, | ||
| 34 | {23, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"}, | ||
| 35 | {24, nullptr, "NotifyLimitedApplicationLicenseUpgradableEventForDebug"}, | ||
| 36 | {25, nullptr, "RequestProceedDynamicRightsState"}, | ||
| 37 | }; | ||
| 38 | // clang-format on | ||
| 39 | |||
| 40 | RegisterHandlers(functions); | ||
| 41 | } | ||
| 42 | |||
| 43 | IDynamicRightsInterface::~IDynamicRightsInterface() = default; | ||
| 44 | |||
| 45 | Result IDynamicRightsInterface::NotifyApplicationRightsCheckStart() { | ||
| 46 | LOG_WARNING(Service_NS, "(STUBBED) called"); | ||
| 47 | R_SUCCEED(); | ||
| 48 | } | ||
| 49 | |||
| 50 | Result IDynamicRightsInterface::GetRunningApplicationStatus(Out<u32> out_status, | ||
| 51 | u64 rights_handle) { | ||
| 52 | LOG_WARNING(Service_NS, "(STUBBED) called, rights_handle={:#x}", rights_handle); | ||
| 53 | *out_status = 0; | ||
| 54 | R_SUCCEED(); | ||
| 55 | } | ||
| 56 | |||
| 57 | Result IDynamicRightsInterface::VerifyActivatedRightsOwners(u64 rights_handle) { | ||
| 58 | LOG_WARNING(Service_NS, "(STUBBED) called, rights_handle={:#x}", rights_handle); | ||
| 59 | R_SUCCEED(); | ||
| 60 | } | ||
| 61 | |||
| 62 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/dynamic_rights_interface.h b/src/core/hle/service/ns/dynamic_rights_interface.h new file mode 100644 index 000000000..877e009b0 --- /dev/null +++ b/src/core/hle/service/ns/dynamic_rights_interface.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/cmif_types.h" | ||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service::NS { | ||
| 10 | |||
| 11 | class IDynamicRightsInterface final : public ServiceFramework<IDynamicRightsInterface> { | ||
| 12 | public: | ||
| 13 | explicit IDynamicRightsInterface(Core::System& system_); | ||
| 14 | ~IDynamicRightsInterface() override; | ||
| 15 | |||
| 16 | private: | ||
| 17 | Result NotifyApplicationRightsCheckStart(); | ||
| 18 | Result GetRunningApplicationStatus(Out<u32> out_status, u64 rights_handle); | ||
| 19 | Result VerifyActivatedRightsOwners(u64 rights_handle); | ||
| 20 | }; | ||
| 21 | |||
| 22 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/ecommerce_interface.cpp b/src/core/hle/service/ns/ecommerce_interface.cpp new file mode 100644 index 000000000..76fc425f0 --- /dev/null +++ b/src/core/hle/service/ns/ecommerce_interface.cpp | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/ns/ecommerce_interface.h" | ||
| 5 | |||
| 6 | namespace Service::NS { | ||
| 7 | |||
| 8 | IECommerceInterface::IECommerceInterface(Core::System& system_) | ||
| 9 | : ServiceFramework{system_, "IECommerceInterface"} { | ||
| 10 | // clang-format off | ||
| 11 | static const FunctionInfo functions[] = { | ||
| 12 | {0, nullptr, "RequestLinkDevice"}, | ||
| 13 | {1, nullptr, "RequestCleanupAllPreInstalledApplications"}, | ||
| 14 | {2, nullptr, "RequestCleanupPreInstalledApplication"}, | ||
| 15 | {3, nullptr, "RequestSyncRights"}, | ||
| 16 | {4, nullptr, "RequestUnlinkDevice"}, | ||
| 17 | {5, nullptr, "RequestRevokeAllELicense"}, | ||
| 18 | {6, nullptr, "RequestSyncRightsBasedOnAssignedELicenses"}, | ||
| 19 | }; | ||
| 20 | // clang-format on | ||
| 21 | |||
| 22 | RegisterHandlers(functions); | ||
| 23 | } | ||
| 24 | |||
| 25 | IECommerceInterface::~IECommerceInterface() = default; | ||
| 26 | |||
| 27 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/ecommerce_interface.h b/src/core/hle/service/ns/ecommerce_interface.h new file mode 100644 index 000000000..4352101f4 --- /dev/null +++ b/src/core/hle/service/ns/ecommerce_interface.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/service.h" | ||
| 7 | |||
| 8 | namespace Service::NS { | ||
| 9 | |||
| 10 | class IECommerceInterface final : public ServiceFramework<IECommerceInterface> { | ||
| 11 | public: | ||
| 12 | explicit IECommerceInterface(Core::System& system_); | ||
| 13 | ~IECommerceInterface() override; | ||
| 14 | }; | ||
| 15 | |||
| 16 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/factory_reset_interface.cpp b/src/core/hle/service/ns/factory_reset_interface.cpp new file mode 100644 index 000000000..fd5cf7e1f --- /dev/null +++ b/src/core/hle/service/ns/factory_reset_interface.cpp | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/ns/factory_reset_interface.h" | ||
| 5 | |||
| 6 | namespace Service::NS { | ||
| 7 | |||
| 8 | IFactoryResetInterface::IFactoryResetInterface(Core::System& system_) | ||
| 9 | : ServiceFramework{system_, "IFactoryResetInterface"} { | ||
| 10 | // clang-format off | ||
| 11 | static const FunctionInfo functions[] = { | ||
| 12 | {100, nullptr, "ResetToFactorySettings"}, | ||
| 13 | {101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"}, | ||
| 14 | {102, nullptr, "ResetToFactorySettingsForRefurbishment"}, | ||
| 15 | {103, nullptr, "ResetToFactorySettingsWithPlatformRegion"}, | ||
| 16 | {104, nullptr, "ResetToFactorySettingsWithPlatformRegionAuthentication"}, | ||
| 17 | {105, nullptr, "RequestResetToFactorySettingsSecurely"}, | ||
| 18 | {106, nullptr, "RequestResetToFactorySettingsWithPlatformRegionAuthenticationSecurely"}, | ||
| 19 | }; | ||
| 20 | // clang-format on | ||
| 21 | |||
| 22 | RegisterHandlers(functions); | ||
| 23 | } | ||
| 24 | |||
| 25 | IFactoryResetInterface::~IFactoryResetInterface() = default; | ||
| 26 | |||
| 27 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/factory_reset_interface.h b/src/core/hle/service/ns/factory_reset_interface.h new file mode 100644 index 000000000..50d125123 --- /dev/null +++ b/src/core/hle/service/ns/factory_reset_interface.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/service.h" | ||
| 7 | |||
| 8 | namespace Service::NS { | ||
| 9 | |||
| 10 | class IFactoryResetInterface final : public ServiceFramework<IFactoryResetInterface> { | ||
| 11 | public: | ||
| 12 | explicit IFactoryResetInterface(Core::System& system_); | ||
| 13 | ~IFactoryResetInterface() override; | ||
| 14 | }; | ||
| 15 | |||
| 16 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 19c3ff01b..8402e83cb 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp | |||
| @@ -1,893 +1,38 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "common/logging/log.h" | 4 | #include "core/hle/service/ns/develop_interface.h" |
| 5 | #include "common/settings.h" | ||
| 6 | #include "core/arm/debug.h" | ||
| 7 | #include "core/core.h" | ||
| 8 | #include "core/file_sys/control_metadata.h" | ||
| 9 | #include "core/file_sys/patch_manager.h" | ||
| 10 | #include "core/file_sys/vfs/vfs.h" | ||
| 11 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 12 | #include "core/hle/service/glue/glue_manager.h" | ||
| 13 | #include "core/hle/service/ipc_helpers.h" | ||
| 14 | #include "core/hle/service/ns/errors.h" | ||
| 15 | #include "core/hle/service/ns/iplatform_service_manager.h" | ||
| 16 | #include "core/hle/service/ns/language.h" | ||
| 17 | #include "core/hle/service/ns/ns.h" | 5 | #include "core/hle/service/ns/ns.h" |
| 18 | #include "core/hle/service/ns/pdm_qry.h" | 6 | #include "core/hle/service/ns/platform_service_manager.h" |
| 7 | #include "core/hle/service/ns/query_service.h" | ||
| 8 | #include "core/hle/service/ns/service_getter_interface.h" | ||
| 9 | #include "core/hle/service/ns/system_update_interface.h" | ||
| 10 | #include "core/hle/service/ns/vulnerability_manager_interface.h" | ||
| 19 | #include "core/hle/service/server_manager.h" | 11 | #include "core/hle/service/server_manager.h" |
| 20 | #include "core/hle/service/set/settings_server.h" | ||
| 21 | 12 | ||
| 22 | namespace Service::NS { | 13 | namespace Service::NS { |
| 23 | 14 | ||
| 24 | IAccountProxyInterface::IAccountProxyInterface(Core::System& system_) | ||
| 25 | : ServiceFramework{system_, "IAccountProxyInterface"} { | ||
| 26 | // clang-format off | ||
| 27 | static const FunctionInfo functions[] = { | ||
| 28 | {0, nullptr, "CreateUserAccount"}, | ||
| 29 | }; | ||
| 30 | // clang-format on | ||
| 31 | |||
| 32 | RegisterHandlers(functions); | ||
| 33 | } | ||
| 34 | |||
| 35 | IAccountProxyInterface::~IAccountProxyInterface() = default; | ||
| 36 | |||
| 37 | IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_) | ||
| 38 | : ServiceFramework{system_, "IApplicationManagerInterface"} { | ||
| 39 | // clang-format off | ||
| 40 | static const FunctionInfo functions[] = { | ||
| 41 | {0, nullptr, "ListApplicationRecord"}, | ||
| 42 | {1, nullptr, "GenerateApplicationRecordCount"}, | ||
| 43 | {2, nullptr, "GetApplicationRecordUpdateSystemEvent"}, | ||
| 44 | {3, nullptr, "GetApplicationViewDeprecated"}, | ||
| 45 | {4, nullptr, "DeleteApplicationEntity"}, | ||
| 46 | {5, nullptr, "DeleteApplicationCompletely"}, | ||
| 47 | {6, nullptr, "IsAnyApplicationEntityRedundant"}, | ||
| 48 | {7, nullptr, "DeleteRedundantApplicationEntity"}, | ||
| 49 | {8, nullptr, "IsApplicationEntityMovable"}, | ||
| 50 | {9, nullptr, "MoveApplicationEntity"}, | ||
| 51 | {11, nullptr, "CalculateApplicationOccupiedSize"}, | ||
| 52 | {16, nullptr, "PushApplicationRecord"}, | ||
| 53 | {17, nullptr, "ListApplicationRecordContentMeta"}, | ||
| 54 | {19, nullptr, "LaunchApplicationOld"}, | ||
| 55 | {21, nullptr, "GetApplicationContentPath"}, | ||
| 56 | {22, nullptr, "TerminateApplication"}, | ||
| 57 | {23, nullptr, "ResolveApplicationContentPath"}, | ||
| 58 | {26, nullptr, "BeginInstallApplication"}, | ||
| 59 | {27, nullptr, "DeleteApplicationRecord"}, | ||
| 60 | {30, nullptr, "RequestApplicationUpdateInfo"}, | ||
| 61 | {31, nullptr, "Unknown31"}, | ||
| 62 | {32, nullptr, "CancelApplicationDownload"}, | ||
| 63 | {33, nullptr, "ResumeApplicationDownload"}, | ||
| 64 | {35, nullptr, "UpdateVersionList"}, | ||
| 65 | {36, nullptr, "PushLaunchVersion"}, | ||
| 66 | {37, nullptr, "ListRequiredVersion"}, | ||
| 67 | {38, nullptr, "CheckApplicationLaunchVersion"}, | ||
| 68 | {39, nullptr, "CheckApplicationLaunchRights"}, | ||
| 69 | {40, nullptr, "GetApplicationLogoData"}, | ||
| 70 | {41, nullptr, "CalculateApplicationDownloadRequiredSize"}, | ||
| 71 | {42, nullptr, "CleanupSdCard"}, | ||
| 72 | {43, nullptr, "CheckSdCardMountStatus"}, | ||
| 73 | {44, nullptr, "GetSdCardMountStatusChangedEvent"}, | ||
| 74 | {45, nullptr, "GetGameCardAttachmentEvent"}, | ||
| 75 | {46, nullptr, "GetGameCardAttachmentInfo"}, | ||
| 76 | {47, nullptr, "GetTotalSpaceSize"}, | ||
| 77 | {48, nullptr, "GetFreeSpaceSize"}, | ||
| 78 | {49, nullptr, "GetSdCardRemovedEvent"}, | ||
| 79 | {52, nullptr, "GetGameCardUpdateDetectionEvent"}, | ||
| 80 | {53, nullptr, "DisableApplicationAutoDelete"}, | ||
| 81 | {54, nullptr, "EnableApplicationAutoDelete"}, | ||
| 82 | {55, &IApplicationManagerInterface::GetApplicationDesiredLanguage, "GetApplicationDesiredLanguage"}, | ||
| 83 | {56, nullptr, "SetApplicationTerminateResult"}, | ||
| 84 | {57, nullptr, "ClearApplicationTerminateResult"}, | ||
| 85 | {58, nullptr, "GetLastSdCardMountUnexpectedResult"}, | ||
| 86 | {59, &IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode, "ConvertApplicationLanguageToLanguageCode"}, | ||
| 87 | {60, nullptr, "ConvertLanguageCodeToApplicationLanguage"}, | ||
| 88 | {61, nullptr, "GetBackgroundDownloadStressTaskInfo"}, | ||
| 89 | {62, nullptr, "GetGameCardStopper"}, | ||
| 90 | {63, nullptr, "IsSystemProgramInstalled"}, | ||
| 91 | {64, nullptr, "StartApplyDeltaTask"}, | ||
| 92 | {65, nullptr, "GetRequestServerStopper"}, | ||
| 93 | {66, nullptr, "GetBackgroundApplyDeltaStressTaskInfo"}, | ||
| 94 | {67, nullptr, "CancelApplicationApplyDelta"}, | ||
| 95 | {68, nullptr, "ResumeApplicationApplyDelta"}, | ||
| 96 | {69, nullptr, "CalculateApplicationApplyDeltaRequiredSize"}, | ||
| 97 | {70, nullptr, "ResumeAll"}, | ||
| 98 | {71, nullptr, "GetStorageSize"}, | ||
| 99 | {80, nullptr, "RequestDownloadApplication"}, | ||
| 100 | {81, nullptr, "RequestDownloadAddOnContent"}, | ||
| 101 | {82, nullptr, "DownloadApplication"}, | ||
| 102 | {83, nullptr, "CheckApplicationResumeRights"}, | ||
| 103 | {84, nullptr, "GetDynamicCommitEvent"}, | ||
| 104 | {85, nullptr, "RequestUpdateApplication2"}, | ||
| 105 | {86, nullptr, "EnableApplicationCrashReport"}, | ||
| 106 | {87, nullptr, "IsApplicationCrashReportEnabled"}, | ||
| 107 | {90, nullptr, "BoostSystemMemoryResourceLimit"}, | ||
| 108 | {91, nullptr, "DeprecatedLaunchApplication"}, | ||
| 109 | {92, nullptr, "GetRunningApplicationProgramId"}, | ||
| 110 | {93, nullptr, "GetMainApplicationProgramIndex"}, | ||
| 111 | {94, nullptr, "LaunchApplication"}, | ||
| 112 | {95, nullptr, "GetApplicationLaunchInfo"}, | ||
| 113 | {96, nullptr, "AcquireApplicationLaunchInfo"}, | ||
| 114 | {97, nullptr, "GetMainApplicationProgramIndexByApplicationLaunchInfo"}, | ||
| 115 | {98, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, | ||
| 116 | {99, nullptr, "LaunchDevMenu"}, | ||
| 117 | {100, nullptr, "ResetToFactorySettings"}, | ||
| 118 | {101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"}, | ||
| 119 | {102, nullptr, "ResetToFactorySettingsForRefurbishment"}, | ||
| 120 | {103, nullptr, "ResetToFactorySettingsWithPlatformRegion"}, | ||
| 121 | {104, nullptr, "ResetToFactorySettingsWithPlatformRegionAuthentication"}, | ||
| 122 | {105, nullptr, "RequestResetToFactorySettingsSecurely"}, | ||
| 123 | {106, nullptr, "RequestResetToFactorySettingsWithPlatformRegionAuthenticationSecurely"}, | ||
| 124 | {200, nullptr, "CalculateUserSaveDataStatistics"}, | ||
| 125 | {201, nullptr, "DeleteUserSaveDataAll"}, | ||
| 126 | {210, nullptr, "DeleteUserSystemSaveData"}, | ||
| 127 | {211, nullptr, "DeleteSaveData"}, | ||
| 128 | {220, nullptr, "UnregisterNetworkServiceAccount"}, | ||
| 129 | {221, nullptr, "UnregisterNetworkServiceAccountWithUserSaveDataDeletion"}, | ||
| 130 | {300, nullptr, "GetApplicationShellEvent"}, | ||
| 131 | {301, nullptr, "PopApplicationShellEventInfo"}, | ||
| 132 | {302, nullptr, "LaunchLibraryApplet"}, | ||
| 133 | {303, nullptr, "TerminateLibraryApplet"}, | ||
| 134 | {304, nullptr, "LaunchSystemApplet"}, | ||
| 135 | {305, nullptr, "TerminateSystemApplet"}, | ||
| 136 | {306, nullptr, "LaunchOverlayApplet"}, | ||
| 137 | {307, nullptr, "TerminateOverlayApplet"}, | ||
| 138 | {400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"}, | ||
| 139 | {401, nullptr, "InvalidateAllApplicationControlCache"}, | ||
| 140 | {402, nullptr, "RequestDownloadApplicationControlData"}, | ||
| 141 | {403, nullptr, "GetMaxApplicationControlCacheCount"}, | ||
| 142 | {404, nullptr, "InvalidateApplicationControlCache"}, | ||
| 143 | {405, nullptr, "ListApplicationControlCacheEntryInfo"}, | ||
| 144 | {406, nullptr, "GetApplicationControlProperty"}, | ||
| 145 | {407, nullptr, "ListApplicationTitle"}, | ||
| 146 | {408, nullptr, "ListApplicationIcon"}, | ||
| 147 | {502, nullptr, "RequestCheckGameCardRegistration"}, | ||
| 148 | {503, nullptr, "RequestGameCardRegistrationGoldPoint"}, | ||
| 149 | {504, nullptr, "RequestRegisterGameCard"}, | ||
| 150 | {505, nullptr, "GetGameCardMountFailureEvent"}, | ||
| 151 | {506, nullptr, "IsGameCardInserted"}, | ||
| 152 | {507, nullptr, "EnsureGameCardAccess"}, | ||
| 153 | {508, nullptr, "GetLastGameCardMountFailureResult"}, | ||
| 154 | {509, nullptr, "ListApplicationIdOnGameCard"}, | ||
| 155 | {510, nullptr, "GetGameCardPlatformRegion"}, | ||
| 156 | {600, nullptr, "CountApplicationContentMeta"}, | ||
| 157 | {601, nullptr, "ListApplicationContentMetaStatus"}, | ||
| 158 | {602, nullptr, "ListAvailableAddOnContent"}, | ||
| 159 | {603, nullptr, "GetOwnedApplicationContentMetaStatus"}, | ||
| 160 | {604, nullptr, "RegisterContentsExternalKey"}, | ||
| 161 | {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"}, | ||
| 162 | {606, nullptr, "GetContentMetaStorage"}, | ||
| 163 | {607, nullptr, "ListAvailableAddOnContent"}, | ||
| 164 | {609, nullptr, "ListAvailabilityAssuredAddOnContent"}, | ||
| 165 | {610, nullptr, "GetInstalledContentMetaStorage"}, | ||
| 166 | {611, nullptr, "PrepareAddOnContent"}, | ||
| 167 | {700, nullptr, "PushDownloadTaskList"}, | ||
| 168 | {701, nullptr, "ClearTaskStatusList"}, | ||
| 169 | {702, nullptr, "RequestDownloadTaskList"}, | ||
| 170 | {703, nullptr, "RequestEnsureDownloadTask"}, | ||
| 171 | {704, nullptr, "ListDownloadTaskStatus"}, | ||
| 172 | {705, nullptr, "RequestDownloadTaskListData"}, | ||
| 173 | {800, nullptr, "RequestVersionList"}, | ||
| 174 | {801, nullptr, "ListVersionList"}, | ||
| 175 | {802, nullptr, "RequestVersionListData"}, | ||
| 176 | {900, nullptr, "GetApplicationRecord"}, | ||
| 177 | {901, nullptr, "GetApplicationRecordProperty"}, | ||
| 178 | {902, nullptr, "EnableApplicationAutoUpdate"}, | ||
| 179 | {903, nullptr, "DisableApplicationAutoUpdate"}, | ||
| 180 | {904, nullptr, "TouchApplication"}, | ||
| 181 | {905, nullptr, "RequestApplicationUpdate"}, | ||
| 182 | {906, nullptr, "IsApplicationUpdateRequested"}, | ||
| 183 | {907, nullptr, "WithdrawApplicationUpdateRequest"}, | ||
| 184 | {908, nullptr, "ListApplicationRecordInstalledContentMeta"}, | ||
| 185 | {909, nullptr, "WithdrawCleanupAddOnContentsWithNoRightsRecommendation"}, | ||
| 186 | {910, nullptr, "HasApplicationRecord"}, | ||
| 187 | {911, nullptr, "SetPreInstalledApplication"}, | ||
| 188 | {912, nullptr, "ClearPreInstalledApplicationFlag"}, | ||
| 189 | {913, nullptr, "ListAllApplicationRecord"}, | ||
| 190 | {914, nullptr, "HideApplicationRecord"}, | ||
| 191 | {915, nullptr, "ShowApplicationRecord"}, | ||
| 192 | {916, nullptr, "IsApplicationAutoDeleteDisabled"}, | ||
| 193 | {1000, nullptr, "RequestVerifyApplicationDeprecated"}, | ||
| 194 | {1001, nullptr, "CorruptApplicationForDebug"}, | ||
| 195 | {1002, nullptr, "RequestVerifyAddOnContentsRights"}, | ||
| 196 | {1003, nullptr, "RequestVerifyApplication"}, | ||
| 197 | {1004, nullptr, "CorruptContentForDebug"}, | ||
| 198 | {1200, nullptr, "NeedsUpdateVulnerability"}, | ||
| 199 | {1300, nullptr, "IsAnyApplicationEntityInstalled"}, | ||
| 200 | {1301, nullptr, "DeleteApplicationContentEntities"}, | ||
| 201 | {1302, nullptr, "CleanupUnrecordedApplicationEntity"}, | ||
| 202 | {1303, nullptr, "CleanupAddOnContentsWithNoRights"}, | ||
| 203 | {1304, nullptr, "DeleteApplicationContentEntity"}, | ||
| 204 | {1305, nullptr, "TryDeleteRunningApplicationEntity"}, | ||
| 205 | {1306, nullptr, "TryDeleteRunningApplicationCompletely"}, | ||
| 206 | {1307, nullptr, "TryDeleteRunningApplicationContentEntities"}, | ||
| 207 | {1308, nullptr, "DeleteApplicationCompletelyForDebug"}, | ||
| 208 | {1309, nullptr, "CleanupUnavailableAddOnContents"}, | ||
| 209 | {1310, nullptr, "RequestMoveApplicationEntity"}, | ||
| 210 | {1311, nullptr, "EstimateSizeToMove"}, | ||
| 211 | {1312, nullptr, "HasMovableEntity"}, | ||
| 212 | {1313, nullptr, "CleanupOrphanContents"}, | ||
| 213 | {1314, nullptr, "CheckPreconditionSatisfiedToMove"}, | ||
| 214 | {1400, nullptr, "PrepareShutdown"}, | ||
| 215 | {1500, nullptr, "FormatSdCard"}, | ||
| 216 | {1501, nullptr, "NeedsSystemUpdateToFormatSdCard"}, | ||
| 217 | {1502, nullptr, "GetLastSdCardFormatUnexpectedResult"}, | ||
| 218 | {1504, nullptr, "InsertSdCard"}, | ||
| 219 | {1505, nullptr, "RemoveSdCard"}, | ||
| 220 | {1506, nullptr, "GetSdCardStartupStatus"}, | ||
| 221 | {1600, nullptr, "GetSystemSeedForPseudoDeviceId"}, | ||
| 222 | {1601, nullptr, "ResetSystemSeedForPseudoDeviceId"}, | ||
| 223 | {1700, nullptr, "ListApplicationDownloadingContentMeta"}, | ||
| 224 | {1701, nullptr, "GetApplicationView"}, | ||
| 225 | {1702, nullptr, "GetApplicationDownloadTaskStatus"}, | ||
| 226 | {1703, nullptr, "GetApplicationViewDownloadErrorContext"}, | ||
| 227 | {1704, nullptr, "GetApplicationViewWithPromotionInfo"}, | ||
| 228 | {1705, nullptr, "IsPatchAutoDeletableApplication"}, | ||
| 229 | {1800, nullptr, "IsNotificationSetupCompleted"}, | ||
| 230 | {1801, nullptr, "GetLastNotificationInfoCount"}, | ||
| 231 | {1802, nullptr, "ListLastNotificationInfo"}, | ||
| 232 | {1803, nullptr, "ListNotificationTask"}, | ||
| 233 | {1900, nullptr, "IsActiveAccount"}, | ||
| 234 | {1901, nullptr, "RequestDownloadApplicationPrepurchasedRights"}, | ||
| 235 | {1902, nullptr, "GetApplicationTicketInfo"}, | ||
| 236 | {1903, nullptr, "RequestDownloadApplicationPrepurchasedRightsForAccount"}, | ||
| 237 | {2000, nullptr, "GetSystemDeliveryInfo"}, | ||
| 238 | {2001, nullptr, "SelectLatestSystemDeliveryInfo"}, | ||
| 239 | {2002, nullptr, "VerifyDeliveryProtocolVersion"}, | ||
| 240 | {2003, nullptr, "GetApplicationDeliveryInfo"}, | ||
| 241 | {2004, nullptr, "HasAllContentsToDeliver"}, | ||
| 242 | {2005, nullptr, "CompareApplicationDeliveryInfo"}, | ||
| 243 | {2006, nullptr, "CanDeliverApplication"}, | ||
| 244 | {2007, nullptr, "ListContentMetaKeyToDeliverApplication"}, | ||
| 245 | {2008, nullptr, "NeedsSystemUpdateToDeliverApplication"}, | ||
| 246 | {2009, nullptr, "EstimateRequiredSize"}, | ||
| 247 | {2010, nullptr, "RequestReceiveApplication"}, | ||
| 248 | {2011, nullptr, "CommitReceiveApplication"}, | ||
| 249 | {2012, nullptr, "GetReceiveApplicationProgress"}, | ||
| 250 | {2013, nullptr, "RequestSendApplication"}, | ||
| 251 | {2014, nullptr, "GetSendApplicationProgress"}, | ||
| 252 | {2015, nullptr, "CompareSystemDeliveryInfo"}, | ||
| 253 | {2016, nullptr, "ListNotCommittedContentMeta"}, | ||
| 254 | {2017, nullptr, "CreateDownloadTask"}, | ||
| 255 | {2018, nullptr, "GetApplicationDeliveryInfoHash"}, | ||
| 256 | {2050, nullptr, "GetApplicationRightsOnClient"}, | ||
| 257 | {2051, nullptr, "InvalidateRightsIdCache"}, | ||
| 258 | {2100, nullptr, "GetApplicationTerminateResult"}, | ||
| 259 | {2101, nullptr, "GetRawApplicationTerminateResult"}, | ||
| 260 | {2150, nullptr, "CreateRightsEnvironment"}, | ||
| 261 | {2151, nullptr, "DestroyRightsEnvironment"}, | ||
| 262 | {2152, nullptr, "ActivateRightsEnvironment"}, | ||
| 263 | {2153, nullptr, "DeactivateRightsEnvironment"}, | ||
| 264 | {2154, nullptr, "ForceActivateRightsContextForExit"}, | ||
| 265 | {2155, nullptr, "UpdateRightsEnvironmentStatus"}, | ||
| 266 | {2156, nullptr, "CreateRightsEnvironmentForMicroApplication"}, | ||
| 267 | {2160, nullptr, "AddTargetApplicationToRightsEnvironment"}, | ||
| 268 | {2161, nullptr, "SetUsersToRightsEnvironment"}, | ||
| 269 | {2170, nullptr, "GetRightsEnvironmentStatus"}, | ||
| 270 | {2171, nullptr, "GetRightsEnvironmentStatusChangedEvent"}, | ||
| 271 | {2180, nullptr, "RequestExtendRightsInRightsEnvironment"}, | ||
| 272 | {2181, nullptr, "GetResultOfExtendRightsInRightsEnvironment"}, | ||
| 273 | {2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"}, | ||
| 274 | {2190, nullptr, "GetRightsEnvironmentHandleForApplication"}, | ||
| 275 | {2199, nullptr, "GetRightsEnvironmentCountForDebug"}, | ||
| 276 | {2200, nullptr, "GetGameCardApplicationCopyIdentifier"}, | ||
| 277 | {2201, nullptr, "GetInstalledApplicationCopyIdentifier"}, | ||
| 278 | {2250, nullptr, "RequestReportActiveELicence"}, | ||
| 279 | {2300, nullptr, "ListEventLog"}, | ||
| 280 | {2350, nullptr, "PerformAutoUpdateByApplicationId"}, | ||
| 281 | {2351, nullptr, "RequestNoDownloadRightsErrorResolution"}, | ||
| 282 | {2352, nullptr, "RequestResolveNoDownloadRightsError"}, | ||
| 283 | {2353, nullptr, "GetApplicationDownloadTaskInfo"}, | ||
| 284 | {2354, nullptr, "PrioritizeApplicationBackgroundTask"}, | ||
| 285 | {2355, nullptr, "PreferStorageEfficientUpdate"}, | ||
| 286 | {2356, nullptr, "RequestStorageEfficientUpdatePreferable"}, | ||
| 287 | {2357, nullptr, "EnableMultiCoreDownload"}, | ||
| 288 | {2358, nullptr, "DisableMultiCoreDownload"}, | ||
| 289 | {2359, nullptr, "IsMultiCoreDownloadEnabled"}, | ||
| 290 | {2400, nullptr, "GetPromotionInfo"}, | ||
| 291 | {2401, nullptr, "CountPromotionInfo"}, | ||
| 292 | {2402, nullptr, "ListPromotionInfo"}, | ||
| 293 | {2403, nullptr, "ImportPromotionJsonForDebug"}, | ||
| 294 | {2404, nullptr, "ClearPromotionInfoForDebug"}, | ||
| 295 | {2500, nullptr, "ConfirmAvailableTime"}, | ||
| 296 | {2510, nullptr, "CreateApplicationResource"}, | ||
| 297 | {2511, nullptr, "GetApplicationResource"}, | ||
| 298 | {2513, nullptr, "LaunchMicroApplication"}, | ||
| 299 | {2514, nullptr, "ClearTaskOfAsyncTaskManager"}, | ||
| 300 | {2515, nullptr, "CleanupAllPlaceHolderAndFragmentsIfNoTask"}, | ||
| 301 | {2516, nullptr, "EnsureApplicationCertificate"}, | ||
| 302 | {2517, nullptr, "CreateApplicationInstance"}, | ||
| 303 | {2518, nullptr, "UpdateQualificationForDebug"}, | ||
| 304 | {2519, nullptr, "IsQualificationTransitionSupported"}, | ||
| 305 | {2520, nullptr, "IsQualificationTransitionSupportedByProcessId"}, | ||
| 306 | {2521, nullptr, "GetRightsUserChangedEvent"}, | ||
| 307 | {2522, nullptr, "IsRomRedirectionAvailable"}, | ||
| 308 | {2800, nullptr, "GetApplicationIdOfPreomia"}, | ||
| 309 | {3000, nullptr, "RegisterDeviceLockKey"}, | ||
| 310 | {3001, nullptr, "UnregisterDeviceLockKey"}, | ||
| 311 | {3002, nullptr, "VerifyDeviceLockKey"}, | ||
| 312 | {3003, nullptr, "HideApplicationIcon"}, | ||
| 313 | {3004, nullptr, "ShowApplicationIcon"}, | ||
| 314 | {3005, nullptr, "HideApplicationTitle"}, | ||
| 315 | {3006, nullptr, "ShowApplicationTitle"}, | ||
| 316 | {3007, nullptr, "EnableGameCard"}, | ||
| 317 | {3008, nullptr, "DisableGameCard"}, | ||
| 318 | {3009, nullptr, "EnableLocalContentShare"}, | ||
| 319 | {3010, nullptr, "DisableLocalContentShare"}, | ||
| 320 | {3011, nullptr, "IsApplicationIconHidden"}, | ||
| 321 | {3012, nullptr, "IsApplicationTitleHidden"}, | ||
| 322 | {3013, nullptr, "IsGameCardEnabled"}, | ||
| 323 | {3014, nullptr, "IsLocalContentShareEnabled"}, | ||
| 324 | {3050, nullptr, "ListAssignELicenseTaskResult"}, | ||
| 325 | {9999, nullptr, "GetApplicationCertificate"}, | ||
| 326 | }; | ||
| 327 | // clang-format on | ||
| 328 | |||
| 329 | RegisterHandlers(functions); | ||
| 330 | } | ||
| 331 | |||
| 332 | IApplicationManagerInterface::~IApplicationManagerInterface() = default; | ||
| 333 | |||
| 334 | void IApplicationManagerInterface::GetApplicationControlData(HLERequestContext& ctx) { | ||
| 335 | IPC::RequestParser rp{ctx}; | ||
| 336 | const auto flag = rp.PopRaw<u64>(); | ||
| 337 | LOG_DEBUG(Service_NS, "called with flag={:016X}", flag); | ||
| 338 | |||
| 339 | const auto title_id = rp.PopRaw<u64>(); | ||
| 340 | |||
| 341 | const auto size = ctx.GetWriteBufferSize(); | ||
| 342 | |||
| 343 | const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), | ||
| 344 | system.GetContentProvider()}; | ||
| 345 | const auto control = pm.GetControlMetadata(); | ||
| 346 | |||
| 347 | std::vector<u8> out; | ||
| 348 | |||
| 349 | if (control.first != nullptr) { | ||
| 350 | if (size < 0x4000) { | ||
| 351 | LOG_ERROR(Service_NS, | ||
| 352 | "output buffer is too small! (actual={:016X}, expected_min=0x4000)", size); | ||
| 353 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 354 | // TODO(DarkLordZach): Find a better error code for this. | ||
| 355 | rb.Push(ResultUnknown); | ||
| 356 | return; | ||
| 357 | } | ||
| 358 | |||
| 359 | out.resize(0x4000); | ||
| 360 | const auto bytes = control.first->GetRawBytes(); | ||
| 361 | std::memcpy(out.data(), bytes.data(), bytes.size()); | ||
| 362 | } else { | ||
| 363 | LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.", | ||
| 364 | title_id); | ||
| 365 | out.resize(std::min<u64>(0x4000, size)); | ||
| 366 | } | ||
| 367 | |||
| 368 | if (control.second != nullptr) { | ||
| 369 | if (size < 0x4000 + control.second->GetSize()) { | ||
| 370 | LOG_ERROR(Service_NS, | ||
| 371 | "output buffer is too small! (actual={:016X}, expected_min={:016X})", size, | ||
| 372 | 0x4000 + control.second->GetSize()); | ||
| 373 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 374 | // TODO(DarkLordZach): Find a better error code for this. | ||
| 375 | rb.Push(ResultUnknown); | ||
| 376 | return; | ||
| 377 | } | ||
| 378 | |||
| 379 | out.resize(0x4000 + control.second->GetSize()); | ||
| 380 | control.second->Read(out.data() + 0x4000, control.second->GetSize()); | ||
| 381 | } else { | ||
| 382 | LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.", | ||
| 383 | title_id); | ||
| 384 | } | ||
| 385 | |||
| 386 | ctx.WriteBuffer(out); | ||
| 387 | |||
| 388 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 389 | rb.Push(ResultSuccess); | ||
| 390 | rb.Push<u32>(static_cast<u32>(out.size())); | ||
| 391 | } | ||
| 392 | |||
| 393 | void IApplicationManagerInterface::GetApplicationDesiredLanguage(HLERequestContext& ctx) { | ||
| 394 | IPC::RequestParser rp{ctx}; | ||
| 395 | const auto supported_languages = rp.Pop<u32>(); | ||
| 396 | |||
| 397 | u8 desired_language{}; | ||
| 398 | const auto res = GetApplicationDesiredLanguage(&desired_language, supported_languages); | ||
| 399 | if (res == ResultSuccess) { | ||
| 400 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 401 | rb.Push(ResultSuccess); | ||
| 402 | rb.Push<u32>(desired_language); | ||
| 403 | } else { | ||
| 404 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 405 | rb.Push(res); | ||
| 406 | } | ||
| 407 | } | ||
| 408 | |||
| 409 | Result IApplicationManagerInterface::GetApplicationDesiredLanguage(u8* out_desired_language, | ||
| 410 | const u32 supported_languages) { | ||
| 411 | LOG_DEBUG(Service_NS, "called with supported_languages={:08X}", supported_languages); | ||
| 412 | |||
| 413 | // Get language code from settings | ||
| 414 | const auto language_code = | ||
| 415 | Set::GetLanguageCodeFromIndex(static_cast<s32>(Settings::values.language_index.GetValue())); | ||
| 416 | |||
| 417 | // Convert to application language, get priority list | ||
| 418 | const auto application_language = ConvertToApplicationLanguage(language_code); | ||
| 419 | if (application_language == std::nullopt) { | ||
| 420 | LOG_ERROR(Service_NS, "Could not convert application language! language_code={}", | ||
| 421 | language_code); | ||
| 422 | return Service::NS::ResultApplicationLanguageNotFound; | ||
| 423 | } | ||
| 424 | const auto priority_list = GetApplicationLanguagePriorityList(*application_language); | ||
| 425 | if (!priority_list) { | ||
| 426 | LOG_ERROR(Service_NS, | ||
| 427 | "Could not find application language priorities! application_language={}", | ||
| 428 | *application_language); | ||
| 429 | return Service::NS::ResultApplicationLanguageNotFound; | ||
| 430 | } | ||
| 431 | |||
| 432 | // Try to find a valid language. | ||
| 433 | for (const auto lang : *priority_list) { | ||
| 434 | const auto supported_flag = GetSupportedLanguageFlag(lang); | ||
| 435 | if (supported_languages == 0 || (supported_languages & supported_flag) == supported_flag) { | ||
| 436 | *out_desired_language = static_cast<u8>(lang); | ||
| 437 | return ResultSuccess; | ||
| 438 | } | ||
| 439 | } | ||
| 440 | |||
| 441 | LOG_ERROR(Service_NS, "Could not find a valid language! supported_languages={:08X}", | ||
| 442 | supported_languages); | ||
| 443 | return Service::NS::ResultApplicationLanguageNotFound; | ||
| 444 | } | ||
| 445 | |||
| 446 | void IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode( | ||
| 447 | HLERequestContext& ctx) { | ||
| 448 | IPC::RequestParser rp{ctx}; | ||
| 449 | const auto application_language = rp.Pop<u8>(); | ||
| 450 | |||
| 451 | u64 language_code{}; | ||
| 452 | const auto res = ConvertApplicationLanguageToLanguageCode(&language_code, application_language); | ||
| 453 | if (res == ResultSuccess) { | ||
| 454 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 455 | rb.Push(ResultSuccess); | ||
| 456 | rb.Push(language_code); | ||
| 457 | } else { | ||
| 458 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 459 | rb.Push(res); | ||
| 460 | } | ||
| 461 | } | ||
| 462 | |||
| 463 | Result IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode( | ||
| 464 | u64* out_language_code, u8 application_language) { | ||
| 465 | const auto language_code = | ||
| 466 | ConvertToLanguageCode(static_cast<ApplicationLanguage>(application_language)); | ||
| 467 | if (language_code == std::nullopt) { | ||
| 468 | LOG_ERROR(Service_NS, "Language not found! application_language={}", application_language); | ||
| 469 | return Service::NS::ResultApplicationLanguageNotFound; | ||
| 470 | } | ||
| 471 | |||
| 472 | *out_language_code = static_cast<u64>(*language_code); | ||
| 473 | return ResultSuccess; | ||
| 474 | } | ||
| 475 | |||
| 476 | IApplicationVersionInterface::IApplicationVersionInterface(Core::System& system_) | ||
| 477 | : ServiceFramework{system_, "IApplicationVersionInterface"} { | ||
| 478 | // clang-format off | ||
| 479 | static const FunctionInfo functions[] = { | ||
| 480 | {0, nullptr, "GetLaunchRequiredVersion"}, | ||
| 481 | {1, nullptr, "UpgradeLaunchRequiredVersion"}, | ||
| 482 | {35, nullptr, "UpdateVersionList"}, | ||
| 483 | {36, nullptr, "PushLaunchVersion"}, | ||
| 484 | {37, nullptr, "ListRequiredVersion"}, | ||
| 485 | {800, nullptr, "RequestVersionList"}, | ||
| 486 | {801, nullptr, "ListVersionList"}, | ||
| 487 | {802, nullptr, "RequestVersionListData"}, | ||
| 488 | {900, nullptr, "ImportAutoUpdatePolicyJsonForDebug"}, | ||
| 489 | {901, nullptr, "ListDefaultAutoUpdatePolicy"}, | ||
| 490 | {902, nullptr, "ListAutoUpdatePolicyForSpecificApplication"}, | ||
| 491 | {1000, nullptr, "PerformAutoUpdate"}, | ||
| 492 | {1001, nullptr, "ListAutoUpdateSchedule"}, | ||
| 493 | }; | ||
| 494 | // clang-format on | ||
| 495 | |||
| 496 | RegisterHandlers(functions); | ||
| 497 | } | ||
| 498 | |||
| 499 | IApplicationVersionInterface::~IApplicationVersionInterface() = default; | ||
| 500 | |||
| 501 | IContentManagementInterface::IContentManagementInterface(Core::System& system_) | ||
| 502 | : ServiceFramework{system_, "IContentManagementInterface"} { | ||
| 503 | // clang-format off | ||
| 504 | static const FunctionInfo functions[] = { | ||
| 505 | {11, nullptr, "CalculateApplicationOccupiedSize"}, | ||
| 506 | {43, nullptr, "CheckSdCardMountStatus"}, | ||
| 507 | {47, &IContentManagementInterface::GetTotalSpaceSize, "GetTotalSpaceSize"}, | ||
| 508 | {48, &IContentManagementInterface::GetFreeSpaceSize, "GetFreeSpaceSize"}, | ||
| 509 | {600, nullptr, "CountApplicationContentMeta"}, | ||
| 510 | {601, nullptr, "ListApplicationContentMetaStatus"}, | ||
| 511 | {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"}, | ||
| 512 | {607, nullptr, "IsAnyApplicationRunning"}, | ||
| 513 | }; | ||
| 514 | // clang-format on | ||
| 515 | |||
| 516 | RegisterHandlers(functions); | ||
| 517 | } | ||
| 518 | |||
| 519 | IContentManagementInterface::~IContentManagementInterface() = default; | ||
| 520 | |||
| 521 | void IContentManagementInterface::GetTotalSpaceSize(HLERequestContext& ctx) { | ||
| 522 | IPC::RequestParser rp{ctx}; | ||
| 523 | const auto storage{rp.PopEnum<FileSys::StorageId>()}; | ||
| 524 | |||
| 525 | LOG_INFO(Service_Capture, "called, storage={}", storage); | ||
| 526 | |||
| 527 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 528 | rb.Push(ResultSuccess); | ||
| 529 | rb.Push<u64>(system.GetFileSystemController().GetTotalSpaceSize(storage)); | ||
| 530 | } | ||
| 531 | |||
| 532 | void IContentManagementInterface::GetFreeSpaceSize(HLERequestContext& ctx) { | ||
| 533 | IPC::RequestParser rp{ctx}; | ||
| 534 | const auto storage{rp.PopEnum<FileSys::StorageId>()}; | ||
| 535 | |||
| 536 | LOG_INFO(Service_Capture, "called, storage={}", storage); | ||
| 537 | |||
| 538 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 539 | rb.Push(ResultSuccess); | ||
| 540 | rb.Push<u64>(system.GetFileSystemController().GetFreeSpaceSize(storage)); | ||
| 541 | } | ||
| 542 | |||
| 543 | IDocumentInterface::IDocumentInterface(Core::System& system_) | ||
| 544 | : ServiceFramework{system_, "IDocumentInterface"} { | ||
| 545 | // clang-format off | ||
| 546 | static const FunctionInfo functions[] = { | ||
| 547 | {21, nullptr, "GetApplicationContentPath"}, | ||
| 548 | {23, &IDocumentInterface::ResolveApplicationContentPath, "ResolveApplicationContentPath"}, | ||
| 549 | {92, &IDocumentInterface::GetRunningApplicationProgramId, "GetRunningApplicationProgramId"}, | ||
| 550 | }; | ||
| 551 | // clang-format on | ||
| 552 | |||
| 553 | RegisterHandlers(functions); | ||
| 554 | } | ||
| 555 | |||
| 556 | IDocumentInterface::~IDocumentInterface() = default; | ||
| 557 | |||
| 558 | void IDocumentInterface::ResolveApplicationContentPath(HLERequestContext& ctx) { | ||
| 559 | struct ContentPath { | ||
| 560 | u8 file_system_proxy_type; | ||
| 561 | u64 program_id; | ||
| 562 | }; | ||
| 563 | static_assert(sizeof(ContentPath) == 0x10, "ContentPath has wrong size"); | ||
| 564 | |||
| 565 | IPC::RequestParser rp{ctx}; | ||
| 566 | auto content_path = rp.PopRaw<ContentPath>(); | ||
| 567 | LOG_WARNING(Service_NS, "(STUBBED) called, file_system_proxy_type={}, program_id={:016X}", | ||
| 568 | content_path.file_system_proxy_type, content_path.program_id); | ||
| 569 | |||
| 570 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 571 | rb.Push(ResultSuccess); | ||
| 572 | } | ||
| 573 | |||
| 574 | void IDocumentInterface::GetRunningApplicationProgramId(HLERequestContext& ctx) { | ||
| 575 | IPC::RequestParser rp{ctx}; | ||
| 576 | const auto caller_program_id = rp.PopRaw<u64>(); | ||
| 577 | LOG_WARNING(Service_NS, "(STUBBED) called, caller_program_id={:016X}", caller_program_id); | ||
| 578 | |||
| 579 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 580 | rb.Push(ResultSuccess); | ||
| 581 | rb.Push<u64>(system.GetApplicationProcessProgramID()); | ||
| 582 | } | ||
| 583 | |||
| 584 | IDownloadTaskInterface::IDownloadTaskInterface(Core::System& system_) | ||
| 585 | : ServiceFramework{system_, "IDownloadTaskInterface"} { | ||
| 586 | // clang-format off | ||
| 587 | static const FunctionInfo functions[] = { | ||
| 588 | {701, nullptr, "ClearTaskStatusList"}, | ||
| 589 | {702, nullptr, "RequestDownloadTaskList"}, | ||
| 590 | {703, nullptr, "RequestEnsureDownloadTask"}, | ||
| 591 | {704, nullptr, "ListDownloadTaskStatus"}, | ||
| 592 | {705, nullptr, "RequestDownloadTaskListData"}, | ||
| 593 | {706, nullptr, "TryCommitCurrentApplicationDownloadTask"}, | ||
| 594 | {707, nullptr, "EnableAutoCommit"}, | ||
| 595 | {708, nullptr, "DisableAutoCommit"}, | ||
| 596 | {709, nullptr, "TriggerDynamicCommitEvent"}, | ||
| 597 | }; | ||
| 598 | // clang-format on | ||
| 599 | |||
| 600 | RegisterHandlers(functions); | ||
| 601 | } | ||
| 602 | |||
| 603 | IDownloadTaskInterface::~IDownloadTaskInterface() = default; | ||
| 604 | |||
| 605 | IECommerceInterface::IECommerceInterface(Core::System& system_) | ||
| 606 | : ServiceFramework{system_, "IECommerceInterface"} { | ||
| 607 | // clang-format off | ||
| 608 | static const FunctionInfo functions[] = { | ||
| 609 | {0, nullptr, "RequestLinkDevice"}, | ||
| 610 | {1, nullptr, "RequestCleanupAllPreInstalledApplications"}, | ||
| 611 | {2, nullptr, "RequestCleanupPreInstalledApplication"}, | ||
| 612 | {3, nullptr, "RequestSyncRights"}, | ||
| 613 | {4, nullptr, "RequestUnlinkDevice"}, | ||
| 614 | {5, nullptr, "RequestRevokeAllELicense"}, | ||
| 615 | {6, nullptr, "RequestSyncRightsBasedOnAssignedELicenses"}, | ||
| 616 | }; | ||
| 617 | // clang-format on | ||
| 618 | |||
| 619 | RegisterHandlers(functions); | ||
| 620 | } | ||
| 621 | |||
| 622 | IECommerceInterface::~IECommerceInterface() = default; | ||
| 623 | |||
| 624 | IFactoryResetInterface::IFactoryResetInterface(Core::System& system_) | ||
| 625 | : ServiceFramework{system_, "IFactoryResetInterface"} { | ||
| 626 | // clang-format off | ||
| 627 | static const FunctionInfo functions[] = { | ||
| 628 | {100, nullptr, "ResetToFactorySettings"}, | ||
| 629 | {101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"}, | ||
| 630 | {102, nullptr, "ResetToFactorySettingsForRefurbishment"}, | ||
| 631 | {103, nullptr, "ResetToFactorySettingsWithPlatformRegion"}, | ||
| 632 | {104, nullptr, "ResetToFactorySettingsWithPlatformRegionAuthentication"}, | ||
| 633 | {105, nullptr, "RequestResetToFactorySettingsSecurely"}, | ||
| 634 | {106, nullptr, "RequestResetToFactorySettingsWithPlatformRegionAuthenticationSecurely"}, | ||
| 635 | }; | ||
| 636 | // clang-format on | ||
| 637 | |||
| 638 | RegisterHandlers(functions); | ||
| 639 | } | ||
| 640 | |||
| 641 | IFactoryResetInterface::~IFactoryResetInterface() = default; | ||
| 642 | |||
| 643 | IReadOnlyApplicationRecordInterface::IReadOnlyApplicationRecordInterface(Core::System& system_) | ||
| 644 | : ServiceFramework{system_, "IReadOnlyApplicationRecordInterface"} { | ||
| 645 | static const FunctionInfo functions[] = { | ||
| 646 | {0, &IReadOnlyApplicationRecordInterface::HasApplicationRecord, "HasApplicationRecord"}, | ||
| 647 | {1, nullptr, "NotifyApplicationFailure"}, | ||
| 648 | {2, &IReadOnlyApplicationRecordInterface::IsDataCorruptedResult, "IsDataCorruptedResult"}, | ||
| 649 | }; | ||
| 650 | // clang-format on | ||
| 651 | |||
| 652 | RegisterHandlers(functions); | ||
| 653 | } | ||
| 654 | |||
| 655 | IReadOnlyApplicationRecordInterface::~IReadOnlyApplicationRecordInterface() = default; | ||
| 656 | |||
| 657 | void IReadOnlyApplicationRecordInterface::HasApplicationRecord(HLERequestContext& ctx) { | ||
| 658 | IPC::RequestParser rp{ctx}; | ||
| 659 | const u64 program_id = rp.PopRaw<u64>(); | ||
| 660 | LOG_WARNING(Service_NS, "(STUBBED) called, program_id={:X}", program_id); | ||
| 661 | |||
| 662 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 663 | rb.Push(ResultSuccess); | ||
| 664 | rb.Push<u8>(1); | ||
| 665 | } | ||
| 666 | |||
| 667 | void IReadOnlyApplicationRecordInterface::IsDataCorruptedResult(HLERequestContext& ctx) { | ||
| 668 | IPC::RequestParser rp{ctx}; | ||
| 669 | const auto result = rp.PopRaw<Result>(); | ||
| 670 | LOG_WARNING(Service_NS, "(STUBBED) called, result={:#x}", result.GetInnerValue()); | ||
| 671 | |||
| 672 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 673 | rb.Push(ResultSuccess); | ||
| 674 | rb.Push<u8>(0); | ||
| 675 | } | ||
| 676 | |||
| 677 | IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface( | ||
| 678 | Core::System& system_) | ||
| 679 | : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} { | ||
| 680 | // clang-format off | ||
| 681 | static const FunctionInfo functions[] = { | ||
| 682 | {0, &IReadOnlyApplicationControlDataInterface::GetApplicationControlData, "GetApplicationControlData"}, | ||
| 683 | {1, nullptr, "GetApplicationDesiredLanguage"}, | ||
| 684 | {2, nullptr, "ConvertApplicationLanguageToLanguageCode"}, | ||
| 685 | {3, nullptr, "ConvertLanguageCodeToApplicationLanguage"}, | ||
| 686 | {4, nullptr, "SelectApplicationDesiredLanguage"}, | ||
| 687 | }; | ||
| 688 | // clang-format on | ||
| 689 | |||
| 690 | RegisterHandlers(functions); | ||
| 691 | } | ||
| 692 | |||
| 693 | IReadOnlyApplicationControlDataInterface::~IReadOnlyApplicationControlDataInterface() = default; | ||
| 694 | |||
| 695 | void IReadOnlyApplicationControlDataInterface::GetApplicationControlData(HLERequestContext& ctx) { | ||
| 696 | enum class ApplicationControlSource : u8 { | ||
| 697 | CacheOnly, | ||
| 698 | Storage, | ||
| 699 | StorageOnly, | ||
| 700 | }; | ||
| 701 | |||
| 702 | struct RequestParameters { | ||
| 703 | ApplicationControlSource source; | ||
| 704 | u64 application_id; | ||
| 705 | }; | ||
| 706 | static_assert(sizeof(RequestParameters) == 0x10, "RequestParameters has incorrect size."); | ||
| 707 | |||
| 708 | IPC::RequestParser rp{ctx}; | ||
| 709 | std::vector<u8> nacp_data{}; | ||
| 710 | const auto parameters{rp.PopRaw<RequestParameters>()}; | ||
| 711 | const auto result = | ||
| 712 | system.GetARPManager().GetControlProperty(&nacp_data, parameters.application_id); | ||
| 713 | |||
| 714 | if (result == ResultSuccess) { | ||
| 715 | ctx.WriteBuffer(nacp_data.data(), nacp_data.size()); | ||
| 716 | } | ||
| 717 | |||
| 718 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 719 | rb.Push(result); | ||
| 720 | } | ||
| 721 | |||
| 722 | NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} { | ||
| 723 | // clang-format off | ||
| 724 | static const FunctionInfo functions[] = { | ||
| 725 | {7988, nullptr, "GetDynamicRightsInterface"}, | ||
| 726 | {7989, &NS::PushInterface<IReadOnlyApplicationControlDataInterface>, "GetReadOnlyApplicationControlDataInterface"}, | ||
| 727 | {7991, &NS::PushInterface<IReadOnlyApplicationRecordInterface>, "GetReadOnlyApplicationRecordInterface"}, | ||
| 728 | {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"}, | ||
| 729 | {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"}, | ||
| 730 | {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"}, | ||
| 731 | {7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"}, | ||
| 732 | {7996, &NS::PushIApplicationManagerInterface, "GetApplicationManagerInterface"}, | ||
| 733 | {7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"}, | ||
| 734 | {7998, &NS::PushInterface<IContentManagementInterface>, "GetContentManagementInterface"}, | ||
| 735 | {7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"}, | ||
| 736 | }; | ||
| 737 | // clang-format on | ||
| 738 | |||
| 739 | RegisterHandlers(functions); | ||
| 740 | } | ||
| 741 | |||
| 742 | NS::~NS() = default; | ||
| 743 | |||
| 744 | std::shared_ptr<IApplicationManagerInterface> NS::GetApplicationManagerInterface() const { | ||
| 745 | return GetInterface<IApplicationManagerInterface>(system); | ||
| 746 | } | ||
| 747 | |||
| 748 | class NS_DEV final : public ServiceFramework<NS_DEV> { | ||
| 749 | public: | ||
| 750 | explicit NS_DEV(Core::System& system_) : ServiceFramework{system_, "ns:dev"} { | ||
| 751 | // clang-format off | ||
| 752 | static const FunctionInfo functions[] = { | ||
| 753 | {0, nullptr, "LaunchProgram"}, | ||
| 754 | {1, nullptr, "TerminateProcess"}, | ||
| 755 | {2, nullptr, "TerminateProgram"}, | ||
| 756 | {4, nullptr, "GetShellEvent"}, | ||
| 757 | {5, nullptr, "GetShellEventInfo"}, | ||
| 758 | {6, nullptr, "TerminateApplication"}, | ||
| 759 | {7, nullptr, "PrepareLaunchProgramFromHost"}, | ||
| 760 | {8, nullptr, "LaunchApplicationFromHost"}, | ||
| 761 | {9, nullptr, "LaunchApplicationWithStorageIdForDevelop"}, | ||
| 762 | {10, nullptr, "IsSystemMemoryResourceLimitBoosted"}, | ||
| 763 | {11, nullptr, "GetRunningApplicationProcessIdForDevelop"}, | ||
| 764 | {12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActiveForDevelop"}, | ||
| 765 | {13, nullptr, "CreateApplicationResourceForDevelop"}, | ||
| 766 | {14, nullptr, "IsPreomiaForDevelop"}, | ||
| 767 | {15, nullptr, "GetApplicationProgramIdFromHost"}, | ||
| 768 | {16, nullptr, "RefreshCachedDebugValues"}, | ||
| 769 | {17, nullptr, "PrepareLaunchApplicationFromHost"}, | ||
| 770 | {18, nullptr, "GetLaunchEvent"}, | ||
| 771 | {19, nullptr, "GetLaunchResult"}, | ||
| 772 | }; | ||
| 773 | // clang-format on | ||
| 774 | |||
| 775 | RegisterHandlers(functions); | ||
| 776 | } | ||
| 777 | }; | ||
| 778 | |||
| 779 | class ISystemUpdateControl final : public ServiceFramework<ISystemUpdateControl> { | ||
| 780 | public: | ||
| 781 | explicit ISystemUpdateControl(Core::System& system_) | ||
| 782 | : ServiceFramework{system_, "ISystemUpdateControl"} { | ||
| 783 | // clang-format off | ||
| 784 | static const FunctionInfo functions[] = { | ||
| 785 | {0, nullptr, "HasDownloaded"}, | ||
| 786 | {1, nullptr, "RequestCheckLatestUpdate"}, | ||
| 787 | {2, nullptr, "RequestDownloadLatestUpdate"}, | ||
| 788 | {3, nullptr, "GetDownloadProgress"}, | ||
| 789 | {4, nullptr, "ApplyDownloadedUpdate"}, | ||
| 790 | {5, nullptr, "RequestPrepareCardUpdate"}, | ||
| 791 | {6, nullptr, "GetPrepareCardUpdateProgress"}, | ||
| 792 | {7, nullptr, "HasPreparedCardUpdate"}, | ||
| 793 | {8, nullptr, "ApplyCardUpdate"}, | ||
| 794 | {9, nullptr, "GetDownloadedEulaDataSize"}, | ||
| 795 | {10, nullptr, "GetDownloadedEulaData"}, | ||
| 796 | {11, nullptr, "SetupCardUpdate"}, | ||
| 797 | {12, nullptr, "GetPreparedCardUpdateEulaDataSize"}, | ||
| 798 | {13, nullptr, "GetPreparedCardUpdateEulaData"}, | ||
| 799 | {14, nullptr, "SetupCardUpdateViaSystemUpdater"}, | ||
| 800 | {15, nullptr, "HasReceived"}, | ||
| 801 | {16, nullptr, "RequestReceiveSystemUpdate"}, | ||
| 802 | {17, nullptr, "GetReceiveProgress"}, | ||
| 803 | {18, nullptr, "ApplyReceivedUpdate"}, | ||
| 804 | {19, nullptr, "GetReceivedEulaDataSize"}, | ||
| 805 | {20, nullptr, "GetReceivedEulaData"}, | ||
| 806 | {21, nullptr, "SetupToReceiveSystemUpdate"}, | ||
| 807 | {22, nullptr, "RequestCheckLatestUpdateIncludesRebootlessUpdate"}, | ||
| 808 | }; | ||
| 809 | // clang-format on | ||
| 810 | |||
| 811 | RegisterHandlers(functions); | ||
| 812 | } | ||
| 813 | }; | ||
| 814 | |||
| 815 | class NS_SU final : public ServiceFramework<NS_SU> { | ||
| 816 | public: | ||
| 817 | explicit NS_SU(Core::System& system_) : ServiceFramework{system_, "ns:su"} { | ||
| 818 | // clang-format off | ||
| 819 | static const FunctionInfo functions[] = { | ||
| 820 | {0, nullptr, "GetBackgroundNetworkUpdateState"}, | ||
| 821 | {1, &NS_SU::OpenSystemUpdateControl, "OpenSystemUpdateControl"}, | ||
| 822 | {2, nullptr, "NotifyExFatDriverRequired"}, | ||
| 823 | {3, nullptr, "ClearExFatDriverStatusForDebug"}, | ||
| 824 | {4, nullptr, "RequestBackgroundNetworkUpdate"}, | ||
| 825 | {5, nullptr, "NotifyBackgroundNetworkUpdate"}, | ||
| 826 | {6, nullptr, "NotifyExFatDriverDownloadedForDebug"}, | ||
| 827 | {9, nullptr, "GetSystemUpdateNotificationEventForContentDelivery"}, | ||
| 828 | {10, nullptr, "NotifySystemUpdateForContentDelivery"}, | ||
| 829 | {11, nullptr, "PrepareShutdown"}, | ||
| 830 | {12, nullptr, "Unknown12"}, | ||
| 831 | {13, nullptr, "Unknown13"}, | ||
| 832 | {14, nullptr, "Unknown14"}, | ||
| 833 | {15, nullptr, "Unknown15"}, | ||
| 834 | {16, nullptr, "DestroySystemUpdateTask"}, | ||
| 835 | {17, nullptr, "RequestSendSystemUpdate"}, | ||
| 836 | {18, nullptr, "GetSendSystemUpdateProgress"}, | ||
| 837 | }; | ||
| 838 | // clang-format on | ||
| 839 | |||
| 840 | RegisterHandlers(functions); | ||
| 841 | } | ||
| 842 | |||
| 843 | private: | ||
| 844 | void OpenSystemUpdateControl(HLERequestContext& ctx) { | ||
| 845 | LOG_DEBUG(Service_NS, "called"); | ||
| 846 | |||
| 847 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 848 | rb.Push(ResultSuccess); | ||
| 849 | rb.PushIpcInterface<ISystemUpdateControl>(system); | ||
| 850 | } | ||
| 851 | }; | ||
| 852 | |||
| 853 | class NS_VM final : public ServiceFramework<NS_VM> { | ||
| 854 | public: | ||
| 855 | explicit NS_VM(Core::System& system_) : ServiceFramework{system_, "ns:vm"} { | ||
| 856 | // clang-format off | ||
| 857 | static const FunctionInfo functions[] = { | ||
| 858 | {1200, &NS_VM::NeedsUpdateVulnerability, "NeedsUpdateVulnerability"}, | ||
| 859 | {1201, nullptr, "UpdateSafeSystemVersionForDebug"}, | ||
| 860 | {1202, nullptr, "GetSafeSystemVersion"}, | ||
| 861 | }; | ||
| 862 | // clang-format on | ||
| 863 | |||
| 864 | RegisterHandlers(functions); | ||
| 865 | } | ||
| 866 | |||
| 867 | private: | ||
| 868 | void NeedsUpdateVulnerability(HLERequestContext& ctx) { | ||
| 869 | LOG_WARNING(Service_NS, "(STUBBED) called"); | ||
| 870 | |||
| 871 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 872 | rb.Push(ResultSuccess); | ||
| 873 | rb.Push(false); | ||
| 874 | } | ||
| 875 | }; | ||
| 876 | |||
| 877 | void LoopProcess(Core::System& system) { | 15 | void LoopProcess(Core::System& system) { |
| 878 | auto server_manager = std::make_unique<ServerManager>(system); | 16 | auto server_manager = std::make_unique<ServerManager>(system); |
| 879 | 17 | ||
| 880 | server_manager->RegisterNamedService("ns:am2", std::make_shared<NS>("ns:am2", system)); | 18 | server_manager->RegisterNamedService( |
| 881 | server_manager->RegisterNamedService("ns:ec", std::make_shared<NS>("ns:ec", system)); | 19 | "ns:am2", std::make_shared<IServiceGetterInterface>(system, "ns:am2")); |
| 882 | server_manager->RegisterNamedService("ns:rid", std::make_shared<NS>("ns:rid", system)); | 20 | server_manager->RegisterNamedService( |
| 883 | server_manager->RegisterNamedService("ns:rt", std::make_shared<NS>("ns:rt", system)); | 21 | "ns:ec", std::make_shared<IServiceGetterInterface>(system, "ns:ec")); |
| 884 | server_manager->RegisterNamedService("ns:web", std::make_shared<NS>("ns:web", system)); | 22 | server_manager->RegisterNamedService( |
| 885 | server_manager->RegisterNamedService("ns:ro", std::make_shared<NS>("ns:ro", system)); | 23 | "ns:rid", std::make_shared<IServiceGetterInterface>(system, "ns:rid")); |
| 886 | 24 | server_manager->RegisterNamedService( | |
| 887 | server_manager->RegisterNamedService("ns:dev", std::make_shared<NS_DEV>(system)); | 25 | "ns:rt", std::make_shared<IServiceGetterInterface>(system, "ns:rt")); |
| 888 | server_manager->RegisterNamedService("ns:su", std::make_shared<NS_SU>(system)); | 26 | server_manager->RegisterNamedService( |
| 889 | server_manager->RegisterNamedService("ns:vm", std::make_shared<NS_VM>(system)); | 27 | "ns:web", std::make_shared<IServiceGetterInterface>(system, "ns:web")); |
| 890 | server_manager->RegisterNamedService("pdm:qry", std::make_shared<PDM_QRY>(system)); | 28 | server_manager->RegisterNamedService( |
| 29 | "ns:ro", std::make_shared<IServiceGetterInterface>(system, "ns:ro")); | ||
| 30 | |||
| 31 | server_manager->RegisterNamedService("ns:dev", std::make_shared<IDevelopInterface>(system)); | ||
| 32 | server_manager->RegisterNamedService("ns:su", std::make_shared<ISystemUpdateInterface>(system)); | ||
| 33 | server_manager->RegisterNamedService("ns:vm", | ||
| 34 | std::make_shared<IVulnerabilityManagerInterface>(system)); | ||
| 35 | server_manager->RegisterNamedService("pdm:qry", std::make_shared<IQueryService>(system)); | ||
| 891 | 36 | ||
| 892 | server_manager->RegisterNamedService("pl:s", | 37 | server_manager->RegisterNamedService("pl:s", |
| 893 | std::make_shared<IPlatformServiceManager>(system, "pl:s")); | 38 | std::make_shared<IPlatformServiceManager>(system, "pl:s")); |
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index 9ee306ef9..f79b4ae3d 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h | |||
| @@ -3,141 +3,12 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include "core/hle/service/service.h" | ||
| 7 | |||
| 8 | namespace Core { | 6 | namespace Core { |
| 9 | class System; | 7 | class System; |
| 10 | } | 8 | } |
| 11 | 9 | ||
| 12 | namespace Service { | 10 | namespace Service::NS { |
| 13 | |||
| 14 | namespace FileSystem { | ||
| 15 | class FileSystemController; | ||
| 16 | } // namespace FileSystem | ||
| 17 | |||
| 18 | namespace NS { | ||
| 19 | |||
| 20 | class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> { | ||
| 21 | public: | ||
| 22 | explicit IAccountProxyInterface(Core::System& system_); | ||
| 23 | ~IAccountProxyInterface() override; | ||
| 24 | }; | ||
| 25 | |||
| 26 | class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> { | ||
| 27 | public: | ||
| 28 | explicit IApplicationManagerInterface(Core::System& system_); | ||
| 29 | ~IApplicationManagerInterface() override; | ||
| 30 | |||
| 31 | Result GetApplicationDesiredLanguage(u8* out_desired_language, u32 supported_languages); | ||
| 32 | Result ConvertApplicationLanguageToLanguageCode(u64* out_language_code, | ||
| 33 | u8 application_language); | ||
| 34 | |||
| 35 | private: | ||
| 36 | void GetApplicationControlData(HLERequestContext& ctx); | ||
| 37 | void GetApplicationDesiredLanguage(HLERequestContext& ctx); | ||
| 38 | void ConvertApplicationLanguageToLanguageCode(HLERequestContext& ctx); | ||
| 39 | }; | ||
| 40 | |||
| 41 | class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> { | ||
| 42 | public: | ||
| 43 | explicit IApplicationVersionInterface(Core::System& system_); | ||
| 44 | ~IApplicationVersionInterface() override; | ||
| 45 | }; | ||
| 46 | |||
| 47 | class IContentManagementInterface final : public ServiceFramework<IContentManagementInterface> { | ||
| 48 | public: | ||
| 49 | explicit IContentManagementInterface(Core::System& system_); | ||
| 50 | ~IContentManagementInterface() override; | ||
| 51 | |||
| 52 | private: | ||
| 53 | void GetTotalSpaceSize(HLERequestContext& ctx); | ||
| 54 | void GetFreeSpaceSize(HLERequestContext& ctx); | ||
| 55 | }; | ||
| 56 | |||
| 57 | class IDocumentInterface final : public ServiceFramework<IDocumentInterface> { | ||
| 58 | public: | ||
| 59 | explicit IDocumentInterface(Core::System& system_); | ||
| 60 | ~IDocumentInterface() override; | ||
| 61 | |||
| 62 | private: | ||
| 63 | void ResolveApplicationContentPath(HLERequestContext& ctx); | ||
| 64 | void GetRunningApplicationProgramId(HLERequestContext& ctx); | ||
| 65 | }; | ||
| 66 | |||
| 67 | class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> { | ||
| 68 | public: | ||
| 69 | explicit IDownloadTaskInterface(Core::System& system_); | ||
| 70 | ~IDownloadTaskInterface() override; | ||
| 71 | }; | ||
| 72 | |||
| 73 | class IECommerceInterface final : public ServiceFramework<IECommerceInterface> { | ||
| 74 | public: | ||
| 75 | explicit IECommerceInterface(Core::System& system_); | ||
| 76 | ~IECommerceInterface() override; | ||
| 77 | }; | ||
| 78 | |||
| 79 | class IFactoryResetInterface final : public ServiceFramework<IFactoryResetInterface> { | ||
| 80 | public: | ||
| 81 | explicit IFactoryResetInterface(Core::System& system_); | ||
| 82 | ~IFactoryResetInterface() override; | ||
| 83 | }; | ||
| 84 | |||
| 85 | class IReadOnlyApplicationRecordInterface final | ||
| 86 | : public ServiceFramework<IReadOnlyApplicationRecordInterface> { | ||
| 87 | public: | ||
| 88 | explicit IReadOnlyApplicationRecordInterface(Core::System& system_); | ||
| 89 | ~IReadOnlyApplicationRecordInterface() override; | ||
| 90 | |||
| 91 | private: | ||
| 92 | void HasApplicationRecord(HLERequestContext& ctx); | ||
| 93 | void IsDataCorruptedResult(HLERequestContext& ctx); | ||
| 94 | }; | ||
| 95 | |||
| 96 | class IReadOnlyApplicationControlDataInterface final | ||
| 97 | : public ServiceFramework<IReadOnlyApplicationControlDataInterface> { | ||
| 98 | public: | ||
| 99 | explicit IReadOnlyApplicationControlDataInterface(Core::System& system_); | ||
| 100 | ~IReadOnlyApplicationControlDataInterface() override; | ||
| 101 | |||
| 102 | private: | ||
| 103 | void GetApplicationControlData(HLERequestContext& ctx); | ||
| 104 | }; | ||
| 105 | |||
| 106 | class NS final : public ServiceFramework<NS> { | ||
| 107 | public: | ||
| 108 | explicit NS(const char* name, Core::System& system_); | ||
| 109 | ~NS() override; | ||
| 110 | |||
| 111 | std::shared_ptr<IApplicationManagerInterface> GetApplicationManagerInterface() const; | ||
| 112 | |||
| 113 | private: | ||
| 114 | template <typename T, typename... Args> | ||
| 115 | void PushInterface(HLERequestContext& ctx) { | ||
| 116 | LOG_DEBUG(Service_NS, "called"); | ||
| 117 | |||
| 118 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 119 | rb.Push(ResultSuccess); | ||
| 120 | rb.PushIpcInterface<T>(system); | ||
| 121 | } | ||
| 122 | |||
| 123 | void PushIApplicationManagerInterface(HLERequestContext& ctx) { | ||
| 124 | LOG_DEBUG(Service_NS, "called"); | ||
| 125 | |||
| 126 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 127 | rb.Push(ResultSuccess); | ||
| 128 | rb.PushIpcInterface<IApplicationManagerInterface>(system); | ||
| 129 | } | ||
| 130 | |||
| 131 | template <typename T, typename... Args> | ||
| 132 | std::shared_ptr<T> GetInterface(Args&&... args) const { | ||
| 133 | static_assert(std::is_base_of_v<SessionRequestHandler, T>, | ||
| 134 | "Not a base of ServiceFrameworkBase"); | ||
| 135 | |||
| 136 | return std::make_shared<T>(std::forward<Args>(args)...); | ||
| 137 | } | ||
| 138 | }; | ||
| 139 | 11 | ||
| 140 | void LoopProcess(Core::System& system); | 12 | void LoopProcess(Core::System& system); |
| 141 | 13 | ||
| 142 | } // namespace NS | 14 | } // namespace Service::NS |
| 143 | } // namespace Service | ||
diff --git a/src/core/hle/service/ns/errors.h b/src/core/hle/service/ns/ns_results.h index 16d2ea6f7..16d2ea6f7 100644 --- a/src/core/hle/service/ns/errors.h +++ b/src/core/hle/service/ns/ns_results.h | |||
diff --git a/src/core/hle/service/ns/ns_types.h b/src/core/hle/service/ns/ns_types.h new file mode 100644 index 000000000..38421b0f4 --- /dev/null +++ b/src/core/hle/service/ns/ns_types.h | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_funcs.h" | ||
| 7 | #include "common/uuid.h" | ||
| 8 | #include "core/file_sys/romfs_factory.h" | ||
| 9 | |||
| 10 | namespace Service::NS { | ||
| 11 | |||
| 12 | enum class ApplicationRecordType : u8 { | ||
| 13 | Installing = 2, | ||
| 14 | Installed = 3, | ||
| 15 | GameCardNotInserted = 5, | ||
| 16 | Archived = 11, | ||
| 17 | GameCard = 16, | ||
| 18 | }; | ||
| 19 | |||
| 20 | enum class ApplicationControlSource : u8 { | ||
| 21 | CacheOnly = 0, | ||
| 22 | Storage = 1, | ||
| 23 | StorageOnly = 2, | ||
| 24 | }; | ||
| 25 | |||
| 26 | enum class BackgroundNetworkUpdateState : u8 { | ||
| 27 | None, | ||
| 28 | InProgress, | ||
| 29 | Ready, | ||
| 30 | }; | ||
| 31 | |||
| 32 | struct ApplicationRecord { | ||
| 33 | u64 application_id; | ||
| 34 | ApplicationRecordType type; | ||
| 35 | u8 unknown; | ||
| 36 | INSERT_PADDING_BYTES_NOINIT(0x6); | ||
| 37 | u8 unknown2; | ||
| 38 | INSERT_PADDING_BYTES_NOINIT(0x7); | ||
| 39 | }; | ||
| 40 | static_assert(sizeof(ApplicationRecord) == 0x18, "ApplicationRecord has incorrect size."); | ||
| 41 | |||
| 42 | /// ApplicationView | ||
| 43 | struct ApplicationView { | ||
| 44 | u64 application_id; ///< ApplicationId. | ||
| 45 | u32 unk; ///< Unknown. | ||
| 46 | u32 flags; ///< Flags. | ||
| 47 | std::array<u8, 0x10> unk_x10; ///< Unknown. | ||
| 48 | u32 unk_x20; ///< Unknown. | ||
| 49 | u16 unk_x24; ///< Unknown. | ||
| 50 | std::array<u8, 0x2> unk_x26; ///< Unknown. | ||
| 51 | std::array<u8, 0x8> unk_x28; ///< Unknown. | ||
| 52 | std::array<u8, 0x10> unk_x30; ///< Unknown. | ||
| 53 | u32 unk_x40; ///< Unknown. | ||
| 54 | u8 unk_x44; ///< Unknown. | ||
| 55 | std::array<u8, 0xb> unk_x45; ///< Unknown. | ||
| 56 | }; | ||
| 57 | static_assert(sizeof(ApplicationView) == 0x50, "ApplicationView has incorrect size."); | ||
| 58 | |||
| 59 | struct ApplicationRightsOnClient { | ||
| 60 | u64 application_id; | ||
| 61 | Common::UUID uid; | ||
| 62 | u8 flags; | ||
| 63 | u8 flags2; | ||
| 64 | INSERT_PADDING_BYTES_NOINIT(0x6); | ||
| 65 | }; | ||
| 66 | static_assert(sizeof(ApplicationRightsOnClient) == 0x20, | ||
| 67 | "ApplicationRightsOnClient has incorrect size."); | ||
| 68 | |||
| 69 | /// NsPromotionInfo | ||
| 70 | struct PromotionInfo { | ||
| 71 | u64 start_timestamp; ///< POSIX timestamp for the promotion start. | ||
| 72 | u64 end_timestamp; ///< POSIX timestamp for the promotion end. | ||
| 73 | s64 remaining_time; ///< Remaining time until the promotion ends, in nanoseconds | ||
| 74 | ///< ({end_timestamp - current_time} converted to nanoseconds). | ||
| 75 | INSERT_PADDING_BYTES_NOINIT(0x4); | ||
| 76 | u8 flags; ///< Flags. Bit0: whether the PromotionInfo is valid (including bit1). Bit1 clear: | ||
| 77 | ///< remaining_time is set. | ||
| 78 | INSERT_PADDING_BYTES_NOINIT(0x3); | ||
| 79 | }; | ||
| 80 | static_assert(sizeof(PromotionInfo) == 0x20, "PromotionInfo has incorrect size."); | ||
| 81 | |||
| 82 | /// NsApplicationViewWithPromotionInfo | ||
| 83 | struct ApplicationViewWithPromotionInfo { | ||
| 84 | ApplicationView view; ///< \ref NsApplicationView | ||
| 85 | PromotionInfo promotion; ///< \ref NsPromotionInfo | ||
| 86 | }; | ||
| 87 | static_assert(sizeof(ApplicationViewWithPromotionInfo) == 0x70, | ||
| 88 | "ApplicationViewWithPromotionInfo has incorrect size."); | ||
| 89 | |||
| 90 | struct ApplicationOccupiedSizeEntity { | ||
| 91 | FileSys::StorageId storage_id; | ||
| 92 | u64 app_size; | ||
| 93 | u64 patch_size; | ||
| 94 | u64 aoc_size; | ||
| 95 | }; | ||
| 96 | static_assert(sizeof(ApplicationOccupiedSizeEntity) == 0x20, | ||
| 97 | "ApplicationOccupiedSizeEntity has incorrect size."); | ||
| 98 | |||
| 99 | struct ApplicationOccupiedSize { | ||
| 100 | std::array<ApplicationOccupiedSizeEntity, 4> entities; | ||
| 101 | }; | ||
| 102 | static_assert(sizeof(ApplicationOccupiedSize) == 0x80, | ||
| 103 | "ApplicationOccupiedSize has incorrect size."); | ||
| 104 | |||
| 105 | struct ContentPath { | ||
| 106 | u8 file_system_proxy_type; | ||
| 107 | u64 program_id; | ||
| 108 | }; | ||
| 109 | static_assert(sizeof(ContentPath) == 0x10, "ContentPath has incorrect size."); | ||
| 110 | |||
| 111 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/pdm_qry.cpp b/src/core/hle/service/ns/pdm_qry.cpp deleted file mode 100644 index ce0ee30e0..000000000 --- a/src/core/hle/service/ns/pdm_qry.cpp +++ /dev/null | |||
| @@ -1,67 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <memory> | ||
| 5 | |||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "common/uuid.h" | ||
| 8 | #include "core/hle/service/ipc_helpers.h" | ||
| 9 | #include "core/hle/service/ns/pdm_qry.h" | ||
| 10 | #include "core/hle/service/service.h" | ||
| 11 | |||
| 12 | namespace Service::NS { | ||
| 13 | |||
| 14 | PDM_QRY::PDM_QRY(Core::System& system_) : ServiceFramework{system_, "pdm:qry"} { | ||
| 15 | // clang-format off | ||
| 16 | static const FunctionInfo functions[] = { | ||
| 17 | {0, nullptr, "QueryAppletEvent"}, | ||
| 18 | {1, nullptr, "QueryPlayStatistics"}, | ||
| 19 | {2, nullptr, "QueryPlayStatisticsByUserAccountId"}, | ||
| 20 | {3, nullptr, "QueryPlayStatisticsByNetworkServiceAccountId"}, | ||
| 21 | {4, nullptr, "QueryPlayStatisticsByApplicationId"}, | ||
| 22 | {5, &PDM_QRY::QueryPlayStatisticsByApplicationIdAndUserAccountId, "QueryPlayStatisticsByApplicationIdAndUserAccountId"}, | ||
| 23 | {6, nullptr, "QueryPlayStatisticsByApplicationIdAndNetworkServiceAccountId"}, | ||
| 24 | {7, nullptr, "QueryLastPlayTimeV0"}, | ||
| 25 | {8, nullptr, "QueryPlayEvent"}, | ||
| 26 | {9, nullptr, "GetAvailablePlayEventRange"}, | ||
| 27 | {10, nullptr, "QueryAccountEvent"}, | ||
| 28 | {11, nullptr, "QueryAccountPlayEvent"}, | ||
| 29 | {12, nullptr, "GetAvailableAccountPlayEventRange"}, | ||
| 30 | {13, nullptr, "QueryApplicationPlayStatisticsForSystemV0"}, | ||
| 31 | {14, nullptr, "QueryRecentlyPlayedApplication"}, | ||
| 32 | {15, nullptr, "GetRecentlyPlayedApplicationUpdateEvent"}, | ||
| 33 | {16, nullptr, "QueryApplicationPlayStatisticsByUserAccountIdForSystemV0"}, | ||
| 34 | {17, nullptr, "QueryLastPlayTime"}, | ||
| 35 | {18, nullptr, "QueryApplicationPlayStatisticsForSystem"}, | ||
| 36 | {19, nullptr, "QueryApplicationPlayStatisticsByUserAccountIdForSystem"}, | ||
| 37 | }; | ||
| 38 | // clang-format on | ||
| 39 | |||
| 40 | RegisterHandlers(functions); | ||
| 41 | } | ||
| 42 | |||
| 43 | PDM_QRY::~PDM_QRY() = default; | ||
| 44 | |||
| 45 | void PDM_QRY::QueryPlayStatisticsByApplicationIdAndUserAccountId(HLERequestContext& ctx) { | ||
| 46 | IPC::RequestParser rp{ctx}; | ||
| 47 | const auto unknown = rp.Pop<bool>(); | ||
| 48 | rp.Pop<u8>(); // Padding | ||
| 49 | const auto application_id = rp.Pop<u64>(); | ||
| 50 | const auto user_account_uid = rp.PopRaw<Common::UUID>(); | ||
| 51 | |||
| 52 | // TODO(German77): Read statistics of the game | ||
| 53 | PlayStatistics statistics{ | ||
| 54 | .application_id = application_id, | ||
| 55 | .total_launches = 1, | ||
| 56 | }; | ||
| 57 | |||
| 58 | LOG_WARNING(Service_NS, | ||
| 59 | "(STUBBED) called. unknown={}. application_id=0x{:016X}, user_account_uid=0x{}", | ||
| 60 | unknown, application_id, user_account_uid.RawString()); | ||
| 61 | |||
| 62 | IPC::ResponseBuilder rb{ctx, 12}; | ||
| 63 | rb.Push(ResultSuccess); | ||
| 64 | rb.PushRaw(statistics); | ||
| 65 | } | ||
| 66 | |||
| 67 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/iplatform_service_manager.cpp b/src/core/hle/service/ns/platform_service_manager.cpp index 46268be95..23cf05005 100644 --- a/src/core/hle/service/ns/iplatform_service_manager.cpp +++ b/src/core/hle/service/ns/platform_service_manager.cpp | |||
| @@ -18,9 +18,9 @@ | |||
| 18 | #include "core/hle/kernel/k_shared_memory.h" | 18 | #include "core/hle/kernel/k_shared_memory.h" |
| 19 | #include "core/hle/kernel/kernel.h" | 19 | #include "core/hle/kernel/kernel.h" |
| 20 | #include "core/hle/kernel/physical_memory.h" | 20 | #include "core/hle/kernel/physical_memory.h" |
| 21 | #include "core/hle/service/cmif_serialization.h" | ||
| 21 | #include "core/hle/service/filesystem/filesystem.h" | 22 | #include "core/hle/service/filesystem/filesystem.h" |
| 22 | #include "core/hle/service/ipc_helpers.h" | 23 | #include "core/hle/service/ns/platform_service_manager.h" |
| 23 | #include "core/hle/service/ns/iplatform_service_manager.h" | ||
| 24 | 24 | ||
| 25 | namespace Service::NS { | 25 | namespace Service::NS { |
| 26 | 26 | ||
| @@ -37,11 +37,6 @@ constexpr u32 EXPECTED_MAGIC{0x36f81a1e}; // What we expect the encrypted bfttf | |||
| 37 | constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000}; | 37 | constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000}; |
| 38 | constexpr FontRegion EMPTY_REGION{0, 0}; | 38 | constexpr FontRegion EMPTY_REGION{0, 0}; |
| 39 | 39 | ||
| 40 | enum class LoadState : u32 { | ||
| 41 | Loading = 0, | ||
| 42 | Done = 1, | ||
| 43 | }; | ||
| 44 | |||
| 45 | static void DecryptSharedFont(const std::vector<u32>& input, Kernel::PhysicalMemory& output, | 40 | static void DecryptSharedFont(const std::vector<u32>& input, Kernel::PhysicalMemory& output, |
| 46 | std::size_t& offset) { | 41 | std::size_t& offset) { |
| 47 | ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE, | 42 | ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE, |
| @@ -138,13 +133,13 @@ IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const ch | |||
| 138 | : ServiceFramework{system_, service_name_}, impl{std::make_unique<Impl>()} { | 133 | : ServiceFramework{system_, service_name_}, impl{std::make_unique<Impl>()} { |
| 139 | // clang-format off | 134 | // clang-format off |
| 140 | static const FunctionInfo functions[] = { | 135 | static const FunctionInfo functions[] = { |
| 141 | {0, &IPlatformServiceManager::RequestLoad, "RequestLoad"}, | 136 | {0, D<&IPlatformServiceManager::RequestLoad>, "RequestLoad"}, |
| 142 | {1, &IPlatformServiceManager::GetLoadState, "GetLoadState"}, | 137 | {1, D<&IPlatformServiceManager::GetLoadState>, "GetLoadState"}, |
| 143 | {2, &IPlatformServiceManager::GetSize, "GetSize"}, | 138 | {2, D<&IPlatformServiceManager::GetSize>, "GetSize"}, |
| 144 | {3, &IPlatformServiceManager::GetSharedMemoryAddressOffset, "GetSharedMemoryAddressOffset"}, | 139 | {3, D<&IPlatformServiceManager::GetSharedMemoryAddressOffset>, "GetSharedMemoryAddressOffset"}, |
| 145 | {4, &IPlatformServiceManager::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, | 140 | {4, D<&IPlatformServiceManager::GetSharedMemoryNativeHandle>, "GetSharedMemoryNativeHandle"}, |
| 146 | {5, &IPlatformServiceManager::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"}, | 141 | {5, D<&IPlatformServiceManager::GetSharedFontInOrderOfPriority>, "GetSharedFontInOrderOfPriority"}, |
| 147 | {6, &IPlatformServiceManager::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriorityForSystem"}, | 142 | {6, D<&IPlatformServiceManager::GetSharedFontInOrderOfPriority>, "GetSharedFontInOrderOfPriorityForSystem"}, |
| 148 | {100, nullptr, "RequestApplicationFunctionAuthorization"}, | 143 | {100, nullptr, "RequestApplicationFunctionAuthorization"}, |
| 149 | {101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"}, | 144 | {101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"}, |
| 150 | {102, nullptr, "RequestApplicationFunctionAuthorizationByApplicationId"}, | 145 | {102, nullptr, "RequestApplicationFunctionAuthorizationByApplicationId"}, |
| @@ -208,47 +203,33 @@ IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const ch | |||
| 208 | 203 | ||
| 209 | IPlatformServiceManager::~IPlatformServiceManager() = default; | 204 | IPlatformServiceManager::~IPlatformServiceManager() = default; |
| 210 | 205 | ||
| 211 | void IPlatformServiceManager::RequestLoad(HLERequestContext& ctx) { | 206 | Result IPlatformServiceManager::RequestLoad(SharedFontType type) { |
| 212 | IPC::RequestParser rp{ctx}; | ||
| 213 | const u32 shared_font_type{rp.Pop<u32>()}; | ||
| 214 | // Games don't call this so all fonts should be loaded | 207 | // Games don't call this so all fonts should be loaded |
| 215 | LOG_DEBUG(Service_NS, "called, shared_font_type={}", shared_font_type); | 208 | LOG_DEBUG(Service_NS, "called, shared_font_type={}", type); |
| 216 | 209 | R_SUCCEED(); | |
| 217 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 218 | rb.Push(ResultSuccess); | ||
| 219 | } | 210 | } |
| 220 | 211 | ||
| 221 | void IPlatformServiceManager::GetLoadState(HLERequestContext& ctx) { | 212 | Result IPlatformServiceManager::GetLoadState(Out<LoadState> out_load_state, SharedFontType type) { |
| 222 | IPC::RequestParser rp{ctx}; | 213 | LOG_DEBUG(Service_NS, "called, shared_font_type={}", type); |
| 223 | const u32 font_id{rp.Pop<u32>()}; | 214 | *out_load_state = LoadState::Loaded; |
| 224 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); | 215 | R_SUCCEED(); |
| 225 | |||
| 226 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 227 | rb.Push(ResultSuccess); | ||
| 228 | rb.Push<u32>(static_cast<u32>(LoadState::Done)); | ||
| 229 | } | 216 | } |
| 230 | 217 | ||
| 231 | void IPlatformServiceManager::GetSize(HLERequestContext& ctx) { | 218 | Result IPlatformServiceManager::GetSize(Out<u32> out_size, SharedFontType type) { |
| 232 | IPC::RequestParser rp{ctx}; | 219 | LOG_DEBUG(Service_NS, "called, shared_font_type={}", type); |
| 233 | const u32 font_id{rp.Pop<u32>()}; | 220 | *out_size = impl->GetSharedFontRegion(static_cast<size_t>(type)).size; |
| 234 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); | 221 | R_SUCCEED(); |
| 235 | |||
| 236 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 237 | rb.Push(ResultSuccess); | ||
| 238 | rb.Push<u32>(impl->GetSharedFontRegion(font_id).size); | ||
| 239 | } | 222 | } |
| 240 | 223 | ||
| 241 | void IPlatformServiceManager::GetSharedMemoryAddressOffset(HLERequestContext& ctx) { | 224 | Result IPlatformServiceManager::GetSharedMemoryAddressOffset(Out<u32> out_shared_memory_offset, |
| 242 | IPC::RequestParser rp{ctx}; | 225 | SharedFontType type) { |
| 243 | const u32 font_id{rp.Pop<u32>()}; | 226 | LOG_DEBUG(Service_NS, "called, shared_font_type={}", type); |
| 244 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); | 227 | *out_shared_memory_offset = impl->GetSharedFontRegion(static_cast<size_t>(type)).offset; |
| 245 | 228 | R_SUCCEED(); | |
| 246 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 247 | rb.Push(ResultSuccess); | ||
| 248 | rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset); | ||
| 249 | } | 229 | } |
| 250 | 230 | ||
| 251 | void IPlatformServiceManager::GetSharedMemoryNativeHandle(HLERequestContext& ctx) { | 231 | Result IPlatformServiceManager::GetSharedMemoryNativeHandle( |
| 232 | OutCopyHandle<Kernel::KSharedMemory> out_shared_memory_native_handle) { | ||
| 252 | // Map backing memory for the font data | 233 | // Map backing memory for the font data |
| 253 | LOG_DEBUG(Service_NS, "called"); | 234 | LOG_DEBUG(Service_NS, "called"); |
| 254 | 235 | ||
| @@ -256,50 +237,37 @@ void IPlatformServiceManager::GetSharedMemoryNativeHandle(HLERequestContext& ctx | |||
| 256 | std::memcpy(kernel.GetFontSharedMem().GetPointer(), impl->shared_font->data(), | 237 | std::memcpy(kernel.GetFontSharedMem().GetPointer(), impl->shared_font->data(), |
| 257 | impl->shared_font->size()); | 238 | impl->shared_font->size()); |
| 258 | 239 | ||
| 259 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 240 | // FIXME: this shouldn't belong to the kernel |
| 260 | rb.Push(ResultSuccess); | 241 | *out_shared_memory_native_handle = &kernel.GetFontSharedMem(); |
| 261 | rb.PushCopyObjects(&kernel.GetFontSharedMem()); | 242 | R_SUCCEED(); |
| 262 | } | 243 | } |
| 263 | 244 | ||
| 264 | void IPlatformServiceManager::GetSharedFontInOrderOfPriority(HLERequestContext& ctx) { | 245 | Result IPlatformServiceManager::GetSharedFontInOrderOfPriority( |
| 246 | OutArray<u32, BufferAttr_HipcMapAlias> out_font_codes, | ||
| 247 | OutArray<u32, BufferAttr_HipcMapAlias> out_font_offsets, | ||
| 248 | OutArray<u32, BufferAttr_HipcMapAlias> out_font_sizes, Out<bool> out_fonts_are_loaded, | ||
| 249 | Out<u32> out_font_count, Set::LanguageCode language_code) { | ||
| 250 | LOG_DEBUG(Service_NS, "called, language_code={:#x}", language_code); | ||
| 251 | |||
| 265 | // The maximum number of elements that can be returned is 6. Regardless of the available fonts | 252 | // The maximum number of elements that can be returned is 6. Regardless of the available fonts |
| 266 | // or buffer size. | 253 | // or buffer size. |
| 267 | constexpr std::size_t MaxElementCount = 6; | 254 | constexpr size_t MaxElementCount = 6; |
| 268 | IPC::RequestParser rp{ctx}; | ||
| 269 | const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for | ||
| 270 | const std::size_t font_codes_count = | ||
| 271 | std::min(MaxElementCount, ctx.GetWriteBufferNumElements<u32>(0)); | ||
| 272 | const std::size_t font_offsets_count = | ||
| 273 | std::min(MaxElementCount, ctx.GetWriteBufferNumElements<u32>(1)); | ||
| 274 | const std::size_t font_sizes_count = | ||
| 275 | std::min(MaxElementCount, ctx.GetWriteBufferNumElements<u32>(2)); | ||
| 276 | LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code); | ||
| 277 | |||
| 278 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 279 | std::vector<u32> font_codes; | ||
| 280 | std::vector<u32> font_offsets; | ||
| 281 | std::vector<u32> font_sizes; | ||
| 282 | 255 | ||
| 283 | // TODO(ogniK): Have actual priority order | 256 | // TODO(ogniK): Have actual priority order |
| 284 | for (std::size_t i = 0; i < impl->shared_font_regions.size(); i++) { | 257 | const auto max_size = std::min({MaxElementCount, out_font_codes.size(), out_font_offsets.size(), |
| 285 | font_codes.push_back(static_cast<u32>(i)); | 258 | out_font_sizes.size(), impl->shared_font_regions.size()}); |
| 286 | auto region = impl->GetSharedFontRegion(i); | ||
| 287 | font_offsets.push_back(region.offset); | ||
| 288 | font_sizes.push_back(region.size); | ||
| 289 | } | ||
| 290 | 259 | ||
| 291 | // Resize buffers if game requests smaller size output | 260 | for (size_t i = 0; i < max_size; i++) { |
| 292 | font_codes.resize(std::min(font_codes.size(), font_codes_count)); | 261 | auto region = impl->GetSharedFontRegion(i); |
| 293 | font_offsets.resize(std::min(font_offsets.size(), font_offsets_count)); | ||
| 294 | font_sizes.resize(std::min(font_sizes.size(), font_sizes_count)); | ||
| 295 | 262 | ||
| 296 | ctx.WriteBuffer(font_codes, 0); | 263 | out_font_codes[i] = static_cast<u32>(i); |
| 297 | ctx.WriteBuffer(font_offsets, 1); | 264 | out_font_offsets[i] = region.offset; |
| 298 | ctx.WriteBuffer(font_sizes, 2); | 265 | out_font_sizes[i] = region.size; |
| 266 | } | ||
| 299 | 267 | ||
| 300 | rb.Push(ResultSuccess); | 268 | *out_fonts_are_loaded = true; |
| 301 | rb.Push<u8>(static_cast<u8>(LoadState::Done)); // Fonts Loaded | 269 | *out_font_count = static_cast<u32>(max_size); |
| 302 | rb.Push<u32>(static_cast<u32>(font_codes.size())); | 270 | R_SUCCEED(); |
| 303 | } | 271 | } |
| 304 | 272 | ||
| 305 | } // namespace Service::NS | 273 | } // namespace Service::NS |
diff --git a/src/core/hle/service/ns/iplatform_service_manager.h b/src/core/hle/service/ns/platform_service_manager.h index 03071e02b..b82c385a6 100644 --- a/src/core/hle/service/ns/iplatform_service_manager.h +++ b/src/core/hle/service/ns/platform_service_manager.h | |||
| @@ -5,7 +5,9 @@ | |||
| 5 | 5 | ||
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include <vector> | 7 | #include <vector> |
| 8 | #include "core/hle/service/cmif_types.h" | ||
| 8 | #include "core/hle/service/service.h" | 9 | #include "core/hle/service/service.h" |
| 10 | #include "core/hle/service/set/settings_types.h" | ||
| 9 | 11 | ||
| 10 | namespace Service { | 12 | namespace Service { |
| 11 | 13 | ||
| @@ -23,6 +25,20 @@ enum class FontArchives : u64 { | |||
| 23 | ChineseSimple = 0x0100000000000814, | 25 | ChineseSimple = 0x0100000000000814, |
| 24 | }; | 26 | }; |
| 25 | 27 | ||
| 28 | enum class SharedFontType : u32 { | ||
| 29 | JapanUSEuropeStandard = 0, | ||
| 30 | ChineseSimplified = 1, | ||
| 31 | ExtendedChineseSimplified = 2, | ||
| 32 | ChineseTraditional = 3, | ||
| 33 | KoreanHangul = 4, | ||
| 34 | NintendoExtended = 5, | ||
| 35 | }; | ||
| 36 | |||
| 37 | enum class LoadState : u32 { | ||
| 38 | Loading = 0, | ||
| 39 | Loaded = 1, | ||
| 40 | }; | ||
| 41 | |||
| 26 | constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{ | 42 | constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{ |
| 27 | std::make_pair(FontArchives::Standard, "nintendo_udsg-r_std_003.bfttf"), | 43 | std::make_pair(FontArchives::Standard, "nintendo_udsg-r_std_003.bfttf"), |
| 28 | std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_org_zh-cn_003.bfttf"), | 44 | std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_org_zh-cn_003.bfttf"), |
| @@ -42,12 +58,17 @@ public: | |||
| 42 | ~IPlatformServiceManager() override; | 58 | ~IPlatformServiceManager() override; |
| 43 | 59 | ||
| 44 | private: | 60 | private: |
| 45 | void RequestLoad(HLERequestContext& ctx); | 61 | Result RequestLoad(SharedFontType type); |
| 46 | void GetLoadState(HLERequestContext& ctx); | 62 | Result GetLoadState(Out<LoadState> out_load_state, SharedFontType type); |
| 47 | void GetSize(HLERequestContext& ctx); | 63 | Result GetSize(Out<u32> out_size, SharedFontType type); |
| 48 | void GetSharedMemoryAddressOffset(HLERequestContext& ctx); | 64 | Result GetSharedMemoryAddressOffset(Out<u32> out_shared_memory_offset, SharedFontType type); |
| 49 | void GetSharedMemoryNativeHandle(HLERequestContext& ctx); | 65 | Result GetSharedMemoryNativeHandle( |
| 50 | void GetSharedFontInOrderOfPriority(HLERequestContext& ctx); | 66 | OutCopyHandle<Kernel::KSharedMemory> out_shared_memory_native_handle); |
| 67 | Result GetSharedFontInOrderOfPriority(OutArray<u32, BufferAttr_HipcMapAlias> out_font_codes, | ||
| 68 | OutArray<u32, BufferAttr_HipcMapAlias> out_font_offsets, | ||
| 69 | OutArray<u32, BufferAttr_HipcMapAlias> out_font_sizes, | ||
| 70 | Out<bool> out_fonts_are_loaded, Out<u32> out_font_count, | ||
| 71 | Set::LanguageCode language_code); | ||
| 51 | 72 | ||
| 52 | struct Impl; | 73 | struct Impl; |
| 53 | std::unique_ptr<Impl> impl; | 74 | std::unique_ptr<Impl> impl; |
diff --git a/src/core/hle/service/ns/query_service.cpp b/src/core/hle/service/ns/query_service.cpp new file mode 100644 index 000000000..946b7fa23 --- /dev/null +++ b/src/core/hle/service/ns/query_service.cpp | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/logging/log.h" | ||
| 5 | #include "common/uuid.h" | ||
| 6 | #include "core/hle/service/cmif_serialization.h" | ||
| 7 | #include "core/hle/service/ns/query_service.h" | ||
| 8 | #include "core/hle/service/service.h" | ||
| 9 | |||
| 10 | namespace Service::NS { | ||
| 11 | |||
| 12 | IQueryService::IQueryService(Core::System& system_) : ServiceFramework{system_, "pdm:qry"} { | ||
| 13 | // clang-format off | ||
| 14 | static const FunctionInfo functions[] = { | ||
| 15 | {0, nullptr, "QueryAppletEvent"}, | ||
| 16 | {1, nullptr, "QueryPlayStatistics"}, | ||
| 17 | {2, nullptr, "QueryPlayStatisticsByUserAccountId"}, | ||
| 18 | {3, nullptr, "QueryPlayStatisticsByNetworkServiceAccountId"}, | ||
| 19 | {4, nullptr, "QueryPlayStatisticsByApplicationId"}, | ||
| 20 | {5, D<&IQueryService::QueryPlayStatisticsByApplicationIdAndUserAccountId>, "QueryPlayStatisticsByApplicationIdAndUserAccountId"}, | ||
| 21 | {6, nullptr, "QueryPlayStatisticsByApplicationIdAndNetworkServiceAccountId"}, | ||
| 22 | {7, nullptr, "QueryLastPlayTimeV0"}, | ||
| 23 | {8, nullptr, "QueryPlayEvent"}, | ||
| 24 | {9, nullptr, "GetAvailablePlayEventRange"}, | ||
| 25 | {10, nullptr, "QueryAccountEvent"}, | ||
| 26 | {11, nullptr, "QueryAccountPlayEvent"}, | ||
| 27 | {12, nullptr, "GetAvailableAccountPlayEventRange"}, | ||
| 28 | {13, nullptr, "QueryApplicationPlayStatisticsForSystemV0"}, | ||
| 29 | {14, nullptr, "QueryRecentlyPlayedApplication"}, | ||
| 30 | {15, nullptr, "GetRecentlyPlayedApplicationUpdateEvent"}, | ||
| 31 | {16, nullptr, "QueryApplicationPlayStatisticsByUserAccountIdForSystemV0"}, | ||
| 32 | {17, nullptr, "QueryLastPlayTime"}, | ||
| 33 | {18, nullptr, "QueryApplicationPlayStatisticsForSystem"}, | ||
| 34 | {19, nullptr, "QueryApplicationPlayStatisticsByUserAccountIdForSystem"}, | ||
| 35 | }; | ||
| 36 | // clang-format on | ||
| 37 | |||
| 38 | RegisterHandlers(functions); | ||
| 39 | } | ||
| 40 | |||
| 41 | IQueryService::~IQueryService() = default; | ||
| 42 | |||
| 43 | Result IQueryService::QueryPlayStatisticsByApplicationIdAndUserAccountId( | ||
| 44 | Out<PlayStatistics> out_play_statistics, bool unknown, Common::UUID account_id, | ||
| 45 | u64 application_id) { | ||
| 46 | // TODO(German77): Read statistics of the game | ||
| 47 | *out_play_statistics = { | ||
| 48 | .application_id = application_id, | ||
| 49 | .total_launches = 1, | ||
| 50 | }; | ||
| 51 | |||
| 52 | LOG_WARNING(Service_NS, "(STUBBED) called. unknown={}. application_id={:016X}, account_id={}", | ||
| 53 | unknown, application_id, account_id.FormattedString()); | ||
| 54 | R_SUCCEED(); | ||
| 55 | } | ||
| 56 | |||
| 57 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/pdm_qry.h b/src/core/hle/service/ns/query_service.h index c98e01660..6cdbfa277 100644 --- a/src/core/hle/service/ns/pdm_qry.h +++ b/src/core/hle/service/ns/query_service.h | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include "common/uuid.h" | ||
| 7 | #include "core/hle/service/cmif_types.h" | ||
| 6 | #include "core/hle/service/service.h" | 8 | #include "core/hle/service/service.h" |
| 7 | 9 | ||
| 8 | namespace Service::NS { | 10 | namespace Service::NS { |
| @@ -20,13 +22,15 @@ struct PlayStatistics { | |||
| 20 | }; | 22 | }; |
| 21 | static_assert(sizeof(PlayStatistics) == 0x28, "PlayStatistics is an invalid size"); | 23 | static_assert(sizeof(PlayStatistics) == 0x28, "PlayStatistics is an invalid size"); |
| 22 | 24 | ||
| 23 | class PDM_QRY final : public ServiceFramework<PDM_QRY> { | 25 | class IQueryService final : public ServiceFramework<IQueryService> { |
| 24 | public: | 26 | public: |
| 25 | explicit PDM_QRY(Core::System& system_); | 27 | explicit IQueryService(Core::System& system_); |
| 26 | ~PDM_QRY() override; | 28 | ~IQueryService() override; |
| 27 | 29 | ||
| 28 | private: | 30 | private: |
| 29 | void QueryPlayStatisticsByApplicationIdAndUserAccountId(HLERequestContext& ctx); | 31 | Result QueryPlayStatisticsByApplicationIdAndUserAccountId( |
| 32 | Out<PlayStatistics> out_play_statistics, bool unknown, Common::UUID account_id, | ||
| 33 | u64 application_id); | ||
| 30 | }; | 34 | }; |
| 31 | 35 | ||
| 32 | } // namespace Service::NS | 36 | } // namespace Service::NS |
diff --git a/src/core/hle/service/ns/read_only_application_control_data_interface.cpp b/src/core/hle/service/ns/read_only_application_control_data_interface.cpp new file mode 100644 index 000000000..9b2ca94a4 --- /dev/null +++ b/src/core/hle/service/ns/read_only_application_control_data_interface.cpp | |||
| @@ -0,0 +1,122 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/settings.h" | ||
| 5 | #include "core/file_sys/control_metadata.h" | ||
| 6 | #include "core/file_sys/patch_manager.h" | ||
| 7 | #include "core/file_sys/vfs/vfs.h" | ||
| 8 | #include "core/hle/service/cmif_serialization.h" | ||
| 9 | #include "core/hle/service/ns/language.h" | ||
| 10 | #include "core/hle/service/ns/ns_results.h" | ||
| 11 | #include "core/hle/service/ns/read_only_application_control_data_interface.h" | ||
| 12 | #include "core/hle/service/set/settings_server.h" | ||
| 13 | |||
| 14 | namespace Service::NS { | ||
| 15 | |||
| 16 | IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface( | ||
| 17 | Core::System& system_) | ||
| 18 | : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} { | ||
| 19 | // clang-format off | ||
| 20 | static const FunctionInfo functions[] = { | ||
| 21 | {0, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlData>, "GetApplicationControlData"}, | ||
| 22 | {1, D<&IReadOnlyApplicationControlDataInterface::GetApplicationDesiredLanguage>, "GetApplicationDesiredLanguage"}, | ||
| 23 | {2, D<&IReadOnlyApplicationControlDataInterface::ConvertApplicationLanguageToLanguageCode>, "ConvertApplicationLanguageToLanguageCode"}, | ||
| 24 | {3, nullptr, "ConvertLanguageCodeToApplicationLanguage"}, | ||
| 25 | {4, nullptr, "SelectApplicationDesiredLanguage"}, | ||
| 26 | }; | ||
| 27 | // clang-format on | ||
| 28 | |||
| 29 | RegisterHandlers(functions); | ||
| 30 | } | ||
| 31 | |||
| 32 | IReadOnlyApplicationControlDataInterface::~IReadOnlyApplicationControlDataInterface() = default; | ||
| 33 | |||
| 34 | Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData( | ||
| 35 | OutBuffer<BufferAttr_HipcMapAlias> out_buffer, Out<u32> out_actual_size, | ||
| 36 | ApplicationControlSource application_control_source, u64 application_id) { | ||
| 37 | LOG_INFO(Service_NS, "called with control_source={}, application_id={:016X}", | ||
| 38 | application_control_source, application_id); | ||
| 39 | |||
| 40 | const FileSys::PatchManager pm{application_id, system.GetFileSystemController(), | ||
| 41 | system.GetContentProvider()}; | ||
| 42 | const auto control = pm.GetControlMetadata(); | ||
| 43 | const auto size = out_buffer.size(); | ||
| 44 | |||
| 45 | const auto icon_size = control.second ? control.second->GetSize() : 0; | ||
| 46 | const auto total_size = sizeof(FileSys::RawNACP) + icon_size; | ||
| 47 | |||
| 48 | if (size < total_size) { | ||
| 49 | LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, expected_min=0x4000)", | ||
| 50 | size); | ||
| 51 | R_THROW(ResultUnknown); | ||
| 52 | } | ||
| 53 | |||
| 54 | if (control.first != nullptr) { | ||
| 55 | const auto bytes = control.first->GetRawBytes(); | ||
| 56 | std::memcpy(out_buffer.data(), bytes.data(), bytes.size()); | ||
| 57 | } else { | ||
| 58 | LOG_WARNING(Service_NS, "missing NACP data for application_id={:016X}, defaulting to zero", | ||
| 59 | application_id); | ||
| 60 | std::memset(out_buffer.data(), 0, sizeof(FileSys::RawNACP)); | ||
| 61 | } | ||
| 62 | |||
| 63 | if (control.second != nullptr) { | ||
| 64 | control.second->Read(out_buffer.data() + sizeof(FileSys::RawNACP), icon_size); | ||
| 65 | } else { | ||
| 66 | LOG_WARNING(Service_NS, "missing icon data for application_id={:016X}", application_id); | ||
| 67 | } | ||
| 68 | |||
| 69 | *out_actual_size = static_cast<u32>(total_size); | ||
| 70 | R_SUCCEED(); | ||
| 71 | } | ||
| 72 | |||
| 73 | Result IReadOnlyApplicationControlDataInterface::GetApplicationDesiredLanguage( | ||
| 74 | Out<ApplicationLanguage> out_desired_language, u32 supported_languages) { | ||
| 75 | LOG_INFO(Service_NS, "called with supported_languages={:08X}", supported_languages); | ||
| 76 | |||
| 77 | // Get language code from settings | ||
| 78 | const auto language_code = | ||
| 79 | Set::GetLanguageCodeFromIndex(static_cast<s32>(Settings::values.language_index.GetValue())); | ||
| 80 | |||
| 81 | // Convert to application language, get priority list | ||
| 82 | const auto application_language = ConvertToApplicationLanguage(language_code); | ||
| 83 | if (application_language == std::nullopt) { | ||
| 84 | LOG_ERROR(Service_NS, "Could not convert application language! language_code={}", | ||
| 85 | language_code); | ||
| 86 | R_THROW(Service::NS::ResultApplicationLanguageNotFound); | ||
| 87 | } | ||
| 88 | const auto priority_list = GetApplicationLanguagePriorityList(*application_language); | ||
| 89 | if (!priority_list) { | ||
| 90 | LOG_ERROR(Service_NS, | ||
| 91 | "Could not find application language priorities! application_language={}", | ||
| 92 | *application_language); | ||
| 93 | R_THROW(Service::NS::ResultApplicationLanguageNotFound); | ||
| 94 | } | ||
| 95 | |||
| 96 | // Try to find a valid language. | ||
| 97 | for (const auto lang : *priority_list) { | ||
| 98 | const auto supported_flag = GetSupportedLanguageFlag(lang); | ||
| 99 | if (supported_languages == 0 || (supported_languages & supported_flag) == supported_flag) { | ||
| 100 | *out_desired_language = lang; | ||
| 101 | R_SUCCEED(); | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | LOG_ERROR(Service_NS, "Could not find a valid language! supported_languages={:08X}", | ||
| 106 | supported_languages); | ||
| 107 | R_THROW(Service::NS::ResultApplicationLanguageNotFound); | ||
| 108 | } | ||
| 109 | |||
| 110 | Result IReadOnlyApplicationControlDataInterface::ConvertApplicationLanguageToLanguageCode( | ||
| 111 | Out<u64> out_language_code, ApplicationLanguage application_language) { | ||
| 112 | const auto language_code = ConvertToLanguageCode(application_language); | ||
| 113 | if (language_code == std::nullopt) { | ||
| 114 | LOG_ERROR(Service_NS, "Language not found! application_language={}", application_language); | ||
| 115 | R_THROW(Service::NS::ResultApplicationLanguageNotFound); | ||
| 116 | } | ||
| 117 | |||
| 118 | *out_language_code = static_cast<u64>(*language_code); | ||
| 119 | R_SUCCEED(); | ||
| 120 | } | ||
| 121 | |||
| 122 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/read_only_application_control_data_interface.h b/src/core/hle/service/ns/read_only_application_control_data_interface.h new file mode 100644 index 000000000..ac099435a --- /dev/null +++ b/src/core/hle/service/ns/read_only_application_control_data_interface.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/cmif_types.h" | ||
| 7 | #include "core/hle/service/ns/language.h" | ||
| 8 | #include "core/hle/service/ns/ns_types.h" | ||
| 9 | #include "core/hle/service/service.h" | ||
| 10 | |||
| 11 | namespace Service::NS { | ||
| 12 | |||
| 13 | class IReadOnlyApplicationControlDataInterface final | ||
| 14 | : public ServiceFramework<IReadOnlyApplicationControlDataInterface> { | ||
| 15 | public: | ||
| 16 | explicit IReadOnlyApplicationControlDataInterface(Core::System& system_); | ||
| 17 | ~IReadOnlyApplicationControlDataInterface() override; | ||
| 18 | |||
| 19 | public: | ||
| 20 | Result GetApplicationControlData(OutBuffer<BufferAttr_HipcMapAlias> out_buffer, | ||
| 21 | Out<u32> out_actual_size, | ||
| 22 | ApplicationControlSource application_control_source, | ||
| 23 | u64 application_id); | ||
| 24 | Result GetApplicationDesiredLanguage(Out<ApplicationLanguage> out_desired_language, | ||
| 25 | u32 supported_languages); | ||
| 26 | Result ConvertApplicationLanguageToLanguageCode(Out<u64> out_language_code, | ||
| 27 | ApplicationLanguage application_language); | ||
| 28 | }; | ||
| 29 | |||
| 30 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/read_only_application_record_interface.cpp b/src/core/hle/service/ns/read_only_application_record_interface.cpp new file mode 100644 index 000000000..816a1e1dc --- /dev/null +++ b/src/core/hle/service/ns/read_only_application_record_interface.cpp | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/cmif_serialization.h" | ||
| 5 | #include "core/hle/service/ns/read_only_application_record_interface.h" | ||
| 6 | |||
| 7 | namespace Service::NS { | ||
| 8 | |||
| 9 | IReadOnlyApplicationRecordInterface::IReadOnlyApplicationRecordInterface(Core::System& system_) | ||
| 10 | : ServiceFramework{system_, "IReadOnlyApplicationRecordInterface"} { | ||
| 11 | static const FunctionInfo functions[] = { | ||
| 12 | {0, D<&IReadOnlyApplicationRecordInterface::HasApplicationRecord>, "HasApplicationRecord"}, | ||
| 13 | {1, nullptr, "NotifyApplicationFailure"}, | ||
| 14 | {2, D<&IReadOnlyApplicationRecordInterface::IsDataCorruptedResult>, | ||
| 15 | "IsDataCorruptedResult"}, | ||
| 16 | }; | ||
| 17 | // clang-format on | ||
| 18 | |||
| 19 | RegisterHandlers(functions); | ||
| 20 | } | ||
| 21 | |||
| 22 | IReadOnlyApplicationRecordInterface::~IReadOnlyApplicationRecordInterface() = default; | ||
| 23 | |||
| 24 | Result IReadOnlyApplicationRecordInterface::HasApplicationRecord( | ||
| 25 | Out<bool> out_has_application_record, u64 program_id) { | ||
| 26 | LOG_WARNING(Service_NS, "(STUBBED) called, program_id={:016X}", program_id); | ||
| 27 | *out_has_application_record = true; | ||
| 28 | R_SUCCEED(); | ||
| 29 | } | ||
| 30 | |||
| 31 | Result IReadOnlyApplicationRecordInterface::IsDataCorruptedResult( | ||
| 32 | Out<bool> out_is_data_corrupted_result, Result result) { | ||
| 33 | LOG_WARNING(Service_NS, "(STUBBED) called, result={:#x}", result.GetInnerValue()); | ||
| 34 | *out_is_data_corrupted_result = false; | ||
| 35 | R_SUCCEED(); | ||
| 36 | } | ||
| 37 | |||
| 38 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/read_only_application_record_interface.h b/src/core/hle/service/ns/read_only_application_record_interface.h new file mode 100644 index 000000000..d06e8f5e6 --- /dev/null +++ b/src/core/hle/service/ns/read_only_application_record_interface.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/cmif_types.h" | ||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service::NS { | ||
| 10 | |||
| 11 | class IReadOnlyApplicationRecordInterface final | ||
| 12 | : public ServiceFramework<IReadOnlyApplicationRecordInterface> { | ||
| 13 | public: | ||
| 14 | explicit IReadOnlyApplicationRecordInterface(Core::System& system_); | ||
| 15 | ~IReadOnlyApplicationRecordInterface() override; | ||
| 16 | |||
| 17 | private: | ||
| 18 | Result HasApplicationRecord(Out<bool> out_has_application_record, u64 program_id); | ||
| 19 | Result IsDataCorruptedResult(Out<bool> out_is_data_corrupted_result, Result result); | ||
| 20 | }; | ||
| 21 | |||
| 22 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/service_getter_interface.cpp b/src/core/hle/service/ns/service_getter_interface.cpp new file mode 100644 index 000000000..1a3dd7166 --- /dev/null +++ b/src/core/hle/service/ns/service_getter_interface.cpp | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/cmif_serialization.h" | ||
| 5 | #include "core/hle/service/ns/account_proxy_interface.h" | ||
| 6 | #include "core/hle/service/ns/application_manager_interface.h" | ||
| 7 | #include "core/hle/service/ns/application_version_interface.h" | ||
| 8 | #include "core/hle/service/ns/content_management_interface.h" | ||
| 9 | #include "core/hle/service/ns/document_interface.h" | ||
| 10 | #include "core/hle/service/ns/download_task_interface.h" | ||
| 11 | #include "core/hle/service/ns/dynamic_rights_interface.h" | ||
| 12 | #include "core/hle/service/ns/ecommerce_interface.h" | ||
| 13 | #include "core/hle/service/ns/factory_reset_interface.h" | ||
| 14 | #include "core/hle/service/ns/read_only_application_control_data_interface.h" | ||
| 15 | #include "core/hle/service/ns/read_only_application_record_interface.h" | ||
| 16 | #include "core/hle/service/ns/service_getter_interface.h" | ||
| 17 | |||
| 18 | namespace Service::NS { | ||
| 19 | |||
| 20 | IServiceGetterInterface::IServiceGetterInterface(Core::System& system_, const char* name) | ||
| 21 | : ServiceFramework{system_, name} { | ||
| 22 | // clang-format off | ||
| 23 | static const FunctionInfo functions[] = { | ||
| 24 | {7988, D<&IServiceGetterInterface::GetDynamicRightsInterface>, "GetDynamicRightsInterface"}, | ||
| 25 | {7989, D<&IServiceGetterInterface::GetReadOnlyApplicationControlDataInterface>, "GetReadOnlyApplicationControlDataInterface"}, | ||
| 26 | {7991, D<&IServiceGetterInterface::GetReadOnlyApplicationRecordInterface>, "GetReadOnlyApplicationRecordInterface"}, | ||
| 27 | {7992, D<&IServiceGetterInterface::GetECommerceInterface>, "GetECommerceInterface"}, | ||
| 28 | {7993, D<&IServiceGetterInterface::GetApplicationVersionInterface>, "GetApplicationVersionInterface"}, | ||
| 29 | {7994, D<&IServiceGetterInterface::GetFactoryResetInterface>, "GetFactoryResetInterface"}, | ||
| 30 | {7995, D<&IServiceGetterInterface::GetAccountProxyInterface>, "GetAccountProxyInterface"}, | ||
| 31 | {7996, D<&IServiceGetterInterface::GetApplicationManagerInterface>, "GetApplicationManagerInterface"}, | ||
| 32 | {7997, D<&IServiceGetterInterface::GetDownloadTaskInterface>, "GetDownloadTaskInterface"}, | ||
| 33 | {7998, D<&IServiceGetterInterface::GetContentManagementInterface>, "GetContentManagementInterface"}, | ||
| 34 | {7999, D<&IServiceGetterInterface::GetDocumentInterface>, "GetDocumentInterface"}, | ||
| 35 | }; | ||
| 36 | // clang-format on | ||
| 37 | |||
| 38 | RegisterHandlers(functions); | ||
| 39 | } | ||
| 40 | |||
| 41 | IServiceGetterInterface::~IServiceGetterInterface() = default; | ||
| 42 | |||
| 43 | Result IServiceGetterInterface::GetDynamicRightsInterface( | ||
| 44 | Out<SharedPointer<IDynamicRightsInterface>> out_interface) { | ||
| 45 | LOG_DEBUG(Service_NS, "called"); | ||
| 46 | *out_interface = std::make_shared<IDynamicRightsInterface>(system); | ||
| 47 | R_SUCCEED(); | ||
| 48 | } | ||
| 49 | |||
| 50 | Result IServiceGetterInterface::GetReadOnlyApplicationControlDataInterface( | ||
| 51 | Out<SharedPointer<IReadOnlyApplicationControlDataInterface>> out_interface) { | ||
| 52 | LOG_DEBUG(Service_NS, "called"); | ||
| 53 | *out_interface = std::make_shared<IReadOnlyApplicationControlDataInterface>(system); | ||
| 54 | R_SUCCEED(); | ||
| 55 | } | ||
| 56 | |||
| 57 | Result IServiceGetterInterface::GetReadOnlyApplicationRecordInterface( | ||
| 58 | Out<SharedPointer<IReadOnlyApplicationRecordInterface>> out_interface) { | ||
| 59 | LOG_DEBUG(Service_NS, "called"); | ||
| 60 | *out_interface = std::make_shared<IReadOnlyApplicationRecordInterface>(system); | ||
| 61 | R_SUCCEED(); | ||
| 62 | } | ||
| 63 | |||
| 64 | Result IServiceGetterInterface::GetECommerceInterface( | ||
| 65 | Out<SharedPointer<IECommerceInterface>> out_interface) { | ||
| 66 | LOG_DEBUG(Service_NS, "called"); | ||
| 67 | *out_interface = std::make_shared<IECommerceInterface>(system); | ||
| 68 | R_SUCCEED(); | ||
| 69 | } | ||
| 70 | |||
| 71 | Result IServiceGetterInterface::GetApplicationVersionInterface( | ||
| 72 | Out<SharedPointer<IApplicationVersionInterface>> out_interface) { | ||
| 73 | LOG_DEBUG(Service_NS, "called"); | ||
| 74 | *out_interface = std::make_shared<IApplicationVersionInterface>(system); | ||
| 75 | R_SUCCEED(); | ||
| 76 | } | ||
| 77 | |||
| 78 | Result IServiceGetterInterface::GetFactoryResetInterface( | ||
| 79 | Out<SharedPointer<IFactoryResetInterface>> out_interface) { | ||
| 80 | LOG_DEBUG(Service_NS, "called"); | ||
| 81 | *out_interface = std::make_shared<IFactoryResetInterface>(system); | ||
| 82 | R_SUCCEED(); | ||
| 83 | } | ||
| 84 | |||
| 85 | Result IServiceGetterInterface::GetAccountProxyInterface( | ||
| 86 | Out<SharedPointer<IAccountProxyInterface>> out_interface) { | ||
| 87 | LOG_DEBUG(Service_NS, "called"); | ||
| 88 | *out_interface = std::make_shared<IAccountProxyInterface>(system); | ||
| 89 | R_SUCCEED(); | ||
| 90 | } | ||
| 91 | |||
| 92 | Result IServiceGetterInterface::GetApplicationManagerInterface( | ||
| 93 | Out<SharedPointer<IApplicationManagerInterface>> out_interface) { | ||
| 94 | LOG_DEBUG(Service_NS, "called"); | ||
| 95 | *out_interface = std::make_shared<IApplicationManagerInterface>(system); | ||
| 96 | R_SUCCEED(); | ||
| 97 | } | ||
| 98 | |||
| 99 | Result IServiceGetterInterface::GetDownloadTaskInterface( | ||
| 100 | Out<SharedPointer<IDownloadTaskInterface>> out_interface) { | ||
| 101 | LOG_DEBUG(Service_NS, "called"); | ||
| 102 | *out_interface = std::make_shared<IDownloadTaskInterface>(system); | ||
| 103 | R_SUCCEED(); | ||
| 104 | } | ||
| 105 | |||
| 106 | Result IServiceGetterInterface::GetContentManagementInterface( | ||
| 107 | Out<SharedPointer<IContentManagementInterface>> out_interface) { | ||
| 108 | LOG_DEBUG(Service_NS, "called"); | ||
| 109 | *out_interface = std::make_shared<IContentManagementInterface>(system); | ||
| 110 | R_SUCCEED(); | ||
| 111 | } | ||
| 112 | |||
| 113 | Result IServiceGetterInterface::GetDocumentInterface( | ||
| 114 | Out<SharedPointer<IDocumentInterface>> out_interface) { | ||
| 115 | LOG_DEBUG(Service_NS, "called"); | ||
| 116 | *out_interface = std::make_shared<IDocumentInterface>(system); | ||
| 117 | R_SUCCEED(); | ||
| 118 | } | ||
| 119 | |||
| 120 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/service_getter_interface.h b/src/core/hle/service/ns/service_getter_interface.h new file mode 100644 index 000000000..bbc18d444 --- /dev/null +++ b/src/core/hle/service/ns/service_getter_interface.h | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/cmif_types.h" | ||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service::NS { | ||
| 10 | |||
| 11 | class IDynamicRightsInterface; | ||
| 12 | class IReadOnlyApplicationControlDataInterface; | ||
| 13 | class IReadOnlyApplicationRecordInterface; | ||
| 14 | class IECommerceInterface; | ||
| 15 | class IApplicationVersionInterface; | ||
| 16 | class IFactoryResetInterface; | ||
| 17 | class IAccountProxyInterface; | ||
| 18 | class IApplicationManagerInterface; | ||
| 19 | class IDownloadTaskInterface; | ||
| 20 | class IContentManagementInterface; | ||
| 21 | class IDocumentInterface; | ||
| 22 | |||
| 23 | class IServiceGetterInterface : public ServiceFramework<IServiceGetterInterface> { | ||
| 24 | public: | ||
| 25 | explicit IServiceGetterInterface(Core::System& system_, const char* name); | ||
| 26 | ~IServiceGetterInterface() override; | ||
| 27 | |||
| 28 | public: | ||
| 29 | Result GetDynamicRightsInterface(Out<SharedPointer<IDynamicRightsInterface>> out_interface); | ||
| 30 | Result GetReadOnlyApplicationControlDataInterface( | ||
| 31 | Out<SharedPointer<IReadOnlyApplicationControlDataInterface>> out_interface); | ||
| 32 | Result GetReadOnlyApplicationRecordInterface( | ||
| 33 | Out<SharedPointer<IReadOnlyApplicationRecordInterface>> out_interface); | ||
| 34 | Result GetECommerceInterface(Out<SharedPointer<IECommerceInterface>> out_interface); | ||
| 35 | Result GetApplicationVersionInterface( | ||
| 36 | Out<SharedPointer<IApplicationVersionInterface>> out_interface); | ||
| 37 | Result GetFactoryResetInterface(Out<SharedPointer<IFactoryResetInterface>> out_interface); | ||
| 38 | Result GetAccountProxyInterface(Out<SharedPointer<IAccountProxyInterface>> out_interface); | ||
| 39 | Result GetApplicationManagerInterface( | ||
| 40 | Out<SharedPointer<IApplicationManagerInterface>> out_interface); | ||
| 41 | Result GetDownloadTaskInterface(Out<SharedPointer<IDownloadTaskInterface>> out_interface); | ||
| 42 | Result GetContentManagementInterface( | ||
| 43 | Out<SharedPointer<IContentManagementInterface>> out_interface); | ||
| 44 | Result GetDocumentInterface(Out<SharedPointer<IDocumentInterface>> out_interface); | ||
| 45 | }; | ||
| 46 | |||
| 47 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/system_update_control.cpp b/src/core/hle/service/ns/system_update_control.cpp new file mode 100644 index 000000000..f5f5cfd90 --- /dev/null +++ b/src/core/hle/service/ns/system_update_control.cpp | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/cmif_serialization.h" | ||
| 5 | #include "core/hle/service/ns/system_update_control.h" | ||
| 6 | |||
| 7 | namespace Service::NS { | ||
| 8 | |||
| 9 | ISystemUpdateControl::ISystemUpdateControl(Core::System& system_) | ||
| 10 | : ServiceFramework{system_, "ISystemUpdateControl"} { | ||
| 11 | // clang-format off | ||
| 12 | static const FunctionInfo functions[] = { | ||
| 13 | {0, nullptr, "HasDownloaded"}, | ||
| 14 | {1, nullptr, "RequestCheckLatestUpdate"}, | ||
| 15 | {2, nullptr, "RequestDownloadLatestUpdate"}, | ||
| 16 | {3, nullptr, "GetDownloadProgress"}, | ||
| 17 | {4, nullptr, "ApplyDownloadedUpdate"}, | ||
| 18 | {5, nullptr, "RequestPrepareCardUpdate"}, | ||
| 19 | {6, nullptr, "GetPrepareCardUpdateProgress"}, | ||
| 20 | {7, nullptr, "HasPreparedCardUpdate"}, | ||
| 21 | {8, nullptr, "ApplyCardUpdate"}, | ||
| 22 | {9, nullptr, "GetDownloadedEulaDataSize"}, | ||
| 23 | {10, nullptr, "GetDownloadedEulaData"}, | ||
| 24 | {11, nullptr, "SetupCardUpdate"}, | ||
| 25 | {12, nullptr, "GetPreparedCardUpdateEulaDataSize"}, | ||
| 26 | {13, nullptr, "GetPreparedCardUpdateEulaData"}, | ||
| 27 | {14, nullptr, "SetupCardUpdateViaSystemUpdater"}, | ||
| 28 | {15, nullptr, "HasReceived"}, | ||
| 29 | {16, nullptr, "RequestReceiveSystemUpdate"}, | ||
| 30 | {17, nullptr, "GetReceiveProgress"}, | ||
| 31 | {18, nullptr, "ApplyReceivedUpdate"}, | ||
| 32 | {19, nullptr, "GetReceivedEulaDataSize"}, | ||
| 33 | {20, nullptr, "GetReceivedEulaData"}, | ||
| 34 | {21, nullptr, "SetupToReceiveSystemUpdate"}, | ||
| 35 | {22, nullptr, "RequestCheckLatestUpdateIncludesRebootlessUpdate"}, | ||
| 36 | }; | ||
| 37 | // clang-format on | ||
| 38 | |||
| 39 | RegisterHandlers(functions); | ||
| 40 | } | ||
| 41 | |||
| 42 | ISystemUpdateControl::~ISystemUpdateControl() = default; | ||
| 43 | |||
| 44 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/system_update_control.h b/src/core/hle/service/ns/system_update_control.h new file mode 100644 index 000000000..a30a09000 --- /dev/null +++ b/src/core/hle/service/ns/system_update_control.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/service.h" | ||
| 7 | |||
| 8 | namespace Service::NS { | ||
| 9 | |||
| 10 | class ISystemUpdateControl final : public ServiceFramework<ISystemUpdateControl> { | ||
| 11 | public: | ||
| 12 | explicit ISystemUpdateControl(Core::System& system_); | ||
| 13 | ~ISystemUpdateControl() override; | ||
| 14 | }; | ||
| 15 | |||
| 16 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/system_update_interface.cpp b/src/core/hle/service/ns/system_update_interface.cpp new file mode 100644 index 000000000..7e22ca3db --- /dev/null +++ b/src/core/hle/service/ns/system_update_interface.cpp | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/cmif_serialization.h" | ||
| 5 | #include "core/hle/service/ns/system_update_control.h" | ||
| 6 | #include "core/hle/service/ns/system_update_interface.h" | ||
| 7 | |||
| 8 | namespace Service::NS { | ||
| 9 | |||
| 10 | ISystemUpdateInterface::ISystemUpdateInterface(Core::System& system_) | ||
| 11 | : ServiceFramework{system_, "ns:su"}, service_context{system_, "ns:su"}, | ||
| 12 | update_notification_event{service_context} { | ||
| 13 | // clang-format off | ||
| 14 | static const FunctionInfo functions[] = { | ||
| 15 | {0, D<&ISystemUpdateInterface::GetBackgroundNetworkUpdateState>, "GetBackgroundNetworkUpdateState"}, | ||
| 16 | {1, D<&ISystemUpdateInterface::OpenSystemUpdateControl>, "OpenSystemUpdateControl"}, | ||
| 17 | {2, nullptr, "NotifyExFatDriverRequired"}, | ||
| 18 | {3, nullptr, "ClearExFatDriverStatusForDebug"}, | ||
| 19 | {4, nullptr, "RequestBackgroundNetworkUpdate"}, | ||
| 20 | {5, nullptr, "NotifyBackgroundNetworkUpdate"}, | ||
| 21 | {6, nullptr, "NotifyExFatDriverDownloadedForDebug"}, | ||
| 22 | {9, D<&ISystemUpdateInterface::GetSystemUpdateNotificationEventForContentDelivery>, "GetSystemUpdateNotificationEventForContentDelivery"}, | ||
| 23 | {10, nullptr, "NotifySystemUpdateForContentDelivery"}, | ||
| 24 | {11, nullptr, "PrepareShutdown"}, | ||
| 25 | {12, nullptr, "Unknown12"}, | ||
| 26 | {13, nullptr, "Unknown13"}, | ||
| 27 | {14, nullptr, "Unknown14"}, | ||
| 28 | {15, nullptr, "Unknown15"}, | ||
| 29 | {16, nullptr, "DestroySystemUpdateTask"}, | ||
| 30 | {17, nullptr, "RequestSendSystemUpdate"}, | ||
| 31 | {18, nullptr, "GetSendSystemUpdateProgress"}, | ||
| 32 | }; | ||
| 33 | // clang-format on | ||
| 34 | |||
| 35 | RegisterHandlers(functions); | ||
| 36 | } | ||
| 37 | |||
| 38 | ISystemUpdateInterface::~ISystemUpdateInterface() = default; | ||
| 39 | |||
| 40 | Result ISystemUpdateInterface::GetBackgroundNetworkUpdateState( | ||
| 41 | Out<BackgroundNetworkUpdateState> out_background_network_update_state) { | ||
| 42 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 43 | *out_background_network_update_state = BackgroundNetworkUpdateState::None; | ||
| 44 | R_SUCCEED(); | ||
| 45 | } | ||
| 46 | |||
| 47 | Result ISystemUpdateInterface::OpenSystemUpdateControl( | ||
| 48 | Out<SharedPointer<ISystemUpdateControl>> out_system_update_control) { | ||
| 49 | LOG_WARNING(Service_NS, "(STUBBED) called"); | ||
| 50 | *out_system_update_control = std::make_shared<ISystemUpdateControl>(system); | ||
| 51 | R_SUCCEED(); | ||
| 52 | } | ||
| 53 | |||
| 54 | Result ISystemUpdateInterface::GetSystemUpdateNotificationEventForContentDelivery( | ||
| 55 | OutCopyHandle<Kernel::KReadableEvent> out_event) { | ||
| 56 | LOG_WARNING(Service_NS, "(STUBBED) called"); | ||
| 57 | *out_event = update_notification_event.GetHandle(); | ||
| 58 | R_SUCCEED(); | ||
| 59 | } | ||
| 60 | |||
| 61 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/system_update_interface.h b/src/core/hle/service/ns/system_update_interface.h new file mode 100644 index 000000000..36a2880ec --- /dev/null +++ b/src/core/hle/service/ns/system_update_interface.h | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/cmif_types.h" | ||
| 7 | #include "core/hle/service/kernel_helpers.h" | ||
| 8 | #include "core/hle/service/ns/ns_types.h" | ||
| 9 | #include "core/hle/service/os/event.h" | ||
| 10 | #include "core/hle/service/service.h" | ||
| 11 | |||
| 12 | namespace Kernel { | ||
| 13 | class KReadableEvent; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service::NS { | ||
| 17 | |||
| 18 | class ISystemUpdateControl; | ||
| 19 | |||
| 20 | class ISystemUpdateInterface final : public ServiceFramework<ISystemUpdateInterface> { | ||
| 21 | public: | ||
| 22 | explicit ISystemUpdateInterface(Core::System& system_); | ||
| 23 | ~ISystemUpdateInterface() override; | ||
| 24 | |||
| 25 | private: | ||
| 26 | Result GetBackgroundNetworkUpdateState( | ||
| 27 | Out<BackgroundNetworkUpdateState> out_background_network_update_state); | ||
| 28 | Result OpenSystemUpdateControl( | ||
| 29 | Out<SharedPointer<ISystemUpdateControl>> out_system_update_control); | ||
| 30 | Result GetSystemUpdateNotificationEventForContentDelivery( | ||
| 31 | OutCopyHandle<Kernel::KReadableEvent> out_event); | ||
| 32 | |||
| 33 | private: | ||
| 34 | KernelHelpers::ServiceContext service_context; | ||
| 35 | Event update_notification_event; | ||
| 36 | }; | ||
| 37 | |||
| 38 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/vulnerability_manager_interface.cpp b/src/core/hle/service/ns/vulnerability_manager_interface.cpp new file mode 100644 index 000000000..69c21fb89 --- /dev/null +++ b/src/core/hle/service/ns/vulnerability_manager_interface.cpp | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/cmif_serialization.h" | ||
| 5 | #include "core/hle/service/ns/vulnerability_manager_interface.h" | ||
| 6 | |||
| 7 | namespace Service::NS { | ||
| 8 | |||
| 9 | IVulnerabilityManagerInterface::IVulnerabilityManagerInterface(Core::System& system_) | ||
| 10 | : ServiceFramework{system_, "ns:vm"} { | ||
| 11 | // clang-format off | ||
| 12 | static const FunctionInfo functions[] = { | ||
| 13 | {1200, D<&IVulnerabilityManagerInterface::NeedsUpdateVulnerability>, "NeedsUpdateVulnerability"}, | ||
| 14 | {1201, nullptr, "UpdateSafeSystemVersionForDebug"}, | ||
| 15 | {1202, nullptr, "GetSafeSystemVersion"}, | ||
| 16 | }; | ||
| 17 | // clang-format on | ||
| 18 | |||
| 19 | RegisterHandlers(functions); | ||
| 20 | } | ||
| 21 | |||
| 22 | IVulnerabilityManagerInterface::~IVulnerabilityManagerInterface() = default; | ||
| 23 | |||
| 24 | Result IVulnerabilityManagerInterface::NeedsUpdateVulnerability( | ||
| 25 | Out<bool> out_needs_update_vulnerability) { | ||
| 26 | LOG_WARNING(Service_NS, "(STUBBED) called"); | ||
| 27 | *out_needs_update_vulnerability = false; | ||
| 28 | R_SUCCEED(); | ||
| 29 | } | ||
| 30 | |||
| 31 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/vulnerability_manager_interface.h b/src/core/hle/service/ns/vulnerability_manager_interface.h new file mode 100644 index 000000000..c689cf7ec --- /dev/null +++ b/src/core/hle/service/ns/vulnerability_manager_interface.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/cmif_types.h" | ||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service::NS { | ||
| 10 | |||
| 11 | class IVulnerabilityManagerInterface final | ||
| 12 | : public ServiceFramework<IVulnerabilityManagerInterface> { | ||
| 13 | public: | ||
| 14 | explicit IVulnerabilityManagerInterface(Core::System& system_); | ||
| 15 | ~IVulnerabilityManagerInterface() override; | ||
| 16 | |||
| 17 | private: | ||
| 18 | Result NeedsUpdateVulnerability(Out<bool> out_needs_update_vulnerability); | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 250d01de3..0265d55f2 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | |||
| @@ -92,11 +92,11 @@ NvResult nvhost_ctrl::IocCtrlEventWait(IocCtrlEventWaitParams& params, bool is_a | |||
| 92 | 92 | ||
| 93 | bool must_unmark_fail = !is_allocation; | 93 | bool must_unmark_fail = !is_allocation; |
| 94 | const u32 event_id = params.value.raw; | 94 | const u32 event_id = params.value.raw; |
| 95 | SCOPE_EXIT({ | 95 | SCOPE_EXIT { |
| 96 | if (must_unmark_fail) { | 96 | if (must_unmark_fail) { |
| 97 | events[event_id].fails = 0; | 97 | events[event_id].fails = 0; |
| 98 | } | 98 | } |
| 99 | }); | 99 | }; |
| 100 | 100 | ||
| 101 | const u32 fence_id = static_cast<u32>(params.fence.id); | 101 | const u32 fence_id = static_cast<u32>(params.fence.id); |
| 102 | 102 | ||
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index cb256e5b4..03eb507b9 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp | |||
| @@ -42,7 +42,7 @@ void EventInterface::FreeEvent(Kernel::KEvent* event) { | |||
| 42 | module.service_context.CloseEvent(event); | 42 | module.service_context.CloseEvent(event); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { | 45 | void LoopProcess(Core::System& system) { |
| 46 | auto server_manager = std::make_unique<ServerManager>(system); | 46 | auto server_manager = std::make_unique<ServerManager>(system); |
| 47 | auto module = std::make_shared<Module>(system); | 47 | auto module = std::make_shared<Module>(system); |
| 48 | const auto NvdrvInterfaceFactoryForApplication = [&, module] { | 48 | const auto NvdrvInterfaceFactoryForApplication = [&, module] { |
| @@ -62,7 +62,6 @@ void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { | |||
| 62 | server_manager->RegisterNamedService("nvdrv:s", NvdrvInterfaceFactoryForSysmodules); | 62 | server_manager->RegisterNamedService("nvdrv:s", NvdrvInterfaceFactoryForSysmodules); |
| 63 | server_manager->RegisterNamedService("nvdrv:t", NvdrvInterfaceFactoryForTesting); | 63 | server_manager->RegisterNamedService("nvdrv:t", NvdrvInterfaceFactoryForTesting); |
| 64 | server_manager->RegisterNamedService("nvmemp", std::make_shared<NVMEMP>(system)); | 64 | server_manager->RegisterNamedService("nvmemp", std::make_shared<NVMEMP>(system)); |
| 65 | nvnflinger.SetNVDrvInstance(module); | ||
| 66 | ServerManager::RunServer(std::move(server_manager)); | 65 | ServerManager::RunServer(std::move(server_manager)); |
| 67 | } | 66 | } |
| 68 | 67 | ||
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index c594f0e5e..b76f81e59 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h | |||
| @@ -10,13 +10,11 @@ | |||
| 10 | #include <span> | 10 | #include <span> |
| 11 | #include <string> | 11 | #include <string> |
| 12 | #include <unordered_map> | 12 | #include <unordered_map> |
| 13 | #include <vector> | ||
| 14 | 13 | ||
| 15 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| 16 | #include "core/hle/service/kernel_helpers.h" | 15 | #include "core/hle/service/kernel_helpers.h" |
| 17 | #include "core/hle/service/nvdrv/core/container.h" | 16 | #include "core/hle/service/nvdrv/core/container.h" |
| 18 | #include "core/hle/service/nvdrv/nvdata.h" | 17 | #include "core/hle/service/nvdrv/nvdata.h" |
| 19 | #include "core/hle/service/nvnflinger/ui/fence.h" | ||
| 20 | #include "core/hle/service/service.h" | 18 | #include "core/hle/service/service.h" |
| 21 | 19 | ||
| 22 | namespace Core { | 20 | namespace Core { |
| @@ -27,10 +25,6 @@ namespace Kernel { | |||
| 27 | class KEvent; | 25 | class KEvent; |
| 28 | } | 26 | } |
| 29 | 27 | ||
| 30 | namespace Service::Nvnflinger { | ||
| 31 | class Nvnflinger; | ||
| 32 | } | ||
| 33 | |||
| 34 | namespace Service::Nvidia { | 28 | namespace Service::Nvidia { |
| 35 | 29 | ||
| 36 | namespace NvCore { | 30 | namespace NvCore { |
| @@ -99,7 +93,6 @@ public: | |||
| 99 | 93 | ||
| 100 | private: | 94 | private: |
| 101 | friend class EventInterface; | 95 | friend class EventInterface; |
| 102 | friend class Service::Nvnflinger::Nvnflinger; | ||
| 103 | 96 | ||
| 104 | /// Manages syncpoints on the host | 97 | /// Manages syncpoints on the host |
| 105 | NvCore::Container container; | 98 | NvCore::Container container; |
| @@ -118,6 +111,6 @@ private: | |||
| 118 | std::unordered_map<std::string, std::function<FilesContainerType::iterator(DeviceFD)>> builders; | 111 | std::unordered_map<std::string, std::function<FilesContainerType::iterator(DeviceFD)>> builders; |
| 119 | }; | 112 | }; |
| 120 | 113 | ||
| 121 | void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system); | 114 | void LoopProcess(Core::System& system); |
| 122 | 115 | ||
| 123 | } // namespace Service::Nvidia | 116 | } // namespace Service::Nvidia |
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp index ffe72f281..258970fd5 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp | |||
| @@ -154,10 +154,10 @@ void NVDRV::Close(HLERequestContext& ctx) { | |||
| 154 | void NVDRV::Initialize(HLERequestContext& ctx) { | 154 | void NVDRV::Initialize(HLERequestContext& ctx) { |
| 155 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 155 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 156 | IPC::ResponseBuilder rb{ctx, 3}; | 156 | IPC::ResponseBuilder rb{ctx, 3}; |
| 157 | SCOPE_EXIT({ | 157 | SCOPE_EXIT { |
| 158 | rb.Push(ResultSuccess); | 158 | rb.Push(ResultSuccess); |
| 159 | rb.PushEnum(NvResult::Success); | 159 | rb.PushEnum(NvResult::Success); |
| 160 | }); | 160 | }; |
| 161 | 161 | ||
| 162 | if (is_initialized) { | 162 | if (is_initialized) { |
| 163 | // No need to initialize again | 163 | // No need to initialize again |
| @@ -263,8 +263,10 @@ NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* | |||
| 263 | } | 263 | } |
| 264 | 264 | ||
| 265 | NVDRV::~NVDRV() { | 265 | NVDRV::~NVDRV() { |
| 266 | auto& container = nvdrv->GetContainer(); | 266 | if (is_initialized) { |
| 267 | container.CloseSession(session_id); | 267 | auto& container = nvdrv->GetContainer(); |
| 268 | container.CloseSession(session_id); | ||
| 269 | } | ||
| 268 | } | 270 | } |
| 269 | 271 | ||
| 270 | } // namespace Service::Nvidia | 272 | } // namespace Service::Nvidia |
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.h b/src/core/hle/service/nvdrv/nvdrv_interface.h index f2195ae1e..c72f92597 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.h +++ b/src/core/hle/service/nvdrv/nvdrv_interface.h | |||
| @@ -16,6 +16,10 @@ public: | |||
| 16 | explicit NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name); | 16 | explicit NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name); |
| 17 | ~NVDRV() override; | 17 | ~NVDRV() override; |
| 18 | 18 | ||
| 19 | std::shared_ptr<Module> GetModule() const { | ||
| 20 | return nvdrv; | ||
| 21 | } | ||
| 22 | |||
| 19 | private: | 23 | private: |
| 20 | void Open(HLERequestContext& ctx); | 24 | void Open(HLERequestContext& ctx); |
| 21 | void Ioctl1(HLERequestContext& ctx); | 25 | void Ioctl1(HLERequestContext& ctx); |
diff --git a/src/core/hle/service/nvnflinger/binder.h b/src/core/hle/service/nvnflinger/binder.h index 179938192..124accb94 100644 --- a/src/core/hle/service/nvnflinger/binder.h +++ b/src/core/hle/service/nvnflinger/binder.h | |||
| @@ -20,29 +20,12 @@ class HLERequestContext; | |||
| 20 | 20 | ||
| 21 | namespace Service::android { | 21 | namespace Service::android { |
| 22 | 22 | ||
| 23 | enum class TransactionId { | ||
| 24 | RequestBuffer = 1, | ||
| 25 | SetBufferCount = 2, | ||
| 26 | DequeueBuffer = 3, | ||
| 27 | DetachBuffer = 4, | ||
| 28 | DetachNextBuffer = 5, | ||
| 29 | AttachBuffer = 6, | ||
| 30 | QueueBuffer = 7, | ||
| 31 | CancelBuffer = 8, | ||
| 32 | Query = 9, | ||
| 33 | Connect = 10, | ||
| 34 | Disconnect = 11, | ||
| 35 | AllocateBuffers = 13, | ||
| 36 | SetPreallocatedBuffer = 14, | ||
| 37 | GetBufferHistory = 17, | ||
| 38 | }; | ||
| 39 | |||
| 40 | class IBinder { | 23 | class IBinder { |
| 41 | public: | 24 | public: |
| 42 | virtual ~IBinder() = default; | 25 | virtual ~IBinder() = default; |
| 43 | virtual void Transact(android::TransactionId code, u32 flags, std::span<const u8> parcel_data, | 26 | virtual void Transact(u32 code, std::span<const u8> parcel_data, std::span<u8> parcel_reply, |
| 44 | std::span<u8> parcel_reply) = 0; | 27 | u32 flags) = 0; |
| 45 | virtual Kernel::KReadableEvent& GetNativeHandle() = 0; | 28 | virtual Kernel::KReadableEvent* GetNativeHandle(u32 type_id) = 0; |
| 46 | }; | 29 | }; |
| 47 | 30 | ||
| 48 | } // namespace Service::android | 31 | } // namespace Service::android |
diff --git a/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp b/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp index cf151ea3a..123507123 100644 --- a/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp +++ b/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | 12 | ||
| 13 | namespace Service::android { | 13 | namespace Service::android { |
| 14 | 14 | ||
| 15 | BufferItemConsumer::BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer_) | 15 | BufferItemConsumer::BufferItemConsumer(std::shared_ptr<BufferQueueConsumer> consumer_) |
| 16 | : ConsumerBase{std::move(consumer_)} {} | 16 | : ConsumerBase{std::move(consumer_)} {} |
| 17 | 17 | ||
| 18 | Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when, | 18 | Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when, |
diff --git a/src/core/hle/service/nvnflinger/buffer_item_consumer.h b/src/core/hle/service/nvnflinger/buffer_item_consumer.h index e0c6b3604..9f95c9280 100644 --- a/src/core/hle/service/nvnflinger/buffer_item_consumer.h +++ b/src/core/hle/service/nvnflinger/buffer_item_consumer.h | |||
| @@ -19,7 +19,7 @@ class BufferItem; | |||
| 19 | 19 | ||
| 20 | class BufferItemConsumer final : public ConsumerBase { | 20 | class BufferItemConsumer final : public ConsumerBase { |
| 21 | public: | 21 | public: |
| 22 | explicit BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer); | 22 | explicit BufferItemConsumer(std::shared_ptr<BufferQueueConsumer> consumer); |
| 23 | Status AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when, | 23 | Status AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when, |
| 24 | bool wait_for_fence = true); | 24 | bool wait_for_fence = true); |
| 25 | Status ReleaseBuffer(const BufferItem& item, const Fence& release_fence); | 25 | Status ReleaseBuffer(const BufferItem& item, const Fence& release_fence); |
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp index bbe8e06d4..3bc23aa97 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp +++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp | |||
| @@ -4,12 +4,13 @@ | |||
| 4 | // Parts of this implementation were based on: | 4 | // Parts of this implementation were based on: |
| 5 | // https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp | 5 | // https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp |
| 6 | 6 | ||
| 7 | #include "common/assert.h" | ||
| 7 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 8 | #include "core/hle/service/nvnflinger/buffer_item.h" | 9 | #include "core/hle/service/nvnflinger/buffer_item.h" |
| 9 | #include "core/hle/service/nvnflinger/buffer_queue_consumer.h" | 10 | #include "core/hle/service/nvnflinger/buffer_queue_consumer.h" |
| 10 | #include "core/hle/service/nvnflinger/buffer_queue_core.h" | 11 | #include "core/hle/service/nvnflinger/buffer_queue_core.h" |
| 12 | #include "core/hle/service/nvnflinger/parcel.h" | ||
| 11 | #include "core/hle/service/nvnflinger/producer_listener.h" | 13 | #include "core/hle/service/nvnflinger/producer_listener.h" |
| 12 | #include "core/hle/service/nvnflinger/ui/graphic_buffer.h" | ||
| 13 | 14 | ||
| 14 | namespace Service::android { | 15 | namespace Service::android { |
| 15 | 16 | ||
| @@ -254,4 +255,77 @@ Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) { | |||
| 254 | return Status::NoError; | 255 | return Status::NoError; |
| 255 | } | 256 | } |
| 256 | 257 | ||
| 258 | void BufferQueueConsumer::Transact(u32 code, std::span<const u8> parcel_data, | ||
| 259 | std::span<u8> parcel_reply, u32 flags) { | ||
| 260 | // Values used by BnGraphicBufferConsumer onTransact | ||
| 261 | enum class TransactionId { | ||
| 262 | AcquireBuffer = 1, | ||
| 263 | DetachBuffer = 2, | ||
| 264 | AttachBuffer = 3, | ||
| 265 | ReleaseBuffer = 4, | ||
| 266 | ConsumerConnect = 5, | ||
| 267 | ConsumerDisconnect = 6, | ||
| 268 | GetReleasedBuffers = 7, | ||
| 269 | SetDefaultBufferSize = 8, | ||
| 270 | SetDefaultMaxBufferCount = 9, | ||
| 271 | DisableAsyncBuffer = 10, | ||
| 272 | SetMaxAcquiredBufferCount = 11, | ||
| 273 | SetConsumerName = 12, | ||
| 274 | SetDefaultBufferFormat = 13, | ||
| 275 | SetConsumerUsageBits = 14, | ||
| 276 | SetTransformHint = 15, | ||
| 277 | GetSidebandStream = 16, | ||
| 278 | Unknown18 = 18, | ||
| 279 | Unknown20 = 20, | ||
| 280 | }; | ||
| 281 | |||
| 282 | Status status{Status::NoError}; | ||
| 283 | InputParcel parcel_in{parcel_data}; | ||
| 284 | OutputParcel parcel_out{}; | ||
| 285 | |||
| 286 | switch (static_cast<TransactionId>(code)) { | ||
| 287 | case TransactionId::AcquireBuffer: { | ||
| 288 | BufferItem item; | ||
| 289 | const s64 present_when = parcel_in.Read<s64>(); | ||
| 290 | |||
| 291 | status = AcquireBuffer(&item, std::chrono::nanoseconds{present_when}); | ||
| 292 | |||
| 293 | // TODO: can't write this directly, needs a flattener for the sp<GraphicBuffer> | ||
| 294 | // parcel_out.WriteFlattened(item); | ||
| 295 | UNREACHABLE(); | ||
| 296 | } | ||
| 297 | case TransactionId::ReleaseBuffer: { | ||
| 298 | const s32 slot = parcel_in.Read<s32>(); | ||
| 299 | const u64 frame_number = parcel_in.Read<u64>(); | ||
| 300 | const auto release_fence = parcel_in.ReadFlattened<Fence>(); | ||
| 301 | |||
| 302 | status = ReleaseBuffer(slot, frame_number, release_fence); | ||
| 303 | |||
| 304 | break; | ||
| 305 | } | ||
| 306 | case TransactionId::GetReleasedBuffers: { | ||
| 307 | u64 slot_mask = 0; | ||
| 308 | |||
| 309 | status = GetReleasedBuffers(&slot_mask); | ||
| 310 | |||
| 311 | parcel_out.Write(slot_mask); | ||
| 312 | break; | ||
| 313 | } | ||
| 314 | default: | ||
| 315 | ASSERT_MSG(false, "called, code={} flags={}", code, flags); | ||
| 316 | break; | ||
| 317 | } | ||
| 318 | |||
| 319 | parcel_out.Write(status); | ||
| 320 | |||
| 321 | const auto serialized = parcel_out.Serialize(); | ||
| 322 | std::memcpy(parcel_reply.data(), serialized.data(), | ||
| 323 | std::min(parcel_reply.size(), serialized.size())); | ||
| 324 | } | ||
| 325 | |||
| 326 | Kernel::KReadableEvent* BufferQueueConsumer::GetNativeHandle(u32 type_id) { | ||
| 327 | ASSERT_MSG(false, "called, type_id={}", type_id); | ||
| 328 | return nullptr; | ||
| 329 | } | ||
| 330 | |||
| 257 | } // namespace Service::android | 331 | } // namespace Service::android |
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_consumer.h b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h index 0a61e8dbd..a9226f1c3 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.h +++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <memory> | 10 | #include <memory> |
| 11 | 11 | ||
| 12 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | #include "core/hle/service/nvnflinger/binder.h" | ||
| 13 | #include "core/hle/service/nvnflinger/buffer_queue_defs.h" | 14 | #include "core/hle/service/nvnflinger/buffer_queue_defs.h" |
| 14 | #include "core/hle/service/nvnflinger/status.h" | 15 | #include "core/hle/service/nvnflinger/status.h" |
| 15 | 16 | ||
| @@ -19,10 +20,10 @@ class BufferItem; | |||
| 19 | class BufferQueueCore; | 20 | class BufferQueueCore; |
| 20 | class IConsumerListener; | 21 | class IConsumerListener; |
| 21 | 22 | ||
| 22 | class BufferQueueConsumer final { | 23 | class BufferQueueConsumer final : public IBinder { |
| 23 | public: | 24 | public: |
| 24 | explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_); | 25 | explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_); |
| 25 | ~BufferQueueConsumer(); | 26 | ~BufferQueueConsumer() override; |
| 26 | 27 | ||
| 27 | Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present); | 28 | Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present); |
| 28 | Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence); | 29 | Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence); |
| @@ -30,6 +31,11 @@ public: | |||
| 30 | Status Disconnect(); | 31 | Status Disconnect(); |
| 31 | Status GetReleasedBuffers(u64* out_slot_mask); | 32 | Status GetReleasedBuffers(u64* out_slot_mask); |
| 32 | 33 | ||
| 34 | void Transact(u32 code, std::span<const u8> parcel_data, std::span<u8> parcel_reply, | ||
| 35 | u32 flags) override; | ||
| 36 | |||
| 37 | Kernel::KReadableEvent* GetNativeHandle(u32 type_id) override; | ||
| 38 | |||
| 33 | private: | 39 | private: |
| 34 | std::shared_ptr<BufferQueueCore> core; | 40 | std::shared_ptr<BufferQueueCore> core; |
| 35 | BufferQueueDefs::SlotsType& slots; | 41 | BufferQueueDefs::SlotsType& slots; |
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp index ec83beb9b..9e5091eeb 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp | |||
| @@ -6,12 +6,9 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "common/settings.h" | ||
| 10 | #include "core/core.h" | ||
| 11 | #include "core/hle/kernel/k_event.h" | 9 | #include "core/hle/kernel/k_event.h" |
| 12 | #include "core/hle/kernel/k_readable_event.h" | 10 | #include "core/hle/kernel/k_readable_event.h" |
| 13 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| 14 | #include "core/hle/service/hle_ipc.h" | ||
| 15 | #include "core/hle/service/kernel_helpers.h" | 12 | #include "core/hle/service/kernel_helpers.h" |
| 16 | #include "core/hle/service/nvnflinger/buffer_queue_core.h" | 13 | #include "core/hle/service/nvnflinger/buffer_queue_core.h" |
| 17 | #include "core/hle/service/nvnflinger/buffer_queue_producer.h" | 14 | #include "core/hle/service/nvnflinger/buffer_queue_producer.h" |
| @@ -19,7 +16,6 @@ | |||
| 19 | #include "core/hle/service/nvnflinger/parcel.h" | 16 | #include "core/hle/service/nvnflinger/parcel.h" |
| 20 | #include "core/hle/service/nvnflinger/ui/graphic_buffer.h" | 17 | #include "core/hle/service/nvnflinger/ui/graphic_buffer.h" |
| 21 | #include "core/hle/service/nvnflinger/window.h" | 18 | #include "core/hle/service/nvnflinger/window.h" |
| 22 | #include "core/hle/service/vi/vi.h" | ||
| 23 | 19 | ||
| 24 | namespace Service::android { | 20 | namespace Service::android { |
| 25 | 21 | ||
| @@ -807,13 +803,31 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot, | |||
| 807 | return Status::NoError; | 803 | return Status::NoError; |
| 808 | } | 804 | } |
| 809 | 805 | ||
| 810 | void BufferQueueProducer::Transact(TransactionId code, u32 flags, std::span<const u8> parcel_data, | 806 | void BufferQueueProducer::Transact(u32 code, std::span<const u8> parcel_data, |
| 811 | std::span<u8> parcel_reply) { | 807 | std::span<u8> parcel_reply, u32 flags) { |
| 808 | // Values used by BnGraphicBufferProducer onTransact | ||
| 809 | enum class TransactionId { | ||
| 810 | RequestBuffer = 1, | ||
| 811 | SetBufferCount = 2, | ||
| 812 | DequeueBuffer = 3, | ||
| 813 | DetachBuffer = 4, | ||
| 814 | DetachNextBuffer = 5, | ||
| 815 | AttachBuffer = 6, | ||
| 816 | QueueBuffer = 7, | ||
| 817 | CancelBuffer = 8, | ||
| 818 | Query = 9, | ||
| 819 | Connect = 10, | ||
| 820 | Disconnect = 11, | ||
| 821 | AllocateBuffers = 13, | ||
| 822 | SetPreallocatedBuffer = 14, | ||
| 823 | GetBufferHistory = 17, | ||
| 824 | }; | ||
| 825 | |||
| 812 | Status status{Status::NoError}; | 826 | Status status{Status::NoError}; |
| 813 | InputParcel parcel_in{parcel_data}; | 827 | InputParcel parcel_in{parcel_data}; |
| 814 | OutputParcel parcel_out{}; | 828 | OutputParcel parcel_out{}; |
| 815 | 829 | ||
| 816 | switch (code) { | 830 | switch (static_cast<TransactionId>(code)) { |
| 817 | case TransactionId::Connect: { | 831 | case TransactionId::Connect: { |
| 818 | const auto enable_listener = parcel_in.Read<bool>(); | 832 | const auto enable_listener = parcel_in.Read<bool>(); |
| 819 | const auto api = parcel_in.Read<NativeWindowApi>(); | 833 | const auto api = parcel_in.Read<NativeWindowApi>(); |
| @@ -923,8 +937,8 @@ void BufferQueueProducer::Transact(TransactionId code, u32 flags, std::span<cons | |||
| 923 | std::min(parcel_reply.size(), serialized.size())); | 937 | std::min(parcel_reply.size(), serialized.size())); |
| 924 | } | 938 | } |
| 925 | 939 | ||
| 926 | Kernel::KReadableEvent& BufferQueueProducer::GetNativeHandle() { | 940 | Kernel::KReadableEvent* BufferQueueProducer::GetNativeHandle(u32 type_id) { |
| 927 | return buffer_wait_event->GetReadableEvent(); | 941 | return &buffer_wait_event->GetReadableEvent(); |
| 928 | } | 942 | } |
| 929 | 943 | ||
| 930 | } // namespace Service::android | 944 | } // namespace Service::android |
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.h b/src/core/hle/service/nvnflinger/buffer_queue_producer.h index 4682b0f84..048523514 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_producer.h +++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.h | |||
| @@ -45,12 +45,12 @@ public: | |||
| 45 | explicit BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_, | 45 | explicit BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_, |
| 46 | std::shared_ptr<BufferQueueCore> buffer_queue_core_, | 46 | std::shared_ptr<BufferQueueCore> buffer_queue_core_, |
| 47 | Service::Nvidia::NvCore::NvMap& nvmap_); | 47 | Service::Nvidia::NvCore::NvMap& nvmap_); |
| 48 | ~BufferQueueProducer(); | 48 | ~BufferQueueProducer() override; |
| 49 | 49 | ||
| 50 | void Transact(android::TransactionId code, u32 flags, std::span<const u8> parcel_data, | 50 | void Transact(u32 code, std::span<const u8> parcel_data, std::span<u8> parcel_reply, |
| 51 | std::span<u8> parcel_reply) override; | 51 | u32 flags) override; |
| 52 | 52 | ||
| 53 | Kernel::KReadableEvent& GetNativeHandle() override; | 53 | Kernel::KReadableEvent* GetNativeHandle(u32 type_id) override; |
| 54 | 54 | ||
| 55 | public: | 55 | public: |
| 56 | Status RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf); | 56 | Status RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf); |
diff --git a/src/core/hle/service/nvnflinger/consumer_base.cpp b/src/core/hle/service/nvnflinger/consumer_base.cpp index 1059e72bf..e360ebfd8 100644 --- a/src/core/hle/service/nvnflinger/consumer_base.cpp +++ b/src/core/hle/service/nvnflinger/consumer_base.cpp | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | 14 | ||
| 15 | namespace Service::android { | 15 | namespace Service::android { |
| 16 | 16 | ||
| 17 | ConsumerBase::ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_) | 17 | ConsumerBase::ConsumerBase(std::shared_ptr<BufferQueueConsumer> consumer_) |
| 18 | : consumer{std::move(consumer_)} {} | 18 | : consumer{std::move(consumer_)} {} |
| 19 | 19 | ||
| 20 | ConsumerBase::~ConsumerBase() { | 20 | ConsumerBase::~ConsumerBase() { |
diff --git a/src/core/hle/service/nvnflinger/consumer_base.h b/src/core/hle/service/nvnflinger/consumer_base.h index ea3e9e97a..b29c16f86 100644 --- a/src/core/hle/service/nvnflinger/consumer_base.h +++ b/src/core/hle/service/nvnflinger/consumer_base.h | |||
| @@ -27,7 +27,7 @@ public: | |||
| 27 | void Abandon(); | 27 | void Abandon(); |
| 28 | 28 | ||
| 29 | protected: | 29 | protected: |
| 30 | explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_); | 30 | explicit ConsumerBase(std::shared_ptr<BufferQueueConsumer> consumer_); |
| 31 | ~ConsumerBase() override; | 31 | ~ConsumerBase() override; |
| 32 | 32 | ||
| 33 | void OnFrameAvailable(const BufferItem& item) override; | 33 | void OnFrameAvailable(const BufferItem& item) override; |
| @@ -54,7 +54,7 @@ protected: | |||
| 54 | 54 | ||
| 55 | bool is_abandoned{}; | 55 | bool is_abandoned{}; |
| 56 | 56 | ||
| 57 | std::unique_ptr<BufferQueueConsumer> consumer; | 57 | std::shared_ptr<BufferQueueConsumer> consumer; |
| 58 | 58 | ||
| 59 | mutable std::mutex mutex; | 59 | mutable std::mutex mutex; |
| 60 | }; | 60 | }; |
diff --git a/src/core/hle/service/nvnflinger/display.h b/src/core/hle/service/nvnflinger/display.h new file mode 100644 index 000000000..f27cbf144 --- /dev/null +++ b/src/core/hle/service/nvnflinger/display.h | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <list> | ||
| 7 | |||
| 8 | #include "core/hle/service/nvnflinger/buffer_item_consumer.h" | ||
| 9 | #include "core/hle/service/nvnflinger/hwc_layer.h" | ||
| 10 | |||
| 11 | namespace Service::Nvnflinger { | ||
| 12 | |||
| 13 | struct Layer { | ||
| 14 | explicit Layer(std::shared_ptr<android::BufferItemConsumer> buffer_item_consumer_, | ||
| 15 | s32 consumer_id_) | ||
| 16 | : buffer_item_consumer(std::move(buffer_item_consumer_)), consumer_id(consumer_id_), | ||
| 17 | blending(LayerBlending::None), visible(true) {} | ||
| 18 | ~Layer() { | ||
| 19 | buffer_item_consumer->Abandon(); | ||
| 20 | } | ||
| 21 | |||
| 22 | std::shared_ptr<android::BufferItemConsumer> buffer_item_consumer; | ||
| 23 | s32 consumer_id; | ||
| 24 | LayerBlending blending; | ||
| 25 | bool visible; | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct LayerStack { | ||
| 29 | std::list<Layer> layers; | ||
| 30 | }; | ||
| 31 | |||
| 32 | struct Display { | ||
| 33 | explicit Display(u64 id_) { | ||
| 34 | id = id_; | ||
| 35 | } | ||
| 36 | |||
| 37 | Layer* FindLayer(s32 consumer_id) { | ||
| 38 | for (auto& layer : stack.layers) { | ||
| 39 | if (layer.consumer_id == consumer_id) { | ||
| 40 | return &layer; | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | return nullptr; | ||
| 45 | } | ||
| 46 | |||
| 47 | bool HasLayers() { | ||
| 48 | return !stack.layers.empty(); | ||
| 49 | } | ||
| 50 | |||
| 51 | u64 id; | ||
| 52 | LayerStack stack; | ||
| 53 | }; | ||
| 54 | |||
| 55 | } // namespace Service::Nvnflinger | ||
diff --git a/src/core/hle/service/nvnflinger/hardware_composer.cpp b/src/core/hle/service/nvnflinger/hardware_composer.cpp index be7eb97a3..02215a786 100644 --- a/src/core/hle/service/nvnflinger/hardware_composer.cpp +++ b/src/core/hle/service/nvnflinger/hardware_composer.cpp | |||
| @@ -10,8 +10,6 @@ | |||
| 10 | #include "core/hle/service/nvnflinger/hardware_composer.h" | 10 | #include "core/hle/service/nvnflinger/hardware_composer.h" |
| 11 | #include "core/hle/service/nvnflinger/hwc_layer.h" | 11 | #include "core/hle/service/nvnflinger/hwc_layer.h" |
| 12 | #include "core/hle/service/nvnflinger/ui/graphic_buffer.h" | 12 | #include "core/hle/service/nvnflinger/ui/graphic_buffer.h" |
| 13 | #include "core/hle/service/vi/display/vi_display.h" | ||
| 14 | #include "core/hle/service/vi/layer/vi_layer.h" | ||
| 15 | 13 | ||
| 16 | namespace Service::Nvnflinger { | 14 | namespace Service::Nvnflinger { |
| 17 | 15 | ||
| @@ -44,7 +42,7 @@ s32 NormalizeSwapInterval(f32* out_speed_scale, s32 swap_interval) { | |||
| 44 | HardwareComposer::HardwareComposer() = default; | 42 | HardwareComposer::HardwareComposer() = default; |
| 45 | HardwareComposer::~HardwareComposer() = default; | 43 | HardwareComposer::~HardwareComposer() = default; |
| 46 | 44 | ||
| 47 | u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, | 45 | u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display, |
| 48 | Nvidia::Devices::nvdisp_disp0& nvdisp) { | 46 | Nvidia::Devices::nvdisp_disp0& nvdisp) { |
| 49 | boost::container::small_vector<HwcLayer, 2> composition_stack; | 47 | boost::container::small_vector<HwcLayer, 2> composition_stack; |
| 50 | 48 | ||
| @@ -56,12 +54,11 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, | |||
| 56 | bool has_acquired_buffer{}; | 54 | bool has_acquired_buffer{}; |
| 57 | 55 | ||
| 58 | // Acquire all necessary framebuffers. | 56 | // Acquire all necessary framebuffers. |
| 59 | for (size_t i = 0; i < display.GetNumLayers(); i++) { | 57 | for (auto& layer : display.stack.layers) { |
| 60 | auto& layer = display.GetLayer(i); | 58 | auto consumer_id = layer.consumer_id; |
| 61 | auto layer_id = layer.GetLayerId(); | ||
| 62 | 59 | ||
| 63 | // Try to fetch the framebuffer (either new or stale). | 60 | // Try to fetch the framebuffer (either new or stale). |
| 64 | const auto result = this->CacheFramebufferLocked(layer, layer_id); | 61 | const auto result = this->CacheFramebufferLocked(layer, consumer_id); |
| 65 | 62 | ||
| 66 | // If we failed, skip this layer. | 63 | // If we failed, skip this layer. |
| 67 | if (result == CacheStatus::NoBufferAvailable) { | 64 | if (result == CacheStatus::NoBufferAvailable) { |
| @@ -73,24 +70,26 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, | |||
| 73 | has_acquired_buffer = true; | 70 | has_acquired_buffer = true; |
| 74 | } | 71 | } |
| 75 | 72 | ||
| 76 | const auto& buffer = m_framebuffers[layer_id]; | 73 | const auto& buffer = m_framebuffers[consumer_id]; |
| 77 | const auto& item = buffer.item; | 74 | const auto& item = buffer.item; |
| 78 | const auto& igbp_buffer = *item.graphic_buffer; | 75 | const auto& igbp_buffer = *item.graphic_buffer; |
| 79 | 76 | ||
| 80 | // TODO: get proper Z-index from layer | 77 | // TODO: get proper Z-index from layer |
| 81 | composition_stack.emplace_back(HwcLayer{ | 78 | if (layer.visible) { |
| 82 | .buffer_handle = igbp_buffer.BufferId(), | 79 | composition_stack.emplace_back(HwcLayer{ |
| 83 | .offset = igbp_buffer.Offset(), | 80 | .buffer_handle = igbp_buffer.BufferId(), |
| 84 | .format = igbp_buffer.ExternalFormat(), | 81 | .offset = igbp_buffer.Offset(), |
| 85 | .width = igbp_buffer.Width(), | 82 | .format = igbp_buffer.ExternalFormat(), |
| 86 | .height = igbp_buffer.Height(), | 83 | .width = igbp_buffer.Width(), |
| 87 | .stride = igbp_buffer.Stride(), | 84 | .height = igbp_buffer.Height(), |
| 88 | .z_index = 0, | 85 | .stride = igbp_buffer.Stride(), |
| 89 | .blending = layer.GetBlending(), | 86 | .z_index = 0, |
| 90 | .transform = static_cast<android::BufferTransformFlags>(item.transform), | 87 | .blending = layer.blending, |
| 91 | .crop_rect = item.crop, | 88 | .transform = static_cast<android::BufferTransformFlags>(item.transform), |
| 92 | .acquire_fence = item.fence, | 89 | .crop_rect = item.crop, |
| 93 | }); | 90 | .acquire_fence = item.fence, |
| 91 | }); | ||
| 92 | } | ||
| 94 | 93 | ||
| 95 | // We need to compose again either before this frame is supposed to | 94 | // We need to compose again either before this frame is supposed to |
| 96 | // be released, or exactly on the vsync period it should be released. | 95 | // be released, or exactly on the vsync period it should be released. |
| @@ -138,7 +137,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, | |||
| 138 | if (auto* layer = display.FindLayer(layer_id); layer != nullptr) { | 137 | if (auto* layer = display.FindLayer(layer_id); layer != nullptr) { |
| 139 | // TODO: support release fence | 138 | // TODO: support release fence |
| 140 | // This is needed to prevent screen tearing | 139 | // This is needed to prevent screen tearing |
| 141 | layer->GetConsumer().ReleaseBuffer(framebuffer.item, android::Fence::NoFence()); | 140 | layer->buffer_item_consumer->ReleaseBuffer(framebuffer.item, android::Fence::NoFence()); |
| 142 | framebuffer.is_acquired = false; | 141 | framebuffer.is_acquired = false; |
| 143 | } | 142 | } |
| 144 | } | 143 | } |
| @@ -146,26 +145,26 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display, | |||
| 146 | return frame_advance; | 145 | return frame_advance; |
| 147 | } | 146 | } |
| 148 | 147 | ||
| 149 | void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) { | 148 | void HardwareComposer::RemoveLayerLocked(Display& display, ConsumerId consumer_id) { |
| 150 | // Check if we are tracking a slot with this layer_id. | 149 | // Check if we are tracking a slot with this consumer_id. |
| 151 | const auto it = m_framebuffers.find(layer_id); | 150 | const auto it = m_framebuffers.find(consumer_id); |
| 152 | if (it == m_framebuffers.end()) { | 151 | if (it == m_framebuffers.end()) { |
| 153 | return; | 152 | return; |
| 154 | } | 153 | } |
| 155 | 154 | ||
| 156 | // Try to release the buffer item. | 155 | // Try to release the buffer item. |
| 157 | auto* const layer = display.FindLayer(layer_id); | 156 | auto* const layer = display.FindLayer(consumer_id); |
| 158 | if (layer && it->second.is_acquired) { | 157 | if (layer && it->second.is_acquired) { |
| 159 | layer->GetConsumer().ReleaseBuffer(it->second.item, android::Fence::NoFence()); | 158 | layer->buffer_item_consumer->ReleaseBuffer(it->second.item, android::Fence::NoFence()); |
| 160 | } | 159 | } |
| 161 | 160 | ||
| 162 | // Erase the slot. | 161 | // Erase the slot. |
| 163 | m_framebuffers.erase(it); | 162 | m_framebuffers.erase(it); |
| 164 | } | 163 | } |
| 165 | 164 | ||
| 166 | bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer) { | 165 | bool HardwareComposer::TryAcquireFramebufferLocked(Layer& layer, Framebuffer& framebuffer) { |
| 167 | // Attempt the update. | 166 | // Attempt the update. |
| 168 | const auto status = layer.GetConsumer().AcquireBuffer(&framebuffer.item, {}, false); | 167 | const auto status = layer.buffer_item_consumer->AcquireBuffer(&framebuffer.item, {}, false); |
| 169 | if (status != android::Status::NoError) { | 168 | if (status != android::Status::NoError) { |
| 170 | return false; | 169 | return false; |
| 171 | } | 170 | } |
| @@ -178,10 +177,10 @@ bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer | |||
| 178 | return true; | 177 | return true; |
| 179 | } | 178 | } |
| 180 | 179 | ||
| 181 | HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(VI::Layer& layer, | 180 | HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(Layer& layer, |
| 182 | LayerId layer_id) { | 181 | ConsumerId consumer_id) { |
| 183 | // Check if this framebuffer is already present. | 182 | // Check if this framebuffer is already present. |
| 184 | const auto it = m_framebuffers.find(layer_id); | 183 | const auto it = m_framebuffers.find(consumer_id); |
| 185 | if (it != m_framebuffers.end()) { | 184 | if (it != m_framebuffers.end()) { |
| 186 | // If it's currently still acquired, we are done. | 185 | // If it's currently still acquired, we are done. |
| 187 | if (it->second.is_acquired) { | 186 | if (it->second.is_acquired) { |
| @@ -203,7 +202,7 @@ HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(VI::Layer | |||
| 203 | 202 | ||
| 204 | if (this->TryAcquireFramebufferLocked(layer, framebuffer)) { | 203 | if (this->TryAcquireFramebufferLocked(layer, framebuffer)) { |
| 205 | // Move the buffer item into a new slot. | 204 | // Move the buffer item into a new slot. |
| 206 | m_framebuffers.emplace(layer_id, std::move(framebuffer)); | 205 | m_framebuffers.emplace(consumer_id, std::move(framebuffer)); |
| 207 | 206 | ||
| 208 | // We succeeded. | 207 | // We succeeded. |
| 209 | return CacheStatus::BufferAcquired; | 208 | return CacheStatus::BufferAcquired; |
diff --git a/src/core/hle/service/nvnflinger/hardware_composer.h b/src/core/hle/service/nvnflinger/hardware_composer.h index 28392c512..c5b830468 100644 --- a/src/core/hle/service/nvnflinger/hardware_composer.h +++ b/src/core/hle/service/nvnflinger/hardware_composer.h | |||
| @@ -3,35 +3,29 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <memory> | ||
| 7 | #include <boost/container/flat_map.hpp> | 6 | #include <boost/container/flat_map.hpp> |
| 8 | 7 | ||
| 9 | #include "core/hle/service/nvnflinger/buffer_item.h" | 8 | #include "core/hle/service/nvnflinger/buffer_item.h" |
| 9 | #include "core/hle/service/nvnflinger/display.h" | ||
| 10 | 10 | ||
| 11 | namespace Service::Nvidia::Devices { | 11 | namespace Service::Nvidia::Devices { |
| 12 | class nvdisp_disp0; | 12 | class nvdisp_disp0; |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | namespace Service::VI { | ||
| 16 | class Display; | ||
| 17 | class Layer; | ||
| 18 | } // namespace Service::VI | ||
| 19 | |||
| 20 | namespace Service::Nvnflinger { | 15 | namespace Service::Nvnflinger { |
| 21 | 16 | ||
| 22 | using LayerId = u64; | 17 | using ConsumerId = s32; |
| 23 | 18 | ||
| 24 | class HardwareComposer { | 19 | class HardwareComposer { |
| 25 | public: | 20 | public: |
| 26 | explicit HardwareComposer(); | 21 | explicit HardwareComposer(); |
| 27 | ~HardwareComposer(); | 22 | ~HardwareComposer(); |
| 28 | 23 | ||
| 29 | u32 ComposeLocked(f32* out_speed_scale, VI::Display& display, | 24 | u32 ComposeLocked(f32* out_speed_scale, Display& display, |
| 30 | Nvidia::Devices::nvdisp_disp0& nvdisp); | 25 | Nvidia::Devices::nvdisp_disp0& nvdisp); |
| 31 | void RemoveLayerLocked(VI::Display& display, LayerId layer_id); | 26 | void RemoveLayerLocked(Display& display, ConsumerId consumer_id); |
| 32 | 27 | ||
| 33 | private: | 28 | private: |
| 34 | // TODO: do we want to track frame number in vi instead? | ||
| 35 | u64 m_frame_number{0}; | 29 | u64 m_frame_number{0}; |
| 36 | 30 | ||
| 37 | private: | 31 | private: |
| @@ -49,11 +43,11 @@ private: | |||
| 49 | CachedBufferReused, | 43 | CachedBufferReused, |
| 50 | }; | 44 | }; |
| 51 | 45 | ||
| 52 | boost::container::flat_map<LayerId, Framebuffer> m_framebuffers{}; | 46 | boost::container::flat_map<ConsumerId, Framebuffer> m_framebuffers{}; |
| 53 | 47 | ||
| 54 | private: | 48 | private: |
| 55 | bool TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer); | 49 | bool TryAcquireFramebufferLocked(Layer& layer, Framebuffer& framebuffer); |
| 56 | CacheStatus CacheFramebufferLocked(VI::Layer& layer, LayerId layer_id); | 50 | CacheStatus CacheFramebufferLocked(Layer& layer, ConsumerId consumer_id); |
| 57 | }; | 51 | }; |
| 58 | 52 | ||
| 59 | } // namespace Service::Nvnflinger | 53 | } // namespace Service::Nvnflinger |
diff --git a/src/core/hle/service/vi/hos_binder_driver.cpp b/src/core/hle/service/nvnflinger/hos_binder_driver.cpp index ba0317245..8629a2e89 100644 --- a/src/core/hle/service/vi/hos_binder_driver.cpp +++ b/src/core/hle/service/nvnflinger/hos_binder_driver.cpp | |||
| @@ -3,13 +3,16 @@ | |||
| 3 | 3 | ||
| 4 | #include "core/hle/service/cmif_serialization.h" | 4 | #include "core/hle/service/cmif_serialization.h" |
| 5 | #include "core/hle/service/nvnflinger/binder.h" | 5 | #include "core/hle/service/nvnflinger/binder.h" |
| 6 | #include "core/hle/service/nvnflinger/hos_binder_driver.h" | ||
| 6 | #include "core/hle/service/nvnflinger/hos_binder_driver_server.h" | 7 | #include "core/hle/service/nvnflinger/hos_binder_driver_server.h" |
| 7 | #include "core/hle/service/vi/hos_binder_driver.h" | ||
| 8 | 8 | ||
| 9 | namespace Service::VI { | 9 | namespace Service::Nvnflinger { |
| 10 | 10 | ||
| 11 | IHOSBinderDriver::IHOSBinderDriver(Core::System& system_, Nvnflinger::HosBinderDriverServer& server) | 11 | IHOSBinderDriver::IHOSBinderDriver(Core::System& system_, |
| 12 | : ServiceFramework{system_, "IHOSBinderDriver"}, m_server(server) { | 12 | std::shared_ptr<HosBinderDriverServer> server, |
| 13 | std::shared_ptr<SurfaceFlinger> surface_flinger) | ||
| 14 | : ServiceFramework{system_, "IHOSBinderDriver"}, m_server(server), | ||
| 15 | m_surface_flinger(surface_flinger) { | ||
| 13 | static const FunctionInfo functions[] = { | 16 | static const FunctionInfo functions[] = { |
| 14 | {0, C<&IHOSBinderDriver::TransactParcel>, "TransactParcel"}, | 17 | {0, C<&IHOSBinderDriver::TransactParcel>, "TransactParcel"}, |
| 15 | {1, C<&IHOSBinderDriver::AdjustRefcount>, "AdjustRefcount"}, | 18 | {1, C<&IHOSBinderDriver::AdjustRefcount>, "AdjustRefcount"}, |
| @@ -21,13 +24,18 @@ IHOSBinderDriver::IHOSBinderDriver(Core::System& system_, Nvnflinger::HosBinderD | |||
| 21 | 24 | ||
| 22 | IHOSBinderDriver::~IHOSBinderDriver() = default; | 25 | IHOSBinderDriver::~IHOSBinderDriver() = default; |
| 23 | 26 | ||
| 24 | Result IHOSBinderDriver::TransactParcel(s32 binder_id, android::TransactionId transaction_id, | 27 | Result IHOSBinderDriver::TransactParcel(s32 binder_id, u32 transaction_id, |
| 25 | InBuffer<BufferAttr_HipcMapAlias> parcel_data, | 28 | InBuffer<BufferAttr_HipcMapAlias> parcel_data, |
| 26 | OutBuffer<BufferAttr_HipcMapAlias> parcel_reply, | 29 | OutBuffer<BufferAttr_HipcMapAlias> parcel_reply, |
| 27 | u32 flags) { | 30 | u32 flags) { |
| 28 | LOG_DEBUG(Service_VI, "called. id={} transaction={}, flags={}", binder_id, transaction_id, | 31 | LOG_DEBUG(Service_VI, "called. id={} transaction={}, flags={}", binder_id, transaction_id, |
| 29 | flags); | 32 | flags); |
| 30 | m_server.TryGetProducer(binder_id)->Transact(transaction_id, flags, parcel_data, parcel_reply); | 33 | |
| 34 | const auto binder = m_server->TryGetBinder(binder_id); | ||
| 35 | R_SUCCEED_IF(binder == nullptr); | ||
| 36 | |||
| 37 | binder->Transact(transaction_id, parcel_data, parcel_reply, flags); | ||
| 38 | |||
| 31 | R_SUCCEED(); | 39 | R_SUCCEED(); |
| 32 | } | 40 | } |
| 33 | 41 | ||
| @@ -39,15 +47,20 @@ Result IHOSBinderDriver::AdjustRefcount(s32 binder_id, s32 addval, s32 type) { | |||
| 39 | Result IHOSBinderDriver::GetNativeHandle(s32 binder_id, u32 type_id, | 47 | Result IHOSBinderDriver::GetNativeHandle(s32 binder_id, u32 type_id, |
| 40 | OutCopyHandle<Kernel::KReadableEvent> out_handle) { | 48 | OutCopyHandle<Kernel::KReadableEvent> out_handle) { |
| 41 | LOG_WARNING(Service_VI, "(STUBBED) called id={}, type_id={}", binder_id, type_id); | 49 | LOG_WARNING(Service_VI, "(STUBBED) called id={}, type_id={}", binder_id, type_id); |
| 42 | *out_handle = &m_server.TryGetProducer(binder_id)->GetNativeHandle(); | 50 | |
| 51 | const auto binder = m_server->TryGetBinder(binder_id); | ||
| 52 | R_UNLESS(binder != nullptr, ResultUnknown); | ||
| 53 | |||
| 54 | *out_handle = binder->GetNativeHandle(type_id); | ||
| 55 | |||
| 43 | R_SUCCEED(); | 56 | R_SUCCEED(); |
| 44 | } | 57 | } |
| 45 | 58 | ||
| 46 | Result IHOSBinderDriver::TransactParcelAuto(s32 binder_id, android::TransactionId transaction_id, | 59 | Result IHOSBinderDriver::TransactParcelAuto(s32 binder_id, u32 transaction_id, |
| 47 | InBuffer<BufferAttr_HipcAutoSelect> parcel_data, | 60 | InBuffer<BufferAttr_HipcAutoSelect> parcel_data, |
| 48 | OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply, | 61 | OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply, |
| 49 | u32 flags) { | 62 | u32 flags) { |
| 50 | R_RETURN(this->TransactParcel(binder_id, transaction_id, parcel_data, parcel_reply, flags)); | 63 | R_RETURN(this->TransactParcel(binder_id, transaction_id, parcel_data, parcel_reply, flags)); |
| 51 | } | 64 | } |
| 52 | 65 | ||
| 53 | } // namespace Service::VI | 66 | } // namespace Service::Nvnflinger |
diff --git a/src/core/hle/service/vi/hos_binder_driver.h b/src/core/hle/service/nvnflinger/hos_binder_driver.h index ed6e8cdbe..b7fb07bd2 100644 --- a/src/core/hle/service/vi/hos_binder_driver.h +++ b/src/core/hle/service/nvnflinger/hos_binder_driver.h | |||
| @@ -2,29 +2,45 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "core/hle/service/cmif_types.h" | 4 | #include "core/hle/service/cmif_types.h" |
| 5 | #include "core/hle/service/nvnflinger/binder.h" | ||
| 6 | #include "core/hle/service/service.h" | 5 | #include "core/hle/service/service.h" |
| 7 | 6 | ||
| 8 | namespace Service::VI { | 7 | namespace Kernel { |
| 8 | class KReadableEvent; | ||
| 9 | } | ||
| 10 | |||
| 11 | namespace Service::Nvnflinger { | ||
| 12 | |||
| 13 | class HosBinderDriverServer; | ||
| 14 | class SurfaceFlinger; | ||
| 9 | 15 | ||
| 10 | class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { | 16 | class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { |
| 11 | public: | 17 | public: |
| 12 | explicit IHOSBinderDriver(Core::System& system_, Nvnflinger::HosBinderDriverServer& server); | 18 | explicit IHOSBinderDriver(Core::System& system_, std::shared_ptr<HosBinderDriverServer> server, |
| 19 | std::shared_ptr<SurfaceFlinger> surface_flinger); | ||
| 13 | ~IHOSBinderDriver() override; | 20 | ~IHOSBinderDriver() override; |
| 14 | 21 | ||
| 22 | std::shared_ptr<SurfaceFlinger> GetSurfaceFlinger() { | ||
| 23 | return m_surface_flinger; | ||
| 24 | } | ||
| 25 | |||
| 26 | std::shared_ptr<HosBinderDriverServer> GetServer() { | ||
| 27 | return m_server; | ||
| 28 | } | ||
| 29 | |||
| 15 | private: | 30 | private: |
| 16 | Result TransactParcel(s32 binder_id, android::TransactionId transaction_id, | 31 | Result TransactParcel(s32 binder_id, u32 transaction_id, |
| 17 | InBuffer<BufferAttr_HipcMapAlias> parcel_data, | 32 | InBuffer<BufferAttr_HipcMapAlias> parcel_data, |
| 18 | OutBuffer<BufferAttr_HipcMapAlias> parcel_reply, u32 flags); | 33 | OutBuffer<BufferAttr_HipcMapAlias> parcel_reply, u32 flags); |
| 19 | Result AdjustRefcount(s32 binder_id, s32 addval, s32 type); | 34 | Result AdjustRefcount(s32 binder_id, s32 addval, s32 type); |
| 20 | Result GetNativeHandle(s32 binder_id, u32 type_id, | 35 | Result GetNativeHandle(s32 binder_id, u32 type_id, |
| 21 | OutCopyHandle<Kernel::KReadableEvent> out_handle); | 36 | OutCopyHandle<Kernel::KReadableEvent> out_handle); |
| 22 | Result TransactParcelAuto(s32 binder_id, android::TransactionId transaction_id, | 37 | Result TransactParcelAuto(s32 binder_id, u32 transaction_id, |
| 23 | InBuffer<BufferAttr_HipcAutoSelect> parcel_data, | 38 | InBuffer<BufferAttr_HipcAutoSelect> parcel_data, |
| 24 | OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply, u32 flags); | 39 | OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply, u32 flags); |
| 25 | 40 | ||
| 26 | private: | 41 | private: |
| 27 | Nvnflinger::HosBinderDriverServer& m_server; | 42 | const std::shared_ptr<HosBinderDriverServer> m_server; |
| 43 | const std::shared_ptr<SurfaceFlinger> m_surface_flinger; | ||
| 28 | }; | 44 | }; |
| 29 | 45 | ||
| 30 | } // namespace Service::VI | 46 | } // namespace Service::Nvnflinger |
diff --git a/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp b/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp index b86a79ec9..29addda44 100644 --- a/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp +++ b/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp | |||
| @@ -8,26 +8,30 @@ | |||
| 8 | 8 | ||
| 9 | namespace Service::Nvnflinger { | 9 | namespace Service::Nvnflinger { |
| 10 | 10 | ||
| 11 | HosBinderDriverServer::HosBinderDriverServer(Core::System& system_) | 11 | HosBinderDriverServer::HosBinderDriverServer() = default; |
| 12 | : service_context(system_, "HosBinderDriverServer") {} | 12 | HosBinderDriverServer::~HosBinderDriverServer() = default; |
| 13 | 13 | ||
| 14 | HosBinderDriverServer::~HosBinderDriverServer() {} | 14 | s32 HosBinderDriverServer::RegisterBinder(std::shared_ptr<android::IBinder>&& binder) { |
| 15 | |||
| 16 | u64 HosBinderDriverServer::RegisterProducer(std::unique_ptr<android::IBinder>&& binder) { | ||
| 17 | std::scoped_lock lk{lock}; | 15 | std::scoped_lock lk{lock}; |
| 18 | 16 | ||
| 19 | last_id++; | 17 | last_id++; |
| 20 | 18 | ||
| 21 | producers[last_id] = std::move(binder); | 19 | binders[last_id] = std::move(binder); |
| 22 | 20 | ||
| 23 | return last_id; | 21 | return last_id; |
| 24 | } | 22 | } |
| 25 | 23 | ||
| 26 | android::IBinder* HosBinderDriverServer::TryGetProducer(u64 id) { | 24 | void HosBinderDriverServer::UnregisterBinder(s32 binder_id) { |
| 25 | std::scoped_lock lk{lock}; | ||
| 26 | |||
| 27 | binders.erase(binder_id); | ||
| 28 | } | ||
| 29 | |||
| 30 | std::shared_ptr<android::IBinder> HosBinderDriverServer::TryGetBinder(s32 id) const { | ||
| 27 | std::scoped_lock lk{lock}; | 31 | std::scoped_lock lk{lock}; |
| 28 | 32 | ||
| 29 | if (auto search = producers.find(id); search != producers.end()) { | 33 | if (auto search = binders.find(id); search != binders.end()) { |
| 30 | return search->second.get(); | 34 | return search->second; |
| 31 | } | 35 | } |
| 32 | 36 | ||
| 33 | return {}; | 37 | return {}; |
diff --git a/src/core/hle/service/nvnflinger/hos_binder_driver_server.h b/src/core/hle/service/nvnflinger/hos_binder_driver_server.h index 58bb9469a..d72b50833 100644 --- a/src/core/hle/service/nvnflinger/hos_binder_driver_server.h +++ b/src/core/hle/service/nvnflinger/hos_binder_driver_server.h | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | #include <unordered_map> | 8 | #include <unordered_map> |
| 9 | 9 | ||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "core/hle/service/kernel_helpers.h" | ||
| 12 | #include "core/hle/service/nvnflinger/binder.h" | 11 | #include "core/hle/service/nvnflinger/binder.h" |
| 13 | 12 | ||
| 14 | namespace Core { | 13 | namespace Core { |
| @@ -19,19 +18,18 @@ namespace Service::Nvnflinger { | |||
| 19 | 18 | ||
| 20 | class HosBinderDriverServer final { | 19 | class HosBinderDriverServer final { |
| 21 | public: | 20 | public: |
| 22 | explicit HosBinderDriverServer(Core::System& system_); | 21 | explicit HosBinderDriverServer(); |
| 23 | ~HosBinderDriverServer(); | 22 | ~HosBinderDriverServer(); |
| 24 | 23 | ||
| 25 | u64 RegisterProducer(std::unique_ptr<android::IBinder>&& binder); | 24 | s32 RegisterBinder(std::shared_ptr<android::IBinder>&& binder); |
| 25 | void UnregisterBinder(s32 binder_id); | ||
| 26 | 26 | ||
| 27 | android::IBinder* TryGetProducer(u64 id); | 27 | std::shared_ptr<android::IBinder> TryGetBinder(s32 id) const; |
| 28 | 28 | ||
| 29 | private: | 29 | private: |
| 30 | KernelHelpers::ServiceContext service_context; | 30 | std::unordered_map<s32, std::shared_ptr<android::IBinder>> binders; |
| 31 | 31 | mutable std::mutex lock; | |
| 32 | std::unordered_map<u64, std::unique_ptr<android::IBinder>> producers; | 32 | s32 last_id{}; |
| 33 | std::mutex lock; | ||
| 34 | u64 last_id{}; | ||
| 35 | }; | 33 | }; |
| 36 | 34 | ||
| 37 | } // namespace Service::Nvnflinger | 35 | } // namespace Service::Nvnflinger |
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index 687ccc9f9..9e3b68b8a 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp | |||
| @@ -1,335 +1,24 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | 2 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 3 | 3 | ||
| 4 | #include <algorithm> | ||
| 5 | #include <optional> | ||
| 6 | |||
| 7 | #include "common/assert.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "common/microprofile.h" | ||
| 10 | #include "common/scope_exit.h" | ||
| 11 | #include "common/settings.h" | ||
| 12 | #include "common/thread.h" | ||
| 13 | #include "core/core.h" | 4 | #include "core/core.h" |
| 14 | #include "core/core_timing.h" | 5 | #include "core/hle/service/nvnflinger/hos_binder_driver.h" |
| 15 | #include "core/hle/kernel/k_readable_event.h" | ||
| 16 | #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" | ||
| 17 | #include "core/hle/service/nvdrv/nvdrv.h" | ||
| 18 | #include "core/hle/service/nvnflinger/buffer_item_consumer.h" | ||
| 19 | #include "core/hle/service/nvnflinger/buffer_queue_core.h" | ||
| 20 | #include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" | ||
| 21 | #include "core/hle/service/nvnflinger/hardware_composer.h" | ||
| 22 | #include "core/hle/service/nvnflinger/hos_binder_driver_server.h" | 6 | #include "core/hle/service/nvnflinger/hos_binder_driver_server.h" |
| 23 | #include "core/hle/service/nvnflinger/nvnflinger.h" | 7 | #include "core/hle/service/nvnflinger/nvnflinger.h" |
| 24 | #include "core/hle/service/nvnflinger/ui/graphic_buffer.h" | 8 | #include "core/hle/service/nvnflinger/surface_flinger.h" |
| 25 | #include "core/hle/service/vi/display/vi_display.h" | 9 | #include "core/hle/service/server_manager.h" |
| 26 | #include "core/hle/service/vi/layer/vi_layer.h" | 10 | #include "core/hle/service/sm/sm.h" |
| 27 | #include "core/hle/service/vi/vi_results.h" | ||
| 28 | #include "video_core/gpu.h" | ||
| 29 | #include "video_core/host1x/host1x.h" | ||
| 30 | #include "video_core/host1x/syncpoint_manager.h" | ||
| 31 | 11 | ||
| 32 | namespace Service::Nvnflinger { | 12 | namespace Service::Nvnflinger { |
| 33 | 13 | ||
| 34 | constexpr auto frame_ns = std::chrono::nanoseconds{1000000000 / 60}; | 14 | void LoopProcess(Core::System& system) { |
| 35 | 15 | const auto binder_server = std::make_shared<HosBinderDriverServer>(); | |
| 36 | void Nvnflinger::SplitVSync(std::stop_token stop_token) { | 16 | const auto surface_flinger = std::make_shared<SurfaceFlinger>(system, *binder_server); |
| 37 | system.RegisterHostThread(); | ||
| 38 | std::string name = "VSyncThread"; | ||
| 39 | MicroProfileOnThreadCreate(name.c_str()); | ||
| 40 | |||
| 41 | // Cleanup | ||
| 42 | SCOPE_EXIT({ MicroProfileOnThreadExit(); }); | ||
| 43 | |||
| 44 | Common::SetCurrentThreadName(name.c_str()); | ||
| 45 | Common::SetCurrentThreadPriority(Common::ThreadPriority::High); | ||
| 46 | |||
| 47 | while (!stop_token.stop_requested()) { | ||
| 48 | vsync_signal.Wait(); | ||
| 49 | |||
| 50 | const auto lock_guard = Lock(); | ||
| 51 | |||
| 52 | if (!is_abandoned) { | ||
| 53 | Compose(); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_) | ||
| 59 | : system(system_), service_context(system_, "nvnflinger"), | ||
| 60 | hos_binder_driver_server(hos_binder_driver_server_) { | ||
| 61 | displays.emplace_back(0, "Default", hos_binder_driver_server, service_context, system); | ||
| 62 | displays.emplace_back(1, "External", hos_binder_driver_server, service_context, system); | ||
| 63 | displays.emplace_back(2, "Edid", hos_binder_driver_server, service_context, system); | ||
| 64 | displays.emplace_back(3, "Internal", hos_binder_driver_server, service_context, system); | ||
| 65 | displays.emplace_back(4, "Null", hos_binder_driver_server, service_context, system); | ||
| 66 | guard = std::make_shared<std::mutex>(); | ||
| 67 | |||
| 68 | // Schedule the screen composition events | ||
| 69 | multi_composition_event = Core::Timing::CreateEvent( | ||
| 70 | "ScreenComposition", | ||
| 71 | [this](s64 time, | ||
| 72 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 73 | vsync_signal.Set(); | ||
| 74 | return std::chrono::nanoseconds(GetNextTicks()); | ||
| 75 | }); | ||
| 76 | |||
| 77 | single_composition_event = Core::Timing::CreateEvent( | ||
| 78 | "ScreenComposition", | ||
| 79 | [this](s64 time, | ||
| 80 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 81 | const auto lock_guard = Lock(); | ||
| 82 | Compose(); | ||
| 83 | |||
| 84 | return std::chrono::nanoseconds(GetNextTicks()); | ||
| 85 | }); | ||
| 86 | |||
| 87 | if (system.IsMulticore()) { | ||
| 88 | system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, multi_composition_event); | ||
| 89 | vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); }); | ||
| 90 | } else { | ||
| 91 | system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, single_composition_event); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | Nvnflinger::~Nvnflinger() { | ||
| 96 | if (system.IsMulticore()) { | ||
| 97 | system.CoreTiming().UnscheduleEvent(multi_composition_event); | ||
| 98 | vsync_thread.request_stop(); | ||
| 99 | vsync_signal.Set(); | ||
| 100 | } else { | ||
| 101 | system.CoreTiming().UnscheduleEvent(single_composition_event); | ||
| 102 | } | ||
| 103 | |||
| 104 | ShutdownLayers(); | ||
| 105 | |||
| 106 | if (nvdrv) { | ||
| 107 | nvdrv->Close(disp_fd); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | void Nvnflinger::ShutdownLayers() { | ||
| 112 | // Abandon consumers. | ||
| 113 | { | ||
| 114 | const auto lock_guard = Lock(); | ||
| 115 | for (auto& display : displays) { | ||
| 116 | display.Abandon(); | ||
| 117 | } | ||
| 118 | |||
| 119 | is_abandoned = true; | ||
| 120 | } | ||
| 121 | |||
| 122 | // Join the vsync thread, if it exists. | ||
| 123 | vsync_thread = {}; | ||
| 124 | } | ||
| 125 | |||
| 126 | void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { | ||
| 127 | nvdrv = std::move(instance); | ||
| 128 | disp_fd = nvdrv->Open("/dev/nvdisp_disp0", {}); | ||
| 129 | } | ||
| 130 | |||
| 131 | std::optional<u64> Nvnflinger::OpenDisplay(std::string_view name) { | ||
| 132 | const auto lock_guard = Lock(); | ||
| 133 | |||
| 134 | LOG_DEBUG(Service_Nvnflinger, "Opening \"{}\" display", name); | ||
| 135 | |||
| 136 | const auto itr = | ||
| 137 | std::find_if(displays.begin(), displays.end(), | ||
| 138 | [&](const VI::Display& display) { return display.GetName() == name; }); | ||
| 139 | |||
| 140 | if (itr == displays.end()) { | ||
| 141 | return std::nullopt; | ||
| 142 | } | ||
| 143 | |||
| 144 | return itr->GetID(); | ||
| 145 | } | ||
| 146 | |||
| 147 | bool Nvnflinger::CloseDisplay(u64 display_id) { | ||
| 148 | const auto lock_guard = Lock(); | ||
| 149 | auto* const display = FindDisplay(display_id); | ||
| 150 | |||
| 151 | if (display == nullptr) { | ||
| 152 | return false; | ||
| 153 | } | ||
| 154 | |||
| 155 | display->Reset(); | ||
| 156 | |||
| 157 | return true; | ||
| 158 | } | ||
| 159 | |||
| 160 | std::optional<u64> Nvnflinger::CreateLayer(u64 display_id, LayerBlending blending) { | ||
| 161 | const auto lock_guard = Lock(); | ||
| 162 | auto* const display = FindDisplay(display_id); | ||
| 163 | |||
| 164 | if (display == nullptr) { | ||
| 165 | return std::nullopt; | ||
| 166 | } | ||
| 167 | |||
| 168 | const u64 layer_id = next_layer_id++; | ||
| 169 | CreateLayerAtId(*display, layer_id, blending); | ||
| 170 | return layer_id; | ||
| 171 | } | ||
| 172 | |||
| 173 | void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending) { | ||
| 174 | const auto buffer_id = next_buffer_queue_id++; | ||
| 175 | display.CreateLayer(layer_id, buffer_id, nvdrv->container); | ||
| 176 | display.FindLayer(layer_id)->SetBlending(blending); | ||
| 177 | } | ||
| 178 | |||
| 179 | bool Nvnflinger::OpenLayer(u64 layer_id) { | ||
| 180 | const auto lock_guard = Lock(); | ||
| 181 | |||
| 182 | for (auto& display : displays) { | ||
| 183 | if (auto* layer = display.FindLayer(layer_id); layer) { | ||
| 184 | return layer->Open(); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | return false; | ||
| 189 | } | ||
| 190 | |||
| 191 | bool Nvnflinger::CloseLayer(u64 layer_id) { | ||
| 192 | const auto lock_guard = Lock(); | ||
| 193 | |||
| 194 | for (auto& display : displays) { | ||
| 195 | if (auto* layer = display.FindLayer(layer_id); layer) { | ||
| 196 | return layer->Close(); | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | return false; | ||
| 201 | } | ||
| 202 | |||
| 203 | void Nvnflinger::SetLayerVisibility(u64 layer_id, bool visible) { | ||
| 204 | const auto lock_guard = Lock(); | ||
| 205 | |||
| 206 | for (auto& display : displays) { | ||
| 207 | if (auto* layer = display.FindLayer(layer_id); layer) { | ||
| 208 | layer->SetVisibility(visible); | ||
| 209 | } | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | void Nvnflinger::DestroyLayer(u64 layer_id) { | ||
| 214 | const auto lock_guard = Lock(); | ||
| 215 | |||
| 216 | for (auto& display : displays) { | ||
| 217 | display.DestroyLayer(layer_id); | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | std::optional<u32> Nvnflinger::FindBufferQueueId(u64 display_id, u64 layer_id) { | ||
| 222 | const auto lock_guard = Lock(); | ||
| 223 | const auto* const layer = FindLayer(display_id, layer_id); | ||
| 224 | |||
| 225 | if (layer == nullptr) { | ||
| 226 | return std::nullopt; | ||
| 227 | } | ||
| 228 | |||
| 229 | return layer->GetBinderId(); | ||
| 230 | } | ||
| 231 | |||
| 232 | Result Nvnflinger::FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 display_id) { | ||
| 233 | const auto lock_guard = Lock(); | ||
| 234 | auto* const display = FindDisplay(display_id); | ||
| 235 | |||
| 236 | if (display == nullptr) { | ||
| 237 | return VI::ResultNotFound; | ||
| 238 | } | ||
| 239 | |||
| 240 | *out_vsync_event = display->GetVSyncEvent(); | ||
| 241 | return ResultSuccess; | ||
| 242 | } | ||
| 243 | |||
| 244 | VI::Display* Nvnflinger::FindDisplay(u64 display_id) { | ||
| 245 | const auto itr = | ||
| 246 | std::find_if(displays.begin(), displays.end(), | ||
| 247 | [&](const VI::Display& display) { return display.GetID() == display_id; }); | ||
| 248 | |||
| 249 | if (itr == displays.end()) { | ||
| 250 | return nullptr; | ||
| 251 | } | ||
| 252 | |||
| 253 | return &*itr; | ||
| 254 | } | ||
| 255 | |||
| 256 | const VI::Display* Nvnflinger::FindDisplay(u64 display_id) const { | ||
| 257 | const auto itr = | ||
| 258 | std::find_if(displays.begin(), displays.end(), | ||
| 259 | [&](const VI::Display& display) { return display.GetID() == display_id; }); | ||
| 260 | |||
| 261 | if (itr == displays.end()) { | ||
| 262 | return nullptr; | ||
| 263 | } | ||
| 264 | |||
| 265 | return &*itr; | ||
| 266 | } | ||
| 267 | |||
| 268 | VI::Layer* Nvnflinger::FindLayer(u64 display_id, u64 layer_id) { | ||
| 269 | auto* const display = FindDisplay(display_id); | ||
| 270 | |||
| 271 | if (display == nullptr) { | ||
| 272 | return nullptr; | ||
| 273 | } | ||
| 274 | |||
| 275 | return display->FindLayer(layer_id); | ||
| 276 | } | ||
| 277 | |||
| 278 | void Nvnflinger::Compose() { | ||
| 279 | for (auto& display : displays) { | ||
| 280 | // Trigger vsync for this display at the end of drawing | ||
| 281 | SCOPE_EXIT({ display.SignalVSyncEvent(); }); | ||
| 282 | |||
| 283 | // Don't do anything for displays without layers. | ||
| 284 | if (!display.HasLayers()) { | ||
| 285 | continue; | ||
| 286 | } | ||
| 287 | |||
| 288 | if (!system.IsPoweredOn()) { | ||
| 289 | return; // We are likely shutting down | ||
| 290 | } | ||
| 291 | |||
| 292 | auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd); | ||
| 293 | ASSERT(nvdisp); | ||
| 294 | |||
| 295 | swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp); | ||
| 296 | } | ||
| 297 | } | ||
| 298 | |||
| 299 | s64 Nvnflinger::GetNextTicks() const { | ||
| 300 | const auto& settings = Settings::values; | ||
| 301 | auto speed_scale = 1.f; | ||
| 302 | if (settings.use_multi_core.GetValue()) { | ||
| 303 | if (settings.use_speed_limit.GetValue()) { | ||
| 304 | // Scales the speed based on speed_limit setting on MC. SC is handled by | ||
| 305 | // SpeedLimiter::DoSpeedLimiting. | ||
| 306 | speed_scale = 100.f / settings.speed_limit.GetValue(); | ||
| 307 | } else { | ||
| 308 | // Run at unlocked framerate. | ||
| 309 | speed_scale = 0.01f; | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | // Adjust by speed limit determined during composition. | ||
| 314 | speed_scale /= compose_speed_scale; | ||
| 315 | |||
| 316 | if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) { | ||
| 317 | // Run at intended presentation rate during video playback. | ||
| 318 | speed_scale = 1.f; | ||
| 319 | } | ||
| 320 | |||
| 321 | const f32 effective_fps = 60.f / static_cast<f32>(swap_interval); | ||
| 322 | return static_cast<s64>(speed_scale * (1000000000.f / effective_fps)); | ||
| 323 | } | ||
| 324 | |||
| 325 | FbShareBufferManager& Nvnflinger::GetSystemBufferManager() { | ||
| 326 | const auto lock_guard = Lock(); | ||
| 327 | |||
| 328 | if (!system_buffer_manager) { | ||
| 329 | system_buffer_manager = std::make_unique<FbShareBufferManager>(system, *this, nvdrv); | ||
| 330 | } | ||
| 331 | 17 | ||
| 332 | return *system_buffer_manager; | 18 | auto server_manager = std::make_unique<ServerManager>(system); |
| 19 | server_manager->RegisterNamedService( | ||
| 20 | "dispdrv", std::make_shared<IHOSBinderDriver>(system, binder_server, surface_flinger)); | ||
| 21 | ServerManager::RunServer(std::move(server_manager)); | ||
| 333 | } | 22 | } |
| 334 | 23 | ||
| 335 | } // namespace Service::Nvnflinger | 24 | } // namespace Service::Nvnflinger |
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h index 4cf4f069d..5c41f3013 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.h +++ b/src/core/hle/service/nvnflinger/nvnflinger.h | |||
| @@ -3,170 +3,12 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <list> | 6 | namespace Core { |
| 7 | #include <memory> | 7 | class System; |
| 8 | #include <mutex> | 8 | } |
| 9 | #include <optional> | ||
| 10 | #include <thread> | ||
| 11 | #include <vector> | ||
| 12 | |||
| 13 | #include "common/common_types.h" | ||
| 14 | #include "common/polyfill_thread.h" | ||
| 15 | #include "common/thread.h" | ||
| 16 | #include "core/hle/result.h" | ||
| 17 | #include "core/hle/service/kernel_helpers.h" | ||
| 18 | #include "core/hle/service/nvnflinger/hwc_layer.h" | ||
| 19 | |||
| 20 | namespace Common { | ||
| 21 | class Event; | ||
| 22 | } // namespace Common | ||
| 23 | |||
| 24 | namespace Core::Timing { | ||
| 25 | class CoreTiming; | ||
| 26 | struct EventType; | ||
| 27 | } // namespace Core::Timing | ||
| 28 | |||
| 29 | namespace Kernel { | ||
| 30 | class KReadableEvent; | ||
| 31 | } // namespace Kernel | ||
| 32 | |||
| 33 | namespace Service::Nvidia { | ||
| 34 | class Module; | ||
| 35 | } // namespace Service::Nvidia | ||
| 36 | |||
| 37 | namespace Service::VI { | ||
| 38 | class Display; | ||
| 39 | class Layer; | ||
| 40 | } // namespace Service::VI | ||
| 41 | |||
| 42 | namespace Service::android { | ||
| 43 | class BufferQueueCore; | ||
| 44 | class BufferQueueProducer; | ||
| 45 | } // namespace Service::android | ||
| 46 | 9 | ||
| 47 | namespace Service::Nvnflinger { | 10 | namespace Service::Nvnflinger { |
| 48 | 11 | ||
| 49 | class FbShareBufferManager; | 12 | void LoopProcess(Core::System& system); |
| 50 | class HardwareComposer; | ||
| 51 | class HosBinderDriverServer; | ||
| 52 | |||
| 53 | class Nvnflinger final { | ||
| 54 | public: | ||
| 55 | explicit Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_); | ||
| 56 | ~Nvnflinger(); | ||
| 57 | |||
| 58 | void ShutdownLayers(); | ||
| 59 | |||
| 60 | /// Sets the NVDrv module instance to use to send buffers to the GPU. | ||
| 61 | void SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance); | ||
| 62 | |||
| 63 | /// Opens the specified display and returns the ID. | ||
| 64 | /// | ||
| 65 | /// If an invalid display name is provided, then an empty optional is returned. | ||
| 66 | [[nodiscard]] std::optional<u64> OpenDisplay(std::string_view name); | ||
| 67 | |||
| 68 | /// Closes the specified display by its ID. | ||
| 69 | /// | ||
| 70 | /// Returns false if an invalid display ID is provided. | ||
| 71 | [[nodiscard]] bool CloseDisplay(u64 display_id); | ||
| 72 | |||
| 73 | /// Creates a layer on the specified display and returns the layer ID. | ||
| 74 | /// | ||
| 75 | /// If an invalid display ID is specified, then an empty optional is returned. | ||
| 76 | [[nodiscard]] std::optional<u64> CreateLayer(u64 display_id, | ||
| 77 | LayerBlending blending = LayerBlending::None); | ||
| 78 | |||
| 79 | /// Opens a layer on all displays for the given layer ID. | ||
| 80 | bool OpenLayer(u64 layer_id); | ||
| 81 | |||
| 82 | /// Closes a layer on all displays for the given layer ID. | ||
| 83 | bool CloseLayer(u64 layer_id); | ||
| 84 | |||
| 85 | /// Makes a layer visible on all displays for the given layer ID. | ||
| 86 | void SetLayerVisibility(u64 layer_id, bool visible); | ||
| 87 | |||
| 88 | /// Destroys the given layer ID. | ||
| 89 | void DestroyLayer(u64 layer_id); | ||
| 90 | |||
| 91 | /// Finds the buffer queue ID of the specified layer in the specified display. | ||
| 92 | /// | ||
| 93 | /// If an invalid display ID or layer ID is provided, then an empty optional is returned. | ||
| 94 | [[nodiscard]] std::optional<u32> FindBufferQueueId(u64 display_id, u64 layer_id); | ||
| 95 | |||
| 96 | /// Gets the vsync event for the specified display. | ||
| 97 | /// | ||
| 98 | /// If an invalid display ID is provided, then VI::ResultNotFound is returned. | ||
| 99 | /// If the vsync event has already been retrieved, then VI::ResultPermissionDenied is returned. | ||
| 100 | [[nodiscard]] Result FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 display_id); | ||
| 101 | |||
| 102 | /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when | ||
| 103 | /// finished. | ||
| 104 | void Compose(); | ||
| 105 | |||
| 106 | [[nodiscard]] s64 GetNextTicks() const; | ||
| 107 | |||
| 108 | FbShareBufferManager& GetSystemBufferManager(); | ||
| 109 | |||
| 110 | private: | ||
| 111 | struct Layer { | ||
| 112 | std::unique_ptr<android::BufferQueueCore> core; | ||
| 113 | std::unique_ptr<android::BufferQueueProducer> producer; | ||
| 114 | }; | ||
| 115 | |||
| 116 | friend class FbShareBufferManager; | ||
| 117 | |||
| 118 | private: | ||
| 119 | [[nodiscard]] std::unique_lock<std::mutex> Lock() const { | ||
| 120 | return std::unique_lock{*guard}; | ||
| 121 | } | ||
| 122 | |||
| 123 | /// Finds the display identified by the specified ID. | ||
| 124 | [[nodiscard]] VI::Display* FindDisplay(u64 display_id); | ||
| 125 | |||
| 126 | /// Finds the display identified by the specified ID. | ||
| 127 | [[nodiscard]] const VI::Display* FindDisplay(u64 display_id) const; | ||
| 128 | |||
| 129 | /// Finds the layer identified by the specified ID in the desired display. | ||
| 130 | [[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id); | ||
| 131 | |||
| 132 | /// Creates a layer with the specified layer ID in the desired display. | ||
| 133 | void CreateLayerAtId(VI::Display& display, u64 layer_id, LayerBlending blending); | ||
| 134 | |||
| 135 | void SplitVSync(std::stop_token stop_token); | ||
| 136 | |||
| 137 | std::shared_ptr<Nvidia::Module> nvdrv; | ||
| 138 | s32 disp_fd; | ||
| 139 | |||
| 140 | std::list<VI::Display> displays; | ||
| 141 | |||
| 142 | /// Id to use for the next layer that is created, this counter is shared among all displays. | ||
| 143 | u64 next_layer_id = 1; | ||
| 144 | /// Id to use for the next buffer queue that is created, this counter is shared among all | ||
| 145 | /// layers. | ||
| 146 | u32 next_buffer_queue_id = 1; | ||
| 147 | |||
| 148 | s32 swap_interval = 1; | ||
| 149 | f32 compose_speed_scale = 1.0f; | ||
| 150 | |||
| 151 | bool is_abandoned = false; | ||
| 152 | |||
| 153 | /// Event that handles screen composition. | ||
| 154 | std::shared_ptr<Core::Timing::EventType> multi_composition_event; | ||
| 155 | std::shared_ptr<Core::Timing::EventType> single_composition_event; | ||
| 156 | |||
| 157 | std::unique_ptr<FbShareBufferManager> system_buffer_manager; | ||
| 158 | |||
| 159 | std::shared_ptr<std::mutex> guard; | ||
| 160 | |||
| 161 | Core::System& system; | ||
| 162 | |||
| 163 | Common::Event vsync_signal; | ||
| 164 | |||
| 165 | std::jthread vsync_thread; | ||
| 166 | |||
| 167 | KernelHelpers::ServiceContext service_context; | ||
| 168 | |||
| 169 | HosBinderDriverServer& hos_binder_driver_server; | ||
| 170 | }; | ||
| 171 | 13 | ||
| 172 | } // namespace Service::Nvnflinger | 14 | } // namespace Service::Nvnflinger |
diff --git a/src/core/hle/service/nvnflinger/surface_flinger.cpp b/src/core/hle/service/nvnflinger/surface_flinger.cpp new file mode 100644 index 000000000..41a705717 --- /dev/null +++ b/src/core/hle/service/nvnflinger/surface_flinger.cpp | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" | ||
| 6 | #include "core/hle/service/nvdrv/nvdrv_interface.h" | ||
| 7 | #include "core/hle/service/nvnflinger/display.h" | ||
| 8 | #include "core/hle/service/nvnflinger/hos_binder_driver_server.h" | ||
| 9 | #include "core/hle/service/nvnflinger/surface_flinger.h" | ||
| 10 | #include "core/hle/service/sm/sm.h" | ||
| 11 | |||
| 12 | #include "core/hle/service/nvnflinger/buffer_queue_consumer.h" | ||
| 13 | #include "core/hle/service/nvnflinger/buffer_queue_core.h" | ||
| 14 | #include "core/hle/service/nvnflinger/buffer_queue_producer.h" | ||
| 15 | |||
| 16 | namespace Service::Nvnflinger { | ||
| 17 | |||
| 18 | SurfaceFlinger::SurfaceFlinger(Core::System& system, HosBinderDriverServer& server) | ||
| 19 | : m_system(system), m_server(server), m_context(m_system, "SurfaceFlinger") { | ||
| 20 | nvdrv = m_system.ServiceManager().GetService<Nvidia::NVDRV>("nvdrv:s", true)->GetModule(); | ||
| 21 | disp_fd = nvdrv->Open("/dev/nvdisp_disp0", {}); | ||
| 22 | } | ||
| 23 | |||
| 24 | SurfaceFlinger::~SurfaceFlinger() { | ||
| 25 | nvdrv->Close(disp_fd); | ||
| 26 | } | ||
| 27 | |||
| 28 | void SurfaceFlinger::AddDisplay(u64 display_id) { | ||
| 29 | m_displays.emplace_back(display_id); | ||
| 30 | } | ||
| 31 | |||
| 32 | void SurfaceFlinger::RemoveDisplay(u64 display_id) { | ||
| 33 | std::erase_if(m_displays, [&](auto& display) { return display.id == display_id; }); | ||
| 34 | } | ||
| 35 | |||
| 36 | bool SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, | ||
| 37 | u64 display_id) { | ||
| 38 | auto* const display = this->FindDisplay(display_id); | ||
| 39 | if (!display || !display->HasLayers()) { | ||
| 40 | return false; | ||
| 41 | } | ||
| 42 | |||
| 43 | *out_swap_interval = | ||
| 44 | m_composer.ComposeLocked(out_compose_speed_scale, *display, | ||
| 45 | *nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd)); | ||
| 46 | return true; | ||
| 47 | } | ||
| 48 | |||
| 49 | void SurfaceFlinger::AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id) { | ||
| 50 | auto* const display = this->FindDisplay(display_id); | ||
| 51 | auto binder = std::static_pointer_cast<android::BufferQueueConsumer>( | ||
| 52 | m_server.TryGetBinder(consumer_binder_id)); | ||
| 53 | |||
| 54 | if (!display || !binder) { | ||
| 55 | return; | ||
| 56 | } | ||
| 57 | |||
| 58 | auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(binder)); | ||
| 59 | buffer_item_consumer->Connect(false); | ||
| 60 | |||
| 61 | display->stack.layers.emplace_back(std::move(buffer_item_consumer), consumer_binder_id); | ||
| 62 | } | ||
| 63 | |||
| 64 | void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id) { | ||
| 65 | auto* const display = this->FindDisplay(display_id); | ||
| 66 | if (!display) { | ||
| 67 | return; | ||
| 68 | } | ||
| 69 | |||
| 70 | m_composer.RemoveLayerLocked(*display, consumer_binder_id); | ||
| 71 | std::erase_if(display->stack.layers, | ||
| 72 | [&](auto& layer) { return layer.consumer_id == consumer_binder_id; }); | ||
| 73 | } | ||
| 74 | |||
| 75 | void SurfaceFlinger::SetLayerVisibility(s32 consumer_binder_id, bool visible) { | ||
| 76 | if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) { | ||
| 77 | layer->visible = visible; | ||
| 78 | return; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blending) { | ||
| 83 | if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) { | ||
| 84 | layer->blending = blending; | ||
| 85 | return; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | Display* SurfaceFlinger::FindDisplay(u64 display_id) { | ||
| 90 | for (auto& display : m_displays) { | ||
| 91 | if (display.id == display_id) { | ||
| 92 | return &display; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | return nullptr; | ||
| 97 | } | ||
| 98 | |||
| 99 | Layer* SurfaceFlinger::FindLayer(s32 consumer_binder_id) { | ||
| 100 | for (auto& display : m_displays) { | ||
| 101 | if (auto* layer = display.FindLayer(consumer_binder_id); layer != nullptr) { | ||
| 102 | return layer; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | return nullptr; | ||
| 107 | } | ||
| 108 | |||
| 109 | void SurfaceFlinger::CreateBufferQueue(s32* out_consumer_binder_id, s32* out_producer_binder_id) { | ||
| 110 | auto& nvmap = nvdrv->GetContainer().GetNvMapFile(); | ||
| 111 | auto core = std::make_shared<android::BufferQueueCore>(); | ||
| 112 | auto producer = std::make_shared<android::BufferQueueProducer>(m_context, core, nvmap); | ||
| 113 | auto consumer = std::make_shared<android::BufferQueueConsumer>(core); | ||
| 114 | |||
| 115 | *out_consumer_binder_id = m_server.RegisterBinder(std::move(consumer)); | ||
| 116 | *out_producer_binder_id = m_server.RegisterBinder(std::move(producer)); | ||
| 117 | } | ||
| 118 | |||
| 119 | void SurfaceFlinger::DestroyBufferQueue(s32 consumer_binder_id, s32 producer_binder_id) { | ||
| 120 | m_server.UnregisterBinder(producer_binder_id); | ||
| 121 | m_server.UnregisterBinder(consumer_binder_id); | ||
| 122 | } | ||
| 123 | |||
| 124 | } // namespace Service::Nvnflinger | ||
diff --git a/src/core/hle/service/nvnflinger/surface_flinger.h b/src/core/hle/service/nvnflinger/surface_flinger.h new file mode 100644 index 000000000..d8c53fbda --- /dev/null +++ b/src/core/hle/service/nvnflinger/surface_flinger.h | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <vector> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/hle/service/kernel_helpers.h" | ||
| 10 | #include "core/hle/service/nvnflinger/hardware_composer.h" | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service::Nvidia { | ||
| 17 | class Module; | ||
| 18 | } | ||
| 19 | |||
| 20 | // TODO: ISurfaceComposer | ||
| 21 | // TODO: ISurfaceComposerClient | ||
| 22 | |||
| 23 | namespace Service::Nvnflinger { | ||
| 24 | |||
| 25 | struct Display; | ||
| 26 | class HosBinderDriverServer; | ||
| 27 | enum class LayerBlending : u32; | ||
| 28 | struct Layer; | ||
| 29 | |||
| 30 | class SurfaceFlinger { | ||
| 31 | public: | ||
| 32 | explicit SurfaceFlinger(Core::System& system, HosBinderDriverServer& server); | ||
| 33 | ~SurfaceFlinger(); | ||
| 34 | |||
| 35 | void AddDisplay(u64 display_id); | ||
| 36 | void RemoveDisplay(u64 display_id); | ||
| 37 | bool ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id); | ||
| 38 | |||
| 39 | void AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id); | ||
| 40 | void RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id); | ||
| 41 | |||
| 42 | void SetLayerVisibility(s32 consumer_binder_id, bool visible); | ||
| 43 | void SetLayerBlending(s32 consumer_binder_id, LayerBlending blending); | ||
| 44 | |||
| 45 | private: | ||
| 46 | Display* FindDisplay(u64 display_id); | ||
| 47 | Layer* FindLayer(s32 consumer_binder_id); | ||
| 48 | |||
| 49 | public: | ||
| 50 | // TODO: these don't belong here | ||
| 51 | void CreateBufferQueue(s32* out_consumer_binder_id, s32* out_producer_binder_id); | ||
| 52 | void DestroyBufferQueue(s32 consumer_binder_id, s32 producer_binder_id); | ||
| 53 | |||
| 54 | private: | ||
| 55 | Core::System& m_system; | ||
| 56 | HosBinderDriverServer& m_server; | ||
| 57 | KernelHelpers::ServiceContext m_context; | ||
| 58 | |||
| 59 | std::vector<Display> m_displays; | ||
| 60 | std::shared_ptr<Nvidia::Module> nvdrv; | ||
| 61 | s32 disp_fd; | ||
| 62 | HardwareComposer m_composer; | ||
| 63 | }; | ||
| 64 | |||
| 65 | } // namespace Service::Nvnflinger | ||
diff --git a/src/core/hle/service/psc/time/static.cpp b/src/core/hle/service/psc/time/static.cpp index 24b85cc61..9a0adb295 100644 --- a/src/core/hle/service/psc/time/static.cpp +++ b/src/core/hle/service/psc/time/static.cpp | |||
| @@ -144,7 +144,9 @@ Result StaticService::GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value) { | |||
| 144 | 144 | ||
| 145 | Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled( | 145 | Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled( |
| 146 | Out<bool> out_is_enabled) { | 146 | Out<bool> out_is_enabled) { |
| 147 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_enabled={}", *out_is_enabled); }); | 147 | SCOPE_EXIT { |
| 148 | LOG_DEBUG(Service_Time, "called. out_is_enabled={}", *out_is_enabled); | ||
| 149 | }; | ||
| 148 | 150 | ||
| 149 | R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized); | 151 | R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized); |
| 150 | 152 | ||
| @@ -180,7 +182,9 @@ Result StaticService::GetStandardUserSystemClockInitialYear(Out<s32> out_year) { | |||
| 180 | } | 182 | } |
| 181 | 183 | ||
| 182 | Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) { | 184 | Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) { |
| 183 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient); }); | 185 | SCOPE_EXIT { |
| 186 | LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient); | ||
| 187 | }; | ||
| 184 | 188 | ||
| 185 | *out_is_sufficient = m_network_system_clock.IsAccuracySufficient(); | 189 | *out_is_sufficient = m_network_system_clock.IsAccuracySufficient(); |
| 186 | 190 | ||
| @@ -189,7 +193,9 @@ Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> o | |||
| 189 | 193 | ||
| 190 | Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( | 194 | Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( |
| 191 | Out<SteadyClockTimePoint> out_time_point) { | 195 | Out<SteadyClockTimePoint> out_time_point) { |
| 192 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); }); | 196 | SCOPE_EXIT { |
| 197 | LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); | ||
| 198 | }; | ||
| 193 | 199 | ||
| 194 | R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized); | 200 | R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized); |
| 195 | 201 | ||
| @@ -200,7 +206,9 @@ Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( | |||
| 200 | 206 | ||
| 201 | Result StaticService::CalculateMonotonicSystemClockBaseTimePoint( | 207 | Result StaticService::CalculateMonotonicSystemClockBaseTimePoint( |
| 202 | Out<s64> out_time, const SystemClockContext& context) { | 208 | Out<s64> out_time, const SystemClockContext& context) { |
| 203 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); }); | 209 | SCOPE_EXIT { |
| 210 | LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); | ||
| 211 | }; | ||
| 204 | 212 | ||
| 205 | R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized); | 213 | R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized); |
| 206 | 214 | ||
| @@ -219,8 +227,9 @@ Result StaticService::CalculateMonotonicSystemClockBaseTimePoint( | |||
| 219 | } | 227 | } |
| 220 | 228 | ||
| 221 | Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType type) { | 229 | Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType type) { |
| 222 | SCOPE_EXIT( | 230 | SCOPE_EXIT { |
| 223 | { LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot); }); | 231 | LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot); |
| 232 | }; | ||
| 224 | 233 | ||
| 225 | SystemClockContext user_context{}; | 234 | SystemClockContext user_context{}; |
| 226 | R_TRY(m_user_system_clock.GetContext(user_context)); | 235 | R_TRY(m_user_system_clock.GetContext(user_context)); |
| @@ -234,11 +243,11 @@ Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType t | |||
| 234 | Result StaticService::GetClockSnapshotFromSystemClockContext( | 243 | Result StaticService::GetClockSnapshotFromSystemClockContext( |
| 235 | TimeType type, OutClockSnapshot out_snapshot, const SystemClockContext& user_context, | 244 | TimeType type, OutClockSnapshot out_snapshot, const SystemClockContext& user_context, |
| 236 | const SystemClockContext& network_context) { | 245 | const SystemClockContext& network_context) { |
| 237 | SCOPE_EXIT({ | 246 | SCOPE_EXIT { |
| 238 | LOG_DEBUG(Service_Time, | 247 | LOG_DEBUG(Service_Time, |
| 239 | "called. type={} user_context={} network_context={} out_snapshot={}", type, | 248 | "called. type={} user_context={} network_context={} out_snapshot={}", type, |
| 240 | user_context, network_context, *out_snapshot); | 249 | user_context, network_context, *out_snapshot); |
| 241 | }); | 250 | }; |
| 242 | 251 | ||
| 243 | R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type)); | 252 | R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type)); |
| 244 | } | 253 | } |
| @@ -246,9 +255,9 @@ Result StaticService::GetClockSnapshotFromSystemClockContext( | |||
| 246 | Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_difference, | 255 | Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_difference, |
| 247 | InClockSnapshot a, | 256 | InClockSnapshot a, |
| 248 | InClockSnapshot b) { | 257 | InClockSnapshot b) { |
| 249 | SCOPE_EXIT({ | 258 | SCOPE_EXIT { |
| 250 | LOG_DEBUG(Service_Time, "called. a={} b={} out_difference={}", *a, *b, *out_difference); | 259 | LOG_DEBUG(Service_Time, "called. a={} b={} out_difference={}", *a, *b, *out_difference); |
| 251 | }); | 260 | }; |
| 252 | 261 | ||
| 253 | auto diff_s = | 262 | auto diff_s = |
| 254 | std::chrono::seconds(b->user_context.offset) - std::chrono::seconds(a->user_context.offset); | 263 | std::chrono::seconds(b->user_context.offset) - std::chrono::seconds(a->user_context.offset); |
| @@ -276,7 +285,9 @@ Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> | |||
| 276 | 285 | ||
| 277 | Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a, | 286 | Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a, |
| 278 | InClockSnapshot b) { | 287 | InClockSnapshot b) { |
| 279 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); }); | 288 | SCOPE_EXIT { |
| 289 | LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); | ||
| 290 | }; | ||
| 280 | 291 | ||
| 281 | s64 time_s{}; | 292 | s64 time_s{}; |
| 282 | auto res = | 293 | auto res = |
diff --git a/src/core/hle/service/psc/time/steady_clock.cpp b/src/core/hle/service/psc/time/steady_clock.cpp index 948610a2b..78dcf532c 100644 --- a/src/core/hle/service/psc/time/steady_clock.cpp +++ b/src/core/hle/service/psc/time/steady_clock.cpp | |||
| @@ -29,7 +29,9 @@ SteadyClock::SteadyClock(Core::System& system_, std::shared_ptr<TimeManager> man | |||
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | Result SteadyClock::GetCurrentTimePoint(Out<SteadyClockTimePoint> out_time_point) { | 31 | Result SteadyClock::GetCurrentTimePoint(Out<SteadyClockTimePoint> out_time_point) { |
| 32 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); }); | 32 | SCOPE_EXIT { |
| 33 | LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); | ||
| 34 | }; | ||
| 33 | 35 | ||
| 34 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | 36 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), |
| 35 | ResultClockUninitialized); | 37 | ResultClockUninitialized); |
| @@ -38,7 +40,9 @@ Result SteadyClock::GetCurrentTimePoint(Out<SteadyClockTimePoint> out_time_point | |||
| 38 | } | 40 | } |
| 39 | 41 | ||
| 40 | Result SteadyClock::GetTestOffset(Out<s64> out_test_offset) { | 42 | Result SteadyClock::GetTestOffset(Out<s64> out_test_offset) { |
| 41 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_test_offset={}", *out_test_offset); }); | 43 | SCOPE_EXIT { |
| 44 | LOG_DEBUG(Service_Time, "called. out_test_offset={}", *out_test_offset); | ||
| 45 | }; | ||
| 42 | 46 | ||
| 43 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | 47 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), |
| 44 | ResultClockUninitialized); | 48 | ResultClockUninitialized); |
| @@ -59,7 +63,9 @@ Result SteadyClock::SetTestOffset(s64 test_offset) { | |||
| 59 | } | 63 | } |
| 60 | 64 | ||
| 61 | Result SteadyClock::GetRtcValue(Out<s64> out_rtc_value) { | 65 | Result SteadyClock::GetRtcValue(Out<s64> out_rtc_value) { |
| 62 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value); }); | 66 | SCOPE_EXIT { |
| 67 | LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value); | ||
| 68 | }; | ||
| 63 | 69 | ||
| 64 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | 70 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), |
| 65 | ResultClockUninitialized); | 71 | ResultClockUninitialized); |
| @@ -68,7 +74,9 @@ Result SteadyClock::GetRtcValue(Out<s64> out_rtc_value) { | |||
| 68 | } | 74 | } |
| 69 | 75 | ||
| 70 | Result SteadyClock::IsRtcResetDetected(Out<bool> out_is_detected) { | 76 | Result SteadyClock::IsRtcResetDetected(Out<bool> out_is_detected) { |
| 71 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_detected={}", *out_is_detected); }); | 77 | SCOPE_EXIT { |
| 78 | LOG_DEBUG(Service_Time, "called. out_is_detected={}", *out_is_detected); | ||
| 79 | }; | ||
| 72 | 80 | ||
| 73 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | 81 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), |
| 74 | ResultClockUninitialized); | 82 | ResultClockUninitialized); |
| @@ -78,7 +86,9 @@ Result SteadyClock::IsRtcResetDetected(Out<bool> out_is_detected) { | |||
| 78 | } | 86 | } |
| 79 | 87 | ||
| 80 | Result SteadyClock::GetSetupResultValue(Out<Result> out_result) { | 88 | Result SteadyClock::GetSetupResultValue(Out<Result> out_result) { |
| 81 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_result=0x{:X}", out_result->raw); }); | 89 | SCOPE_EXIT { |
| 90 | LOG_DEBUG(Service_Time, "called. out_result=0x{:X}", out_result->raw); | ||
| 91 | }; | ||
| 82 | 92 | ||
| 83 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | 93 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), |
| 84 | ResultClockUninitialized); | 94 | ResultClockUninitialized); |
| @@ -88,8 +98,9 @@ Result SteadyClock::GetSetupResultValue(Out<Result> out_result) { | |||
| 88 | } | 98 | } |
| 89 | 99 | ||
| 90 | Result SteadyClock::GetInternalOffset(Out<s64> out_internal_offset) { | 100 | Result SteadyClock::GetInternalOffset(Out<s64> out_internal_offset) { |
| 91 | SCOPE_EXIT( | 101 | SCOPE_EXIT { |
| 92 | { LOG_DEBUG(Service_Time, "called. out_internal_offset={}", *out_internal_offset); }); | 102 | LOG_DEBUG(Service_Time, "called. out_internal_offset={}", *out_internal_offset); |
| 103 | }; | ||
| 93 | 104 | ||
| 94 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | 105 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), |
| 95 | ResultClockUninitialized); | 106 | ResultClockUninitialized); |
diff --git a/src/core/hle/service/psc/time/system_clock.cpp b/src/core/hle/service/psc/time/system_clock.cpp index b4e9264d8..9f841d8e0 100644 --- a/src/core/hle/service/psc/time/system_clock.cpp +++ b/src/core/hle/service/psc/time/system_clock.cpp | |||
| @@ -26,7 +26,9 @@ SystemClock::SystemClock(Core::System& system_, SystemClockCore& clock_core, boo | |||
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | Result SystemClock::GetCurrentTime(Out<s64> out_time) { | 28 | Result SystemClock::GetCurrentTime(Out<s64> out_time) { |
| 29 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time={}", *out_time); }); | 29 | SCOPE_EXIT { |
| 30 | LOG_DEBUG(Service_Time, "called. out_time={}", *out_time); | ||
| 31 | }; | ||
| 30 | 32 | ||
| 31 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | 33 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), |
| 32 | ResultClockUninitialized); | 34 | ResultClockUninitialized); |
| @@ -45,7 +47,9 @@ Result SystemClock::SetCurrentTime(s64 time) { | |||
| 45 | } | 47 | } |
| 46 | 48 | ||
| 47 | Result SystemClock::GetSystemClockContext(Out<SystemClockContext> out_context) { | 49 | Result SystemClock::GetSystemClockContext(Out<SystemClockContext> out_context) { |
| 48 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_context={}", *out_context); }); | 50 | SCOPE_EXIT { |
| 51 | LOG_DEBUG(Service_Time, "called. out_context={}", *out_context); | ||
| 52 | }; | ||
| 49 | 53 | ||
| 50 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), | 54 | R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), |
| 51 | ResultClockUninitialized); | 55 | ResultClockUninitialized); |
diff --git a/src/core/hle/service/psc/time/time_zone_service.cpp b/src/core/hle/service/psc/time/time_zone_service.cpp index 2f80030a4..9e0674f27 100644 --- a/src/core/hle/service/psc/time/time_zone_service.cpp +++ b/src/core/hle/service/psc/time/time_zone_service.cpp | |||
| @@ -37,7 +37,9 @@ TimeZoneService::TimeZoneService(Core::System& system_, StandardSteadyClockCore& | |||
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | Result TimeZoneService::GetDeviceLocationName(Out<LocationName> out_location_name) { | 39 | Result TimeZoneService::GetDeviceLocationName(Out<LocationName> out_location_name) { |
| 40 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name); }); | 40 | SCOPE_EXIT { |
| 41 | LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name); | ||
| 42 | }; | ||
| 41 | 43 | ||
| 42 | R_RETURN(m_time_zone.GetLocationName(*out_location_name)); | 44 | R_RETURN(m_time_zone.GetLocationName(*out_location_name)); |
| 43 | } | 45 | } |
| @@ -50,7 +52,9 @@ Result TimeZoneService::SetDeviceLocationName(const LocationName& location_name) | |||
| 50 | } | 52 | } |
| 51 | 53 | ||
| 52 | Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) { | 54 | Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) { |
| 53 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_count={}", *out_count); }); | 55 | SCOPE_EXIT { |
| 56 | LOG_DEBUG(Service_Time, "called. out_count={}", *out_count); | ||
| 57 | }; | ||
| 54 | 58 | ||
| 55 | R_RETURN(m_time_zone.GetTotalLocationCount(*out_count)); | 59 | R_RETURN(m_time_zone.GetTotalLocationCount(*out_count)); |
| 56 | } | 60 | } |
| @@ -69,17 +73,19 @@ Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule, const LocationName& l | |||
| 69 | } | 73 | } |
| 70 | 74 | ||
| 71 | Result TimeZoneService::GetTimeZoneRuleVersion(Out<RuleVersion> out_rule_version) { | 75 | Result TimeZoneService::GetTimeZoneRuleVersion(Out<RuleVersion> out_rule_version) { |
| 72 | SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version); }); | 76 | SCOPE_EXIT { |
| 77 | LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version); | ||
| 78 | }; | ||
| 73 | 79 | ||
| 74 | R_RETURN(m_time_zone.GetRuleVersion(*out_rule_version)); | 80 | R_RETURN(m_time_zone.GetRuleVersion(*out_rule_version)); |
| 75 | } | 81 | } |
| 76 | 82 | ||
| 77 | Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime( | 83 | Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime( |
| 78 | Out<LocationName> out_location_name, Out<SteadyClockTimePoint> out_time_point) { | 84 | Out<LocationName> out_location_name, Out<SteadyClockTimePoint> out_time_point) { |
| 79 | SCOPE_EXIT({ | 85 | SCOPE_EXIT { |
| 80 | LOG_DEBUG(Service_Time, "called. out_location_name={} out_time_point={}", | 86 | LOG_DEBUG(Service_Time, "called. out_location_name={} out_time_point={}", |
| 81 | *out_location_name, *out_time_point); | 87 | *out_location_name, *out_time_point); |
| 82 | }); | 88 | }; |
| 83 | 89 | ||
| 84 | R_TRY(m_time_zone.GetLocationName(*out_location_name)); | 90 | R_TRY(m_time_zone.GetLocationName(*out_location_name)); |
| 85 | R_RETURN(m_time_zone.GetTimePoint(*out_time_point)); | 91 | R_RETURN(m_time_zone.GetTimePoint(*out_time_point)); |
| @@ -116,10 +122,10 @@ Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle( | |||
| 116 | Result TimeZoneService::ToCalendarTime(Out<CalendarTime> out_calendar_time, | 122 | Result TimeZoneService::ToCalendarTime(Out<CalendarTime> out_calendar_time, |
| 117 | Out<CalendarAdditionalInfo> out_additional_info, s64 time, | 123 | Out<CalendarAdditionalInfo> out_additional_info, s64 time, |
| 118 | InRule rule) { | 124 | InRule rule) { |
| 119 | SCOPE_EXIT({ | 125 | SCOPE_EXIT { |
| 120 | LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, | 126 | LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, |
| 121 | *out_calendar_time, *out_additional_info); | 127 | *out_calendar_time, *out_additional_info); |
| 122 | }); | 128 | }; |
| 123 | 129 | ||
| 124 | R_RETURN( | 130 | R_RETURN( |
| 125 | m_time_zone.ToCalendarTime(*out_calendar_time, *out_additional_info, time, *rule.Get())); | 131 | m_time_zone.ToCalendarTime(*out_calendar_time, *out_additional_info, time, *rule.Get())); |
| @@ -128,10 +134,10 @@ Result TimeZoneService::ToCalendarTime(Out<CalendarTime> out_calendar_time, | |||
| 128 | Result TimeZoneService::ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_time, | 134 | Result TimeZoneService::ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_time, |
| 129 | Out<CalendarAdditionalInfo> out_additional_info, | 135 | Out<CalendarAdditionalInfo> out_additional_info, |
| 130 | s64 time) { | 136 | s64 time) { |
| 131 | SCOPE_EXIT({ | 137 | SCOPE_EXIT { |
| 132 | LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, | 138 | LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, |
| 133 | *out_calendar_time, *out_additional_info); | 139 | *out_calendar_time, *out_additional_info); |
| 134 | }); | 140 | }; |
| 135 | 141 | ||
| 136 | R_RETURN(m_time_zone.ToCalendarTimeWithMyRule(*out_calendar_time, *out_additional_info, time)); | 142 | R_RETURN(m_time_zone.ToCalendarTimeWithMyRule(*out_calendar_time, *out_additional_info, time)); |
| 137 | } | 143 | } |
| @@ -139,11 +145,11 @@ Result TimeZoneService::ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_ | |||
| 139 | Result TimeZoneService::ToPosixTime(Out<u32> out_count, | 145 | Result TimeZoneService::ToPosixTime(Out<u32> out_count, |
| 140 | OutArray<s64, BufferAttr_HipcPointer> out_times, | 146 | OutArray<s64, BufferAttr_HipcPointer> out_times, |
| 141 | const CalendarTime& calendar_time, InRule rule) { | 147 | const CalendarTime& calendar_time, InRule rule) { |
| 142 | SCOPE_EXIT({ | 148 | SCOPE_EXIT { |
| 143 | LOG_DEBUG(Service_Time, | 149 | LOG_DEBUG(Service_Time, |
| 144 | "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ", | 150 | "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ", |
| 145 | calendar_time, *out_count, out_times[0], out_times[1]); | 151 | calendar_time, *out_count, out_times[0], out_times[1]); |
| 146 | }); | 152 | }; |
| 147 | 153 | ||
| 148 | R_RETURN( | 154 | R_RETURN( |
| 149 | m_time_zone.ToPosixTime(*out_count, out_times, out_times.size(), calendar_time, *rule)); | 155 | m_time_zone.ToPosixTime(*out_count, out_times, out_times.size(), calendar_time, *rule)); |
| @@ -152,11 +158,11 @@ Result TimeZoneService::ToPosixTime(Out<u32> out_count, | |||
| 152 | Result TimeZoneService::ToPosixTimeWithMyRule(Out<u32> out_count, | 158 | Result TimeZoneService::ToPosixTimeWithMyRule(Out<u32> out_count, |
| 153 | OutArray<s64, BufferAttr_HipcPointer> out_times, | 159 | OutArray<s64, BufferAttr_HipcPointer> out_times, |
| 154 | const CalendarTime& calendar_time) { | 160 | const CalendarTime& calendar_time) { |
| 155 | SCOPE_EXIT({ | 161 | SCOPE_EXIT { |
| 156 | LOG_DEBUG(Service_Time, | 162 | LOG_DEBUG(Service_Time, |
| 157 | "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ", | 163 | "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ", |
| 158 | calendar_time, *out_count, out_times[0], out_times[1]); | 164 | calendar_time, *out_count, out_times[0], out_times[1]); |
| 159 | }); | 165 | }; |
| 160 | 166 | ||
| 161 | R_RETURN( | 167 | R_RETURN( |
| 162 | m_time_zone.ToPosixTimeWithMyRule(*out_count, out_times, out_times.size(), calendar_time)); | 168 | m_time_zone.ToPosixTimeWithMyRule(*out_count, out_times, out_times.size(), calendar_time)); |
diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp index 8c7f94c8c..0b41bbcb9 100644 --- a/src/core/hle/service/server_manager.cpp +++ b/src/core/hle/service/server_manager.cpp | |||
| @@ -177,10 +177,10 @@ Result ServerManager::ManageNamedPort(const std::string& service_name, | |||
| 177 | Kernel::KPort::Register(m_system.Kernel(), port); | 177 | Kernel::KPort::Register(m_system.Kernel(), port); |
| 178 | 178 | ||
| 179 | // Ensure that our reference to the port is closed if we fail to register it. | 179 | // Ensure that our reference to the port is closed if we fail to register it. |
| 180 | SCOPE_EXIT({ | 180 | SCOPE_EXIT { |
| 181 | port->GetClientPort().Close(); | 181 | port->GetClientPort().Close(); |
| 182 | port->GetServerPort().Close(); | 182 | port->GetServerPort().Close(); |
| 183 | }); | 183 | }; |
| 184 | 184 | ||
| 185 | // Register the object name with the kernel. | 185 | // Register the object name with the kernel. |
| 186 | R_TRY(Kernel::KObjectName::NewFromName(m_system.Kernel(), std::addressof(port->GetClientPort()), | 186 | R_TRY(Kernel::KObjectName::NewFromName(m_system.Kernel(), std::addressof(port->GetClientPort()), |
| @@ -237,7 +237,9 @@ void ServerManager::StartAdditionalHostThreads(const char* name, size_t num_thre | |||
| 237 | } | 237 | } |
| 238 | 238 | ||
| 239 | Result ServerManager::LoopProcess() { | 239 | Result ServerManager::LoopProcess() { |
| 240 | SCOPE_EXIT({ m_stopped.Set(); }); | 240 | SCOPE_EXIT { |
| 241 | m_stopped.Set(); | ||
| 242 | }; | ||
| 241 | 243 | ||
| 242 | R_RETURN(this->LoopProcessImpl()); | 244 | R_RETURN(this->LoopProcessImpl()); |
| 243 | } | 245 | } |
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index fbdf217ba..ce5e3b5b4 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -7,68 +7,10 @@ | |||
| 7 | #include "common/settings.h" | 7 | #include "common/settings.h" |
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/ipc.h" | 9 | #include "core/hle/ipc.h" |
| 10 | #include "core/hle/kernel/k_process.h" | ||
| 11 | #include "core/hle/kernel/k_server_port.h" | ||
| 12 | #include "core/hle/kernel/kernel.h" | 10 | #include "core/hle/kernel/kernel.h" |
| 13 | #include "core/hle/service/acc/acc.h" | ||
| 14 | #include "core/hle/service/am/am.h" | ||
| 15 | #include "core/hle/service/aoc/aoc_u.h" | ||
| 16 | #include "core/hle/service/apm/apm.h" | ||
| 17 | #include "core/hle/service/audio/audio.h" | ||
| 18 | #include "core/hle/service/bcat/bcat.h" | ||
| 19 | #include "core/hle/service/bpc/bpc.h" | ||
| 20 | #include "core/hle/service/btdrv/btdrv.h" | ||
| 21 | #include "core/hle/service/btm/btm.h" | ||
| 22 | #include "core/hle/service/caps/caps.h" | ||
| 23 | #include "core/hle/service/erpt/erpt.h" | ||
| 24 | #include "core/hle/service/es/es.h" | ||
| 25 | #include "core/hle/service/eupld/eupld.h" | ||
| 26 | #include "core/hle/service/fatal/fatal.h" | ||
| 27 | #include "core/hle/service/fgm/fgm.h" | ||
| 28 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 29 | #include "core/hle/service/friend/friend.h" | ||
| 30 | #include "core/hle/service/glue/glue.h" | ||
| 31 | #include "core/hle/service/grc/grc.h" | ||
| 32 | #include "core/hle/service/hid/hid.h" | ||
| 33 | #include "core/hle/service/ipc_helpers.h" | 11 | #include "core/hle/service/ipc_helpers.h" |
| 34 | #include "core/hle/service/jit/jit.h" | ||
| 35 | #include "core/hle/service/lbl/lbl.h" | ||
| 36 | #include "core/hle/service/ldn/ldn.h" | ||
| 37 | #include "core/hle/service/ldr/ldr.h" | ||
| 38 | #include "core/hle/service/lm/lm.h" | ||
| 39 | #include "core/hle/service/mig/mig.h" | ||
| 40 | #include "core/hle/service/mii/mii.h" | ||
| 41 | #include "core/hle/service/mm/mm_u.h" | ||
| 42 | #include "core/hle/service/mnpp/mnpp_app.h" | ||
| 43 | #include "core/hle/service/ncm/ncm.h" | ||
| 44 | #include "core/hle/service/nfc/nfc.h" | ||
| 45 | #include "core/hle/service/nfp/nfp.h" | ||
| 46 | #include "core/hle/service/ngc/ngc.h" | ||
| 47 | #include "core/hle/service/nifm/nifm.h" | ||
| 48 | #include "core/hle/service/nim/nim.h" | ||
| 49 | #include "core/hle/service/npns/npns.h" | ||
| 50 | #include "core/hle/service/ns/ns.h" | ||
| 51 | #include "core/hle/service/nvdrv/nvdrv.h" | ||
| 52 | #include "core/hle/service/nvnflinger/hos_binder_driver_server.h" | ||
| 53 | #include "core/hle/service/nvnflinger/nvnflinger.h" | ||
| 54 | #include "core/hle/service/olsc/olsc.h" | ||
| 55 | #include "core/hle/service/omm/omm.h" | ||
| 56 | #include "core/hle/service/pcie/pcie.h" | ||
| 57 | #include "core/hle/service/pctl/pctl_module.h" | ||
| 58 | #include "core/hle/service/pcv/pcv.h" | ||
| 59 | #include "core/hle/service/pm/pm.h" | ||
| 60 | #include "core/hle/service/prepo/prepo.h" | ||
| 61 | #include "core/hle/service/psc/psc.h" | ||
| 62 | #include "core/hle/service/ptm/ptm.h" | ||
| 63 | #include "core/hle/service/ro/ro.h" | ||
| 64 | #include "core/hle/service/service.h" | 12 | #include "core/hle/service/service.h" |
| 65 | #include "core/hle/service/set/settings.h" | ||
| 66 | #include "core/hle/service/sm/sm.h" | 13 | #include "core/hle/service/sm/sm.h" |
| 67 | #include "core/hle/service/sockets/sockets.h" | ||
| 68 | #include "core/hle/service/spl/spl_module.h" | ||
| 69 | #include "core/hle/service/ssl/ssl.h" | ||
| 70 | #include "core/hle/service/usb/usb.h" | ||
| 71 | #include "core/hle/service/vi/vi.h" | ||
| 72 | #include "core/reporter.h" | 14 | #include "core/reporter.h" |
| 73 | 15 | ||
| 74 | namespace Service { | 16 | namespace Service { |
| @@ -209,82 +151,4 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session, | |||
| 209 | return result; | 151 | return result; |
| 210 | } | 152 | } |
| 211 | 153 | ||
| 212 | /// Initialize Services | ||
| 213 | Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) | ||
| 214 | : hos_binder_driver_server{std::make_unique<Nvnflinger::HosBinderDriverServer>(system)}, | ||
| 215 | nv_flinger{std::make_unique<Nvnflinger::Nvnflinger>(system, *hos_binder_driver_server)} { | ||
| 216 | |||
| 217 | auto& kernel = system.Kernel(); | ||
| 218 | |||
| 219 | // Nvnflinger needs to be accessed by several services like Vi and AppletOE so we instantiate it | ||
| 220 | // here and pass it into the respective InstallInterfaces functions. | ||
| 221 | system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); | ||
| 222 | |||
| 223 | // clang-format off | ||
| 224 | kernel.RunOnHostCoreProcess("audio", [&] { Audio::LoopProcess(system); }).detach(); | ||
| 225 | kernel.RunOnHostCoreProcess("FS", [&] { FileSystem::LoopProcess(system); }).detach(); | ||
| 226 | kernel.RunOnHostCoreProcess("jit", [&] { JIT::LoopProcess(system); }).detach(); | ||
| 227 | kernel.RunOnHostCoreProcess("ldn", [&] { LDN::LoopProcess(system); }).detach(); | ||
| 228 | kernel.RunOnHostCoreProcess("Loader", [&] { LDR::LoopProcess(system); }).detach(); | ||
| 229 | kernel.RunOnHostCoreProcess("nvservices", [&] { Nvidia::LoopProcess(*nv_flinger, system); }).detach(); | ||
| 230 | kernel.RunOnHostCoreProcess("bsdsocket", [&] { Sockets::LoopProcess(system); }).detach(); | ||
| 231 | kernel.RunOnHostCoreProcess("vi", [&] { VI::LoopProcess(system, *nv_flinger, *hos_binder_driver_server); }).detach(); | ||
| 232 | |||
| 233 | kernel.RunOnGuestCoreProcess("sm", [&] { SM::LoopProcess(system); }); | ||
| 234 | kernel.RunOnGuestCoreProcess("account", [&] { Account::LoopProcess(system); }); | ||
| 235 | kernel.RunOnGuestCoreProcess("am", [&] { AM::LoopProcess(*nv_flinger, system); }); | ||
| 236 | kernel.RunOnGuestCoreProcess("aoc", [&] { AOC::LoopProcess(system); }); | ||
| 237 | kernel.RunOnGuestCoreProcess("apm", [&] { APM::LoopProcess(system); }); | ||
| 238 | kernel.RunOnGuestCoreProcess("bcat", [&] { BCAT::LoopProcess(system); }); | ||
| 239 | kernel.RunOnGuestCoreProcess("bpc", [&] { BPC::LoopProcess(system); }); | ||
| 240 | kernel.RunOnGuestCoreProcess("btdrv", [&] { BtDrv::LoopProcess(system); }); | ||
| 241 | kernel.RunOnGuestCoreProcess("btm", [&] { BTM::LoopProcess(system); }); | ||
| 242 | kernel.RunOnGuestCoreProcess("capsrv", [&] { Capture::LoopProcess(system); }); | ||
| 243 | kernel.RunOnGuestCoreProcess("erpt", [&] { ERPT::LoopProcess(system); }); | ||
| 244 | kernel.RunOnGuestCoreProcess("es", [&] { ES::LoopProcess(system); }); | ||
| 245 | kernel.RunOnGuestCoreProcess("eupld", [&] { EUPLD::LoopProcess(system); }); | ||
| 246 | kernel.RunOnGuestCoreProcess("fatal", [&] { Fatal::LoopProcess(system); }); | ||
| 247 | kernel.RunOnGuestCoreProcess("fgm", [&] { FGM::LoopProcess(system); }); | ||
| 248 | kernel.RunOnGuestCoreProcess("friends", [&] { Friend::LoopProcess(system); }); | ||
| 249 | // glue depends on settings and psc, so they must come first | ||
| 250 | kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); }); | ||
| 251 | kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); }); | ||
| 252 | kernel.RunOnGuestCoreProcess("glue", [&] { Glue::LoopProcess(system); }); | ||
| 253 | kernel.RunOnGuestCoreProcess("grc", [&] { GRC::LoopProcess(system); }); | ||
| 254 | kernel.RunOnGuestCoreProcess("hid", [&] { HID::LoopProcess(system); }); | ||
| 255 | kernel.RunOnGuestCoreProcess("lbl", [&] { LBL::LoopProcess(system); }); | ||
| 256 | kernel.RunOnGuestCoreProcess("LogManager.Prod", [&] { LM::LoopProcess(system); }); | ||
| 257 | kernel.RunOnGuestCoreProcess("mig", [&] { Migration::LoopProcess(system); }); | ||
| 258 | kernel.RunOnGuestCoreProcess("mii", [&] { Mii::LoopProcess(system); }); | ||
| 259 | kernel.RunOnGuestCoreProcess("mm", [&] { MM::LoopProcess(system); }); | ||
| 260 | kernel.RunOnGuestCoreProcess("mnpp", [&] { MNPP::LoopProcess(system); }); | ||
| 261 | kernel.RunOnGuestCoreProcess("NCM", [&] { NCM::LoopProcess(system); }); | ||
| 262 | kernel.RunOnGuestCoreProcess("nfc", [&] { NFC::LoopProcess(system); }); | ||
| 263 | kernel.RunOnGuestCoreProcess("nfp", [&] { NFP::LoopProcess(system); }); | ||
| 264 | kernel.RunOnGuestCoreProcess("ngc", [&] { NGC::LoopProcess(system); }); | ||
| 265 | kernel.RunOnGuestCoreProcess("nifm", [&] { NIFM::LoopProcess(system); }); | ||
| 266 | kernel.RunOnGuestCoreProcess("nim", [&] { NIM::LoopProcess(system); }); | ||
| 267 | kernel.RunOnGuestCoreProcess("npns", [&] { NPNS::LoopProcess(system); }); | ||
| 268 | kernel.RunOnGuestCoreProcess("ns", [&] { NS::LoopProcess(system); }); | ||
| 269 | kernel.RunOnGuestCoreProcess("olsc", [&] { OLSC::LoopProcess(system); }); | ||
| 270 | kernel.RunOnGuestCoreProcess("omm", [&] { OMM::LoopProcess(system); }); | ||
| 271 | kernel.RunOnGuestCoreProcess("pcie", [&] { PCIe::LoopProcess(system); }); | ||
| 272 | kernel.RunOnGuestCoreProcess("pctl", [&] { PCTL::LoopProcess(system); }); | ||
| 273 | kernel.RunOnGuestCoreProcess("pcv", [&] { PCV::LoopProcess(system); }); | ||
| 274 | kernel.RunOnGuestCoreProcess("prepo", [&] { PlayReport::LoopProcess(system); }); | ||
| 275 | kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); }); | ||
| 276 | kernel.RunOnGuestCoreProcess("ptm", [&] { PTM::LoopProcess(system); }); | ||
| 277 | kernel.RunOnGuestCoreProcess("ro", [&] { RO::LoopProcess(system); }); | ||
| 278 | kernel.RunOnGuestCoreProcess("spl", [&] { SPL::LoopProcess(system); }); | ||
| 279 | kernel.RunOnGuestCoreProcess("ssl", [&] { SSL::LoopProcess(system); }); | ||
| 280 | kernel.RunOnGuestCoreProcess("usb", [&] { USB::LoopProcess(system); }); | ||
| 281 | // clang-format on | ||
| 282 | } | ||
| 283 | |||
| 284 | Services::~Services() = default; | ||
| 285 | |||
| 286 | void Services::KillNVNFlinger() { | ||
| 287 | nv_flinger->ShutdownLayers(); | ||
| 288 | } | ||
| 289 | |||
| 290 | } // namespace Service | 154 | } // namespace Service |
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 22d1343d5..36aae1c79 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h | |||
| @@ -28,11 +28,6 @@ namespace FileSystem { | |||
| 28 | class FileSystemController; | 28 | class FileSystemController; |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | namespace Nvnflinger { | ||
| 32 | class HosBinderDriverServer; | ||
| 33 | class Nvnflinger; | ||
| 34 | } // namespace Nvnflinger | ||
| 35 | |||
| 36 | namespace SM { | 31 | namespace SM { |
| 37 | class ServiceManager; | 32 | class ServiceManager; |
| 38 | } | 33 | } |
| @@ -236,20 +231,4 @@ private: | |||
| 236 | } | 231 | } |
| 237 | }; | 232 | }; |
| 238 | 233 | ||
| 239 | /** | ||
| 240 | * The purpose of this class is to own any objects that need to be shared across the other service | ||
| 241 | * implementations. Will be torn down when the global system instance is shutdown. | ||
| 242 | */ | ||
| 243 | class Services final { | ||
| 244 | public: | ||
| 245 | explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system); | ||
| 246 | ~Services(); | ||
| 247 | |||
| 248 | void KillNVNFlinger(); | ||
| 249 | |||
| 250 | private: | ||
| 251 | std::unique_ptr<Nvnflinger::HosBinderDriverServer> hos_binder_driver_server; | ||
| 252 | std::unique_ptr<Nvnflinger::Nvnflinger> nv_flinger; | ||
| 253 | }; | ||
| 254 | |||
| 255 | } // namespace Service | 234 | } // namespace Service |
diff --git a/src/core/hle/service/services.cpp b/src/core/hle/service/services.cpp new file mode 100644 index 000000000..d6c6eff50 --- /dev/null +++ b/src/core/hle/service/services.cpp | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/services.h" | ||
| 5 | |||
| 6 | #include "core/hle/service/acc/acc.h" | ||
| 7 | #include "core/hle/service/am/am.h" | ||
| 8 | #include "core/hle/service/aoc/aoc_u.h" | ||
| 9 | #include "core/hle/service/apm/apm.h" | ||
| 10 | #include "core/hle/service/audio/audio.h" | ||
| 11 | #include "core/hle/service/bcat/bcat.h" | ||
| 12 | #include "core/hle/service/bpc/bpc.h" | ||
| 13 | #include "core/hle/service/btdrv/btdrv.h" | ||
| 14 | #include "core/hle/service/btm/btm.h" | ||
| 15 | #include "core/hle/service/caps/caps.h" | ||
| 16 | #include "core/hle/service/erpt/erpt.h" | ||
| 17 | #include "core/hle/service/es/es.h" | ||
| 18 | #include "core/hle/service/eupld/eupld.h" | ||
| 19 | #include "core/hle/service/fatal/fatal.h" | ||
| 20 | #include "core/hle/service/fgm/fgm.h" | ||
| 21 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 22 | #include "core/hle/service/friend/friend.h" | ||
| 23 | #include "core/hle/service/glue/glue.h" | ||
| 24 | #include "core/hle/service/grc/grc.h" | ||
| 25 | #include "core/hle/service/hid/hid.h" | ||
| 26 | #include "core/hle/service/ipc_helpers.h" | ||
| 27 | #include "core/hle/service/jit/jit.h" | ||
| 28 | #include "core/hle/service/lbl/lbl.h" | ||
| 29 | #include "core/hle/service/ldn/ldn.h" | ||
| 30 | #include "core/hle/service/ldr/ldr.h" | ||
| 31 | #include "core/hle/service/lm/lm.h" | ||
| 32 | #include "core/hle/service/mig/mig.h" | ||
| 33 | #include "core/hle/service/mii/mii.h" | ||
| 34 | #include "core/hle/service/mm/mm_u.h" | ||
| 35 | #include "core/hle/service/mnpp/mnpp_app.h" | ||
| 36 | #include "core/hle/service/ncm/ncm.h" | ||
| 37 | #include "core/hle/service/nfc/nfc.h" | ||
| 38 | #include "core/hle/service/nfp/nfp.h" | ||
| 39 | #include "core/hle/service/ngc/ngc.h" | ||
| 40 | #include "core/hle/service/nifm/nifm.h" | ||
| 41 | #include "core/hle/service/nim/nim.h" | ||
| 42 | #include "core/hle/service/npns/npns.h" | ||
| 43 | #include "core/hle/service/ns/ns.h" | ||
| 44 | #include "core/hle/service/nvdrv/nvdrv.h" | ||
| 45 | #include "core/hle/service/nvnflinger/nvnflinger.h" | ||
| 46 | #include "core/hle/service/olsc/olsc.h" | ||
| 47 | #include "core/hle/service/omm/omm.h" | ||
| 48 | #include "core/hle/service/pcie/pcie.h" | ||
| 49 | #include "core/hle/service/pctl/pctl_module.h" | ||
| 50 | #include "core/hle/service/pcv/pcv.h" | ||
| 51 | #include "core/hle/service/pm/pm.h" | ||
| 52 | #include "core/hle/service/prepo/prepo.h" | ||
| 53 | #include "core/hle/service/psc/psc.h" | ||
| 54 | #include "core/hle/service/ptm/ptm.h" | ||
| 55 | #include "core/hle/service/ro/ro.h" | ||
| 56 | #include "core/hle/service/service.h" | ||
| 57 | #include "core/hle/service/set/settings.h" | ||
| 58 | #include "core/hle/service/sm/sm.h" | ||
| 59 | #include "core/hle/service/sockets/sockets.h" | ||
| 60 | #include "core/hle/service/spl/spl_module.h" | ||
| 61 | #include "core/hle/service/ssl/ssl.h" | ||
| 62 | #include "core/hle/service/usb/usb.h" | ||
| 63 | #include "core/hle/service/vi/vi.h" | ||
| 64 | |||
| 65 | namespace Service { | ||
| 66 | |||
| 67 | Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system, | ||
| 68 | std::stop_token token) { | ||
| 69 | auto& kernel = system.Kernel(); | ||
| 70 | |||
| 71 | system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); | ||
| 72 | |||
| 73 | // clang-format off | ||
| 74 | kernel.RunOnHostCoreProcess("audio", [&] { Audio::LoopProcess(system); }).detach(); | ||
| 75 | kernel.RunOnHostCoreProcess("FS", [&] { FileSystem::LoopProcess(system); }).detach(); | ||
| 76 | kernel.RunOnHostCoreProcess("jit", [&] { JIT::LoopProcess(system); }).detach(); | ||
| 77 | kernel.RunOnHostCoreProcess("ldn", [&] { LDN::LoopProcess(system); }).detach(); | ||
| 78 | kernel.RunOnHostCoreProcess("Loader", [&] { LDR::LoopProcess(system); }).detach(); | ||
| 79 | kernel.RunOnHostCoreProcess("nvservices", [&] { Nvidia::LoopProcess(system); }).detach(); | ||
| 80 | kernel.RunOnHostCoreProcess("bsdsocket", [&] { Sockets::LoopProcess(system); }).detach(); | ||
| 81 | kernel.RunOnHostCoreProcess("vi", [&, token] { VI::LoopProcess(system, token); }).detach(); | ||
| 82 | |||
| 83 | kernel.RunOnGuestCoreProcess("sm", [&] { SM::LoopProcess(system); }); | ||
| 84 | kernel.RunOnGuestCoreProcess("account", [&] { Account::LoopProcess(system); }); | ||
| 85 | kernel.RunOnGuestCoreProcess("am", [&] { AM::LoopProcess(system); }); | ||
| 86 | kernel.RunOnGuestCoreProcess("aoc", [&] { AOC::LoopProcess(system); }); | ||
| 87 | kernel.RunOnGuestCoreProcess("apm", [&] { APM::LoopProcess(system); }); | ||
| 88 | kernel.RunOnGuestCoreProcess("bcat", [&] { BCAT::LoopProcess(system); }); | ||
| 89 | kernel.RunOnGuestCoreProcess("bpc", [&] { BPC::LoopProcess(system); }); | ||
| 90 | kernel.RunOnGuestCoreProcess("btdrv", [&] { BtDrv::LoopProcess(system); }); | ||
| 91 | kernel.RunOnGuestCoreProcess("btm", [&] { BTM::LoopProcess(system); }); | ||
| 92 | kernel.RunOnGuestCoreProcess("capsrv", [&] { Capture::LoopProcess(system); }); | ||
| 93 | kernel.RunOnGuestCoreProcess("erpt", [&] { ERPT::LoopProcess(system); }); | ||
| 94 | kernel.RunOnGuestCoreProcess("es", [&] { ES::LoopProcess(system); }); | ||
| 95 | kernel.RunOnGuestCoreProcess("eupld", [&] { EUPLD::LoopProcess(system); }); | ||
| 96 | kernel.RunOnGuestCoreProcess("fatal", [&] { Fatal::LoopProcess(system); }); | ||
| 97 | kernel.RunOnGuestCoreProcess("fgm", [&] { FGM::LoopProcess(system); }); | ||
| 98 | kernel.RunOnGuestCoreProcess("friends", [&] { Friend::LoopProcess(system); }); | ||
| 99 | kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); }); | ||
| 100 | kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); }); | ||
| 101 | kernel.RunOnGuestCoreProcess("glue", [&] { Glue::LoopProcess(system); }); | ||
| 102 | kernel.RunOnGuestCoreProcess("grc", [&] { GRC::LoopProcess(system); }); | ||
| 103 | kernel.RunOnGuestCoreProcess("hid", [&] { HID::LoopProcess(system); }); | ||
| 104 | kernel.RunOnGuestCoreProcess("lbl", [&] { LBL::LoopProcess(system); }); | ||
| 105 | kernel.RunOnGuestCoreProcess("LogManager.Prod", [&] { LM::LoopProcess(system); }); | ||
| 106 | kernel.RunOnGuestCoreProcess("mig", [&] { Migration::LoopProcess(system); }); | ||
| 107 | kernel.RunOnGuestCoreProcess("mii", [&] { Mii::LoopProcess(system); }); | ||
| 108 | kernel.RunOnGuestCoreProcess("mm", [&] { MM::LoopProcess(system); }); | ||
| 109 | kernel.RunOnGuestCoreProcess("mnpp", [&] { MNPP::LoopProcess(system); }); | ||
| 110 | kernel.RunOnGuestCoreProcess("nvnflinger", [&] { Nvnflinger::LoopProcess(system); }); | ||
| 111 | kernel.RunOnGuestCoreProcess("NCM", [&] { NCM::LoopProcess(system); }); | ||
| 112 | kernel.RunOnGuestCoreProcess("nfc", [&] { NFC::LoopProcess(system); }); | ||
| 113 | kernel.RunOnGuestCoreProcess("nfp", [&] { NFP::LoopProcess(system); }); | ||
| 114 | kernel.RunOnGuestCoreProcess("ngc", [&] { NGC::LoopProcess(system); }); | ||
| 115 | kernel.RunOnGuestCoreProcess("nifm", [&] { NIFM::LoopProcess(system); }); | ||
| 116 | kernel.RunOnGuestCoreProcess("nim", [&] { NIM::LoopProcess(system); }); | ||
| 117 | kernel.RunOnGuestCoreProcess("npns", [&] { NPNS::LoopProcess(system); }); | ||
| 118 | kernel.RunOnGuestCoreProcess("ns", [&] { NS::LoopProcess(system); }); | ||
| 119 | kernel.RunOnGuestCoreProcess("olsc", [&] { OLSC::LoopProcess(system); }); | ||
| 120 | kernel.RunOnGuestCoreProcess("omm", [&] { OMM::LoopProcess(system); }); | ||
| 121 | kernel.RunOnGuestCoreProcess("pcie", [&] { PCIe::LoopProcess(system); }); | ||
| 122 | kernel.RunOnGuestCoreProcess("pctl", [&] { PCTL::LoopProcess(system); }); | ||
| 123 | kernel.RunOnGuestCoreProcess("pcv", [&] { PCV::LoopProcess(system); }); | ||
| 124 | kernel.RunOnGuestCoreProcess("prepo", [&] { PlayReport::LoopProcess(system); }); | ||
| 125 | kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); }); | ||
| 126 | kernel.RunOnGuestCoreProcess("ptm", [&] { PTM::LoopProcess(system); }); | ||
| 127 | kernel.RunOnGuestCoreProcess("ro", [&] { RO::LoopProcess(system); }); | ||
| 128 | kernel.RunOnGuestCoreProcess("spl", [&] { SPL::LoopProcess(system); }); | ||
| 129 | kernel.RunOnGuestCoreProcess("ssl", [&] { SSL::LoopProcess(system); }); | ||
| 130 | kernel.RunOnGuestCoreProcess("usb", [&] { USB::LoopProcess(system); }); | ||
| 131 | // clang-format on | ||
| 132 | } | ||
| 133 | |||
| 134 | Services::~Services() = default; | ||
| 135 | |||
| 136 | } // namespace Service | ||
diff --git a/src/core/hle/service/services.h b/src/core/hle/service/services.h new file mode 100644 index 000000000..a99fa1e53 --- /dev/null +++ b/src/core/hle/service/services.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/polyfill_thread.h" | ||
| 7 | #include "core/hle/service/sm/sm.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | |||
| 11 | /** | ||
| 12 | * The purpose of this class is to own any objects that need to be shared across the other service | ||
| 13 | * implementations. Will be torn down when the global system instance is shutdown. | ||
| 14 | */ | ||
| 15 | class Services final { | ||
| 16 | public: | ||
| 17 | explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system, | ||
| 18 | std::stop_token token); | ||
| 19 | ~Services(); | ||
| 20 | }; | ||
| 21 | |||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/vi/application_display_service.cpp b/src/core/hle/service/vi/application_display_service.cpp index 78229e30f..6b0bcb536 100644 --- a/src/core/hle/service/vi/application_display_service.cpp +++ b/src/core/hle/service/vi/application_display_service.cpp | |||
| @@ -2,22 +2,21 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "core/hle/service/cmif_serialization.h" | 4 | #include "core/hle/service/cmif_serialization.h" |
| 5 | #include "core/hle/service/nvnflinger/nvnflinger.h" | 5 | #include "core/hle/service/nvnflinger/hos_binder_driver.h" |
| 6 | #include "core/hle/service/nvnflinger/parcel.h" | 6 | #include "core/hle/service/nvnflinger/parcel.h" |
| 7 | #include "core/hle/service/os/event.h" | ||
| 7 | #include "core/hle/service/vi/application_display_service.h" | 8 | #include "core/hle/service/vi/application_display_service.h" |
| 8 | #include "core/hle/service/vi/hos_binder_driver.h" | 9 | #include "core/hle/service/vi/container.h" |
| 9 | #include "core/hle/service/vi/manager_display_service.h" | 10 | #include "core/hle/service/vi/manager_display_service.h" |
| 10 | #include "core/hle/service/vi/system_display_service.h" | 11 | #include "core/hle/service/vi/system_display_service.h" |
| 11 | #include "core/hle/service/vi/vi_results.h" | 12 | #include "core/hle/service/vi/vi_results.h" |
| 12 | 13 | ||
| 13 | namespace Service::VI { | 14 | namespace Service::VI { |
| 14 | 15 | ||
| 15 | IApplicationDisplayService::IApplicationDisplayService( | 16 | IApplicationDisplayService::IApplicationDisplayService(Core::System& system_, |
| 16 | Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, | 17 | std::shared_ptr<Container> container) |
| 17 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) | 18 | : ServiceFramework{system_, "IApplicationDisplayService"}, |
| 18 | : ServiceFramework{system_, "IApplicationDisplayService"}, m_nvnflinger{nvnflinger}, | 19 | m_container{std::move(container)}, m_context{system, "IApplicationDisplayService"} { |
| 19 | m_hos_binder_driver_server{hos_binder_driver_server} { | ||
| 20 | |||
| 21 | // clang-format off | 20 | // clang-format off |
| 22 | static const FunctionInfo functions[] = { | 21 | static const FunctionInfo functions[] = { |
| 23 | {100, C<&IApplicationDisplayService::GetRelayService>, "GetRelayService"}, | 22 | {100, C<&IApplicationDisplayService::GetRelayService>, "GetRelayService"}, |
| @@ -48,38 +47,41 @@ IApplicationDisplayService::IApplicationDisplayService( | |||
| 48 | } | 47 | } |
| 49 | 48 | ||
| 50 | IApplicationDisplayService::~IApplicationDisplayService() { | 49 | IApplicationDisplayService::~IApplicationDisplayService() { |
| 50 | for (auto& [display_id, event] : m_display_vsync_events) { | ||
| 51 | m_container->UnlinkVsyncEvent(display_id, &event); | ||
| 52 | } | ||
| 53 | for (const auto layer_id : m_open_layer_ids) { | ||
| 54 | m_container->CloseLayer(layer_id); | ||
| 55 | } | ||
| 51 | for (const auto layer_id : m_stray_layer_ids) { | 56 | for (const auto layer_id : m_stray_layer_ids) { |
| 52 | m_nvnflinger.DestroyLayer(layer_id); | 57 | m_container->DestroyStrayLayer(layer_id); |
| 53 | } | 58 | } |
| 54 | } | 59 | } |
| 55 | 60 | ||
| 56 | Result IApplicationDisplayService::GetRelayService( | 61 | Result IApplicationDisplayService::GetRelayService( |
| 57 | Out<SharedPointer<IHOSBinderDriver>> out_relay_service) { | 62 | Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_relay_service) { |
| 58 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 63 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 59 | *out_relay_service = std::make_shared<IHOSBinderDriver>(system, m_hos_binder_driver_server); | 64 | R_RETURN(m_container->GetBinderDriver(out_relay_service)); |
| 60 | R_SUCCEED(); | ||
| 61 | } | 65 | } |
| 62 | 66 | ||
| 63 | Result IApplicationDisplayService::GetSystemDisplayService( | 67 | Result IApplicationDisplayService::GetSystemDisplayService( |
| 64 | Out<SharedPointer<ISystemDisplayService>> out_system_display_service) { | 68 | Out<SharedPointer<ISystemDisplayService>> out_system_display_service) { |
| 65 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 69 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 66 | *out_system_display_service = std::make_shared<ISystemDisplayService>(system, m_nvnflinger); | 70 | *out_system_display_service = std::make_shared<ISystemDisplayService>(system, m_container); |
| 67 | R_SUCCEED(); | 71 | R_SUCCEED(); |
| 68 | } | 72 | } |
| 69 | 73 | ||
| 70 | Result IApplicationDisplayService::GetManagerDisplayService( | 74 | Result IApplicationDisplayService::GetManagerDisplayService( |
| 71 | Out<SharedPointer<IManagerDisplayService>> out_manager_display_service) { | 75 | Out<SharedPointer<IManagerDisplayService>> out_manager_display_service) { |
| 72 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 76 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 73 | *out_manager_display_service = std::make_shared<IManagerDisplayService>(system, m_nvnflinger); | 77 | *out_manager_display_service = std::make_shared<IManagerDisplayService>(system, m_container); |
| 74 | R_SUCCEED(); | 78 | R_SUCCEED(); |
| 75 | } | 79 | } |
| 76 | 80 | ||
| 77 | Result IApplicationDisplayService::GetIndirectDisplayTransactionService( | 81 | Result IApplicationDisplayService::GetIndirectDisplayTransactionService( |
| 78 | Out<SharedPointer<IHOSBinderDriver>> out_indirect_display_transaction_service) { | 82 | Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_indirect_display_transaction_service) { |
| 79 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 83 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 80 | *out_indirect_display_transaction_service = | 84 | R_RETURN(m_container->GetBinderDriver(out_indirect_display_transaction_service)); |
| 81 | std::make_shared<IHOSBinderDriver>(system, m_hos_binder_driver_server); | ||
| 82 | R_SUCCEED(); | ||
| 83 | } | 85 | } |
| 84 | 86 | ||
| 85 | Result IApplicationDisplayService::OpenDisplay(Out<u64> out_display_id, DisplayName display_name) { | 87 | Result IApplicationDisplayService::OpenDisplay(Out<u64> out_display_id, DisplayName display_name) { |
| @@ -89,14 +91,7 @@ Result IApplicationDisplayService::OpenDisplay(Out<u64> out_display_id, DisplayN | |||
| 89 | ASSERT_MSG(strcmp(display_name.data(), "Default") == 0, | 91 | ASSERT_MSG(strcmp(display_name.data(), "Default") == 0, |
| 90 | "Non-default displays aren't supported yet"); | 92 | "Non-default displays aren't supported yet"); |
| 91 | 93 | ||
| 92 | const auto display_id = m_nvnflinger.OpenDisplay(display_name.data()); | 94 | R_RETURN(m_container->OpenDisplay(out_display_id, display_name)); |
| 93 | if (!display_id) { | ||
| 94 | LOG_ERROR(Service_VI, "Display not found! display_name={}", display_name.data()); | ||
| 95 | R_THROW(VI::ResultNotFound); | ||
| 96 | } | ||
| 97 | |||
| 98 | *out_display_id = *display_id; | ||
| 99 | R_SUCCEED(); | ||
| 100 | } | 95 | } |
| 101 | 96 | ||
| 102 | Result IApplicationDisplayService::OpenDefaultDisplay(Out<u64> out_display_id) { | 97 | Result IApplicationDisplayService::OpenDefaultDisplay(Out<u64> out_display_id) { |
| @@ -106,8 +101,7 @@ Result IApplicationDisplayService::OpenDefaultDisplay(Out<u64> out_display_id) { | |||
| 106 | 101 | ||
| 107 | Result IApplicationDisplayService::CloseDisplay(u64 display_id) { | 102 | Result IApplicationDisplayService::CloseDisplay(u64 display_id) { |
| 108 | LOG_DEBUG(Service_VI, "called"); | 103 | LOG_DEBUG(Service_VI, "called"); |
| 109 | R_SUCCEED_IF(m_nvnflinger.CloseDisplay(display_id)); | 104 | R_RETURN(m_container->CloseDisplay(display_id)); |
| 110 | R_THROW(ResultUnknown); | ||
| 111 | } | 105 | } |
| 112 | 106 | ||
| 113 | Result IApplicationDisplayService::SetDisplayEnabled(u32 state, u64 display_id) { | 107 | Result IApplicationDisplayService::SetDisplayEnabled(u32 state, u64 display_id) { |
| @@ -168,25 +162,19 @@ Result IApplicationDisplayService::OpenLayer(Out<u64> out_size, | |||
| 168 | 162 | ||
| 169 | LOG_DEBUG(Service_VI, "called. layer_id={}, aruid={:#x}", layer_id, aruid.pid); | 163 | LOG_DEBUG(Service_VI, "called. layer_id={}, aruid={:#x}", layer_id, aruid.pid); |
| 170 | 164 | ||
| 171 | const auto display_id = m_nvnflinger.OpenDisplay(display_name.data()); | 165 | u64 display_id; |
| 172 | if (!display_id) { | 166 | R_TRY(m_container->OpenDisplay(&display_id, display_name)); |
| 173 | LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id); | ||
| 174 | R_THROW(VI::ResultNotFound); | ||
| 175 | } | ||
| 176 | 167 | ||
| 177 | const auto buffer_queue_id = m_nvnflinger.FindBufferQueueId(*display_id, layer_id); | 168 | s32 producer_binder_id; |
| 178 | if (!buffer_queue_id) { | 169 | R_TRY(m_container->OpenLayer(&producer_binder_id, layer_id, aruid.pid)); |
| 179 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id); | ||
| 180 | R_THROW(VI::ResultNotFound); | ||
| 181 | } | ||
| 182 | 170 | ||
| 183 | if (!m_nvnflinger.OpenLayer(layer_id)) { | 171 | { |
| 184 | LOG_WARNING(Service_VI, "Tried to open layer which was already open"); | 172 | std::scoped_lock lk{m_lock}; |
| 185 | R_THROW(VI::ResultOperationFailed); | 173 | m_open_layer_ids.insert(layer_id); |
| 186 | } | 174 | } |
| 187 | 175 | ||
| 188 | android::OutputParcel parcel; | 176 | android::OutputParcel parcel; |
| 189 | parcel.WriteInterface(NativeWindow{*buffer_queue_id}); | 177 | parcel.WriteInterface(NativeWindow{producer_binder_id}); |
| 190 | 178 | ||
| 191 | const auto buffer = parcel.Serialize(); | 179 | const auto buffer = parcel.Serialize(); |
| 192 | std::memcpy(out_native_window.data(), buffer.data(), | 180 | std::memcpy(out_native_window.data(), buffer.data(), |
| @@ -199,12 +187,13 @@ Result IApplicationDisplayService::OpenLayer(Out<u64> out_size, | |||
| 199 | Result IApplicationDisplayService::CloseLayer(u64 layer_id) { | 187 | Result IApplicationDisplayService::CloseLayer(u64 layer_id) { |
| 200 | LOG_DEBUG(Service_VI, "called. layer_id={}", layer_id); | 188 | LOG_DEBUG(Service_VI, "called. layer_id={}", layer_id); |
| 201 | 189 | ||
| 202 | if (!m_nvnflinger.CloseLayer(layer_id)) { | 190 | { |
| 203 | LOG_WARNING(Service_VI, "Tried to close layer which was not open"); | 191 | std::scoped_lock lk{m_lock}; |
| 204 | R_THROW(VI::ResultOperationFailed); | 192 | R_UNLESS(m_open_layer_ids.contains(layer_id), VI::ResultNotFound); |
| 193 | m_open_layer_ids.erase(layer_id); | ||
| 205 | } | 194 | } |
| 206 | 195 | ||
| 207 | R_SUCCEED(); | 196 | R_RETURN(m_container->CloseLayer(layer_id)); |
| 208 | } | 197 | } |
| 209 | 198 | ||
| 210 | Result IApplicationDisplayService::CreateStrayLayer( | 199 | Result IApplicationDisplayService::CreateStrayLayer( |
| @@ -212,27 +201,19 @@ Result IApplicationDisplayService::CreateStrayLayer( | |||
| 212 | u32 flags, u64 display_id) { | 201 | u32 flags, u64 display_id) { |
| 213 | LOG_DEBUG(Service_VI, "called. flags={}, display_id={}", flags, display_id); | 202 | LOG_DEBUG(Service_VI, "called. flags={}, display_id={}", flags, display_id); |
| 214 | 203 | ||
| 215 | const auto layer_id = m_nvnflinger.CreateLayer(display_id); | 204 | s32 producer_binder_id; |
| 216 | if (!layer_id) { | 205 | R_TRY(m_container->CreateStrayLayer(&producer_binder_id, out_layer_id, display_id)); |
| 217 | LOG_ERROR(Service_VI, "Layer not found! display_id={}", display_id); | ||
| 218 | R_THROW(VI::ResultNotFound); | ||
| 219 | } | ||
| 220 | 206 | ||
| 221 | m_stray_layer_ids.push_back(*layer_id); | 207 | std::scoped_lock lk{m_lock}; |
| 222 | const auto buffer_queue_id = m_nvnflinger.FindBufferQueueId(display_id, *layer_id); | 208 | m_stray_layer_ids.insert(*out_layer_id); |
| 223 | if (!buffer_queue_id) { | ||
| 224 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); | ||
| 225 | R_THROW(VI::ResultNotFound); | ||
| 226 | } | ||
| 227 | 209 | ||
| 228 | android::OutputParcel parcel; | 210 | android::OutputParcel parcel; |
| 229 | parcel.WriteInterface(NativeWindow{*buffer_queue_id}); | 211 | parcel.WriteInterface(NativeWindow{producer_binder_id}); |
| 230 | 212 | ||
| 231 | const auto buffer = parcel.Serialize(); | 213 | const auto buffer = parcel.Serialize(); |
| 232 | std::memcpy(out_native_window.data(), buffer.data(), | 214 | std::memcpy(out_native_window.data(), buffer.data(), |
| 233 | std::min(out_native_window.size(), buffer.size())); | 215 | std::min(out_native_window.size(), buffer.size())); |
| 234 | 216 | ||
| 235 | *out_layer_id = *layer_id; | ||
| 236 | *out_size = buffer.size(); | 217 | *out_size = buffer.size(); |
| 237 | 218 | ||
| 238 | R_SUCCEED(); | 219 | R_SUCCEED(); |
| @@ -240,25 +221,27 @@ Result IApplicationDisplayService::CreateStrayLayer( | |||
| 240 | 221 | ||
| 241 | Result IApplicationDisplayService::DestroyStrayLayer(u64 layer_id) { | 222 | Result IApplicationDisplayService::DestroyStrayLayer(u64 layer_id) { |
| 242 | LOG_WARNING(Service_VI, "(STUBBED) called. layer_id={}", layer_id); | 223 | LOG_WARNING(Service_VI, "(STUBBED) called. layer_id={}", layer_id); |
| 243 | m_nvnflinger.DestroyLayer(layer_id); | 224 | |
| 244 | R_SUCCEED(); | 225 | { |
| 226 | std::scoped_lock lk{m_lock}; | ||
| 227 | R_UNLESS(m_stray_layer_ids.contains(layer_id), VI::ResultNotFound); | ||
| 228 | m_stray_layer_ids.erase(layer_id); | ||
| 229 | } | ||
| 230 | |||
| 231 | R_RETURN(m_container->DestroyStrayLayer(layer_id)); | ||
| 245 | } | 232 | } |
| 246 | 233 | ||
| 247 | Result IApplicationDisplayService::GetDisplayVsyncEvent( | 234 | Result IApplicationDisplayService::GetDisplayVsyncEvent( |
| 248 | OutCopyHandle<Kernel::KReadableEvent> out_vsync_event, u64 display_id) { | 235 | OutCopyHandle<Kernel::KReadableEvent> out_vsync_event, u64 display_id) { |
| 249 | LOG_DEBUG(Service_VI, "called. display_id={}", display_id); | 236 | LOG_DEBUG(Service_VI, "called. display_id={}", display_id); |
| 250 | 237 | ||
| 251 | const auto result = m_nvnflinger.FindVsyncEvent(out_vsync_event, display_id); | 238 | std::scoped_lock lk{m_lock}; |
| 252 | if (result != ResultSuccess) { | ||
| 253 | if (result == ResultNotFound) { | ||
| 254 | LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id); | ||
| 255 | } | ||
| 256 | 239 | ||
| 257 | R_THROW(result); | 240 | auto [it, created] = m_display_vsync_events.emplace(display_id, m_context); |
| 258 | } | 241 | R_UNLESS(created, VI::ResultPermissionDenied); |
| 259 | 242 | ||
| 260 | R_UNLESS(!m_vsync_event_fetched, VI::ResultPermissionDenied); | 243 | m_container->LinkVsyncEvent(display_id, &it->second); |
| 261 | m_vsync_event_fetched = true; | 244 | *out_vsync_event = it->second.GetHandle(); |
| 262 | 245 | ||
| 263 | R_SUCCEED(); | 246 | R_SUCCEED(); |
| 264 | } | 247 | } |
diff --git a/src/core/hle/service/vi/application_display_service.h b/src/core/hle/service/vi/application_display_service.h index 5dff4bb31..1bdeb8f84 100644 --- a/src/core/hle/service/vi/application_display_service.h +++ b/src/core/hle/service/vi/application_display_service.h | |||
| @@ -1,7 +1,12 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <map> | ||
| 5 | #include <set> | ||
| 6 | |||
| 4 | #include "core/hle/service/cmif_types.h" | 7 | #include "core/hle/service/cmif_types.h" |
| 8 | #include "core/hle/service/kernel_helpers.h" | ||
| 9 | #include "core/hle/service/os/event.h" | ||
| 5 | #include "core/hle/service/service.h" | 10 | #include "core/hle/service/service.h" |
| 6 | #include "core/hle/service/vi/vi_types.h" | 11 | #include "core/hle/service/vi/vi_types.h" |
| 7 | 12 | ||
| @@ -9,26 +14,33 @@ namespace Kernel { | |||
| 9 | class KReadableEvent; | 14 | class KReadableEvent; |
| 10 | } | 15 | } |
| 11 | 16 | ||
| 17 | namespace Service::Nvnflinger { | ||
| 18 | class IHOSBinderDriver; | ||
| 19 | } | ||
| 20 | |||
| 12 | namespace Service::VI { | 21 | namespace Service::VI { |
| 13 | 22 | ||
| 14 | class IHOSBinderDriver; | 23 | class Container; |
| 15 | class IManagerDisplayService; | 24 | class IManagerDisplayService; |
| 16 | class ISystemDisplayService; | 25 | class ISystemDisplayService; |
| 17 | 26 | ||
| 18 | class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { | 27 | class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { |
| 19 | public: | 28 | public: |
| 20 | IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, | 29 | IApplicationDisplayService(Core::System& system_, std::shared_ptr<Container> container); |
| 21 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server); | ||
| 22 | ~IApplicationDisplayService() override; | 30 | ~IApplicationDisplayService() override; |
| 23 | 31 | ||
| 24 | private: | 32 | std::shared_ptr<Container> GetContainer() const { |
| 25 | Result GetRelayService(Out<SharedPointer<IHOSBinderDriver>> out_relay_service); | 33 | return m_container; |
| 34 | } | ||
| 35 | |||
| 36 | public: | ||
| 37 | Result GetRelayService(Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_relay_service); | ||
| 26 | Result GetSystemDisplayService( | 38 | Result GetSystemDisplayService( |
| 27 | Out<SharedPointer<ISystemDisplayService>> out_system_display_service); | 39 | Out<SharedPointer<ISystemDisplayService>> out_system_display_service); |
| 28 | Result GetManagerDisplayService( | 40 | Result GetManagerDisplayService( |
| 29 | Out<SharedPointer<IManagerDisplayService>> out_manager_display_service); | 41 | Out<SharedPointer<IManagerDisplayService>> out_manager_display_service); |
| 30 | Result GetIndirectDisplayTransactionService( | 42 | Result GetIndirectDisplayTransactionService( |
| 31 | Out<SharedPointer<IHOSBinderDriver>> out_indirect_display_transaction_service); | 43 | Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_indirect_display_transaction_service); |
| 32 | Result OpenDisplay(Out<u64> out_display_id, DisplayName display_name); | 44 | Result OpenDisplay(Out<u64> out_display_id, DisplayName display_name); |
| 33 | Result OpenDefaultDisplay(Out<u64> out_display_id); | 45 | Result OpenDefaultDisplay(Out<u64> out_display_id); |
| 34 | Result CloseDisplay(u64 display_id); | 46 | Result CloseDisplay(u64 display_id); |
| @@ -56,9 +68,13 @@ private: | |||
| 56 | s64 width, s64 height); | 68 | s64 width, s64 height); |
| 57 | 69 | ||
| 58 | private: | 70 | private: |
| 59 | Nvnflinger::Nvnflinger& m_nvnflinger; | 71 | const std::shared_ptr<Container> m_container; |
| 60 | Nvnflinger::HosBinderDriverServer& m_hos_binder_driver_server; | 72 | |
| 61 | std::vector<u64> m_stray_layer_ids; | 73 | KernelHelpers::ServiceContext m_context; |
| 74 | std::mutex m_lock{}; | ||
| 75 | std::set<u64> m_open_layer_ids{}; | ||
| 76 | std::set<u64> m_stray_layer_ids{}; | ||
| 77 | std::map<u64, Event> m_display_vsync_events{}; | ||
| 62 | bool m_vsync_event_fetched{false}; | 78 | bool m_vsync_event_fetched{false}; |
| 63 | }; | 79 | }; |
| 64 | 80 | ||
diff --git a/src/core/hle/service/vi/application_root_service.cpp b/src/core/hle/service/vi/application_root_service.cpp index 7af7f062c..7f35a048d 100644 --- a/src/core/hle/service/vi/application_root_service.cpp +++ b/src/core/hle/service/vi/application_root_service.cpp | |||
| @@ -4,17 +4,16 @@ | |||
| 4 | #include "core/hle/service/cmif_serialization.h" | 4 | #include "core/hle/service/cmif_serialization.h" |
| 5 | #include "core/hle/service/vi/application_display_service.h" | 5 | #include "core/hle/service/vi/application_display_service.h" |
| 6 | #include "core/hle/service/vi/application_root_service.h" | 6 | #include "core/hle/service/vi/application_root_service.h" |
| 7 | #include "core/hle/service/vi/container.h" | ||
| 7 | #include "core/hle/service/vi/service_creator.h" | 8 | #include "core/hle/service/vi/service_creator.h" |
| 8 | #include "core/hle/service/vi/vi.h" | 9 | #include "core/hle/service/vi/vi.h" |
| 9 | #include "core/hle/service/vi/vi_types.h" | 10 | #include "core/hle/service/vi/vi_types.h" |
| 10 | 11 | ||
| 11 | namespace Service::VI { | 12 | namespace Service::VI { |
| 12 | 13 | ||
| 13 | IApplicationRootService::IApplicationRootService( | 14 | IApplicationRootService::IApplicationRootService(Core::System& system_, |
| 14 | Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, | 15 | std::shared_ptr<Container> container) |
| 15 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) | 16 | : ServiceFramework{system_, "vi:u"}, m_container{std::move(container)} { |
| 16 | : ServiceFramework{system_, "vi:u"}, m_nvnflinger{nvnflinger}, m_hos_binder_driver_server{ | ||
| 17 | hos_binder_driver_server} { | ||
| 18 | static const FunctionInfo functions[] = { | 17 | static const FunctionInfo functions[] = { |
| 19 | {0, C<&IApplicationRootService::GetDisplayService>, "GetDisplayService"}, | 18 | {0, C<&IApplicationRootService::GetDisplayService>, "GetDisplayService"}, |
| 20 | {1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, | 19 | {1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, |
| @@ -27,8 +26,8 @@ IApplicationRootService::~IApplicationRootService() = default; | |||
| 27 | Result IApplicationRootService::GetDisplayService( | 26 | Result IApplicationRootService::GetDisplayService( |
| 28 | Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) { | 27 | Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) { |
| 29 | LOG_DEBUG(Service_VI, "called"); | 28 | LOG_DEBUG(Service_VI, "called"); |
| 30 | R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_nvnflinger, | 29 | R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_container, |
| 31 | m_hos_binder_driver_server, Permission::User, policy)); | 30 | Permission::User, policy)); |
| 32 | } | 31 | } |
| 33 | 32 | ||
| 34 | } // namespace Service::VI | 33 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/application_root_service.h b/src/core/hle/service/vi/application_root_service.h index 9dbf28cb4..15aa4483d 100644 --- a/src/core/hle/service/vi/application_root_service.h +++ b/src/core/hle/service/vi/application_root_service.h | |||
| @@ -10,20 +10,15 @@ namespace Core { | |||
| 10 | class System; | 10 | class System; |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | namespace Service::Nvnflinger { | ||
| 14 | class HosBinderDriverServer; | ||
| 15 | class Nvnflinger; | ||
| 16 | } // namespace Service::Nvnflinger | ||
| 17 | |||
| 18 | namespace Service::VI { | 13 | namespace Service::VI { |
| 19 | 14 | ||
| 15 | class Container; | ||
| 20 | class IApplicationDisplayService; | 16 | class IApplicationDisplayService; |
| 21 | enum class Policy : u32; | 17 | enum class Policy : u32; |
| 22 | 18 | ||
| 23 | class IApplicationRootService final : public ServiceFramework<IApplicationRootService> { | 19 | class IApplicationRootService final : public ServiceFramework<IApplicationRootService> { |
| 24 | public: | 20 | public: |
| 25 | explicit IApplicationRootService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, | 21 | explicit IApplicationRootService(Core::System& system_, std::shared_ptr<Container> container); |
| 26 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server); | ||
| 27 | ~IApplicationRootService() override; | 22 | ~IApplicationRootService() override; |
| 28 | 23 | ||
| 29 | private: | 24 | private: |
| @@ -32,8 +27,7 @@ private: | |||
| 32 | Policy policy); | 27 | Policy policy); |
| 33 | 28 | ||
| 34 | private: | 29 | private: |
| 35 | Nvnflinger::Nvnflinger& m_nvnflinger; | 30 | const std::shared_ptr<Container> m_container; |
| 36 | Nvnflinger::HosBinderDriverServer& m_hos_binder_driver_server; | ||
| 37 | }; | 31 | }; |
| 38 | 32 | ||
| 39 | } // namespace Service::VI | 33 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/conductor.cpp b/src/core/hle/service/vi/conductor.cpp new file mode 100644 index 000000000..c8ce4fca0 --- /dev/null +++ b/src/core/hle/service/vi/conductor.cpp | |||
| @@ -0,0 +1,114 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/settings.h" | ||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/core_timing.h" | ||
| 7 | #include "core/hle/service/vi/conductor.h" | ||
| 8 | #include "core/hle/service/vi/container.h" | ||
| 9 | #include "core/hle/service/vi/display_list.h" | ||
| 10 | #include "core/hle/service/vi/vsync_manager.h" | ||
| 11 | |||
| 12 | constexpr auto FrameNs = std::chrono::nanoseconds{1000000000 / 60}; | ||
| 13 | |||
| 14 | namespace Service::VI { | ||
| 15 | |||
| 16 | Conductor::Conductor(Core::System& system, Container& container, DisplayList& displays) | ||
| 17 | : m_system(system), m_container(container) { | ||
| 18 | displays.ForEachDisplay([&](Display& display) { | ||
| 19 | m_vsync_managers.insert({display.GetId(), VsyncManager{}}); | ||
| 20 | }); | ||
| 21 | |||
| 22 | if (system.IsMulticore()) { | ||
| 23 | m_event = Core::Timing::CreateEvent( | ||
| 24 | "ScreenComposition", | ||
| 25 | [this](s64 time, | ||
| 26 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 27 | m_signal.Set(); | ||
| 28 | return std::chrono::nanoseconds(this->GetNextTicks()); | ||
| 29 | }); | ||
| 30 | |||
| 31 | system.CoreTiming().ScheduleLoopingEvent(FrameNs, FrameNs, m_event); | ||
| 32 | m_thread = std::jthread([this](std::stop_token token) { this->VsyncThread(token); }); | ||
| 33 | } else { | ||
| 34 | m_event = Core::Timing::CreateEvent( | ||
| 35 | "ScreenComposition", | ||
| 36 | [this](s64 time, | ||
| 37 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | ||
| 38 | this->ProcessVsync(); | ||
| 39 | return std::chrono::nanoseconds(this->GetNextTicks()); | ||
| 40 | }); | ||
| 41 | |||
| 42 | system.CoreTiming().ScheduleLoopingEvent(FrameNs, FrameNs, m_event); | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | Conductor::~Conductor() { | ||
| 47 | m_system.CoreTiming().UnscheduleEvent(m_event); | ||
| 48 | |||
| 49 | if (m_system.IsMulticore()) { | ||
| 50 | m_thread.request_stop(); | ||
| 51 | m_signal.Set(); | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | void Conductor::LinkVsyncEvent(u64 display_id, Event* event) { | ||
| 56 | if (auto it = m_vsync_managers.find(display_id); it != m_vsync_managers.end()) { | ||
| 57 | it->second.LinkVsyncEvent(event); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | void Conductor::UnlinkVsyncEvent(u64 display_id, Event* event) { | ||
| 62 | if (auto it = m_vsync_managers.find(display_id); it != m_vsync_managers.end()) { | ||
| 63 | it->second.UnlinkVsyncEvent(event); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | void Conductor::ProcessVsync() { | ||
| 68 | for (auto& [display_id, manager] : m_vsync_managers) { | ||
| 69 | m_container.ComposeOnDisplay(&m_swap_interval, &m_compose_speed_scale, display_id); | ||
| 70 | manager.SignalVsync(); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | void Conductor::VsyncThread(std::stop_token token) { | ||
| 75 | Common::SetCurrentThreadName("VSyncThread"); | ||
| 76 | |||
| 77 | while (!token.stop_requested()) { | ||
| 78 | m_signal.Wait(); | ||
| 79 | |||
| 80 | if (m_system.IsShuttingDown()) { | ||
| 81 | return; | ||
| 82 | } | ||
| 83 | |||
| 84 | this->ProcessVsync(); | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | s64 Conductor::GetNextTicks() const { | ||
| 89 | const auto& settings = Settings::values; | ||
| 90 | auto speed_scale = 1.f; | ||
| 91 | if (settings.use_multi_core.GetValue()) { | ||
| 92 | if (settings.use_speed_limit.GetValue()) { | ||
| 93 | // Scales the speed based on speed_limit setting on MC. SC is handled by | ||
| 94 | // SpeedLimiter::DoSpeedLimiting. | ||
| 95 | speed_scale = 100.f / settings.speed_limit.GetValue(); | ||
| 96 | } else { | ||
| 97 | // Run at unlocked framerate. | ||
| 98 | speed_scale = 0.01f; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | // Adjust by speed limit determined during composition. | ||
| 103 | speed_scale /= m_compose_speed_scale; | ||
| 104 | |||
| 105 | if (m_system.GetNVDECActive() && settings.use_video_framerate.GetValue()) { | ||
| 106 | // Run at intended presentation rate during video playback. | ||
| 107 | speed_scale = 1.f; | ||
| 108 | } | ||
| 109 | |||
| 110 | const f32 effective_fps = 60.f / static_cast<f32>(m_swap_interval); | ||
| 111 | return static_cast<s64>(speed_scale * (1000000000.f / effective_fps)); | ||
| 112 | } | ||
| 113 | |||
| 114 | } // namespace Service::VI | ||
diff --git a/src/core/hle/service/vi/conductor.h b/src/core/hle/service/vi/conductor.h new file mode 100644 index 000000000..52e3595d2 --- /dev/null +++ b/src/core/hle/service/vi/conductor.h | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | #include <unordered_map> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/polyfill_thread.h" | ||
| 11 | #include "common/thread.h" | ||
| 12 | |||
| 13 | namespace Core { | ||
| 14 | class System; | ||
| 15 | } | ||
| 16 | |||
| 17 | namespace Core::Timing { | ||
| 18 | struct EventType; | ||
| 19 | } | ||
| 20 | |||
| 21 | namespace Service { | ||
| 22 | class Event; | ||
| 23 | } | ||
| 24 | |||
| 25 | namespace Service::VI { | ||
| 26 | |||
| 27 | class Container; | ||
| 28 | class DisplayList; | ||
| 29 | class VsyncManager; | ||
| 30 | |||
| 31 | class Conductor { | ||
| 32 | public: | ||
| 33 | explicit Conductor(Core::System& system, Container& container, DisplayList& displays); | ||
| 34 | ~Conductor(); | ||
| 35 | |||
| 36 | void LinkVsyncEvent(u64 display_id, Event* event); | ||
| 37 | void UnlinkVsyncEvent(u64 display_id, Event* event); | ||
| 38 | |||
| 39 | private: | ||
| 40 | void ProcessVsync(); | ||
| 41 | void VsyncThread(std::stop_token token); | ||
| 42 | s64 GetNextTicks() const; | ||
| 43 | |||
| 44 | private: | ||
| 45 | Core::System& m_system; | ||
| 46 | Container& m_container; | ||
| 47 | std::unordered_map<u64, VsyncManager> m_vsync_managers; | ||
| 48 | std::shared_ptr<Core::Timing::EventType> m_event; | ||
| 49 | Common::Event m_signal; | ||
| 50 | std::jthread m_thread; | ||
| 51 | |||
| 52 | private: | ||
| 53 | s32 m_swap_interval = 1; | ||
| 54 | f32 m_compose_speed_scale = 1.0f; | ||
| 55 | }; | ||
| 56 | |||
| 57 | } // namespace Service::VI | ||
diff --git a/src/core/hle/service/vi/container.cpp b/src/core/hle/service/vi/container.cpp new file mode 100644 index 000000000..310a207f1 --- /dev/null +++ b/src/core/hle/service/vi/container.cpp | |||
| @@ -0,0 +1,228 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/hle/service/nvdrv/nvdrv_interface.h" | ||
| 6 | #include "core/hle/service/nvnflinger/buffer_queue_producer.h" | ||
| 7 | #include "core/hle/service/nvnflinger/hos_binder_driver.h" | ||
| 8 | #include "core/hle/service/nvnflinger/hos_binder_driver_server.h" | ||
| 9 | #include "core/hle/service/nvnflinger/surface_flinger.h" | ||
| 10 | #include "core/hle/service/sm/sm.h" | ||
| 11 | #include "core/hle/service/vi/container.h" | ||
| 12 | #include "core/hle/service/vi/vi_results.h" | ||
| 13 | |||
| 14 | namespace Service::VI { | ||
| 15 | |||
| 16 | Container::Container(Core::System& system) { | ||
| 17 | m_displays.CreateDisplay(DisplayName{"Default"}); | ||
| 18 | m_displays.CreateDisplay(DisplayName{"External"}); | ||
| 19 | m_displays.CreateDisplay(DisplayName{"Edid"}); | ||
| 20 | m_displays.CreateDisplay(DisplayName{"Internal"}); | ||
| 21 | m_displays.CreateDisplay(DisplayName{"Null"}); | ||
| 22 | |||
| 23 | m_binder_driver = | ||
| 24 | system.ServiceManager().GetService<Nvnflinger::IHOSBinderDriver>("dispdrv", true); | ||
| 25 | m_surface_flinger = m_binder_driver->GetSurfaceFlinger(); | ||
| 26 | |||
| 27 | const auto nvdrv = | ||
| 28 | system.ServiceManager().GetService<Nvidia::NVDRV>("nvdrv:s", true)->GetModule(); | ||
| 29 | m_shared_buffer_manager.emplace(system, *this, nvdrv); | ||
| 30 | |||
| 31 | m_displays.ForEachDisplay( | ||
| 32 | [&](auto& display) { m_surface_flinger->AddDisplay(display.GetId()); }); | ||
| 33 | |||
| 34 | m_conductor.emplace(system, *this, m_displays); | ||
| 35 | } | ||
| 36 | |||
| 37 | Container::~Container() { | ||
| 38 | this->OnTerminate(); | ||
| 39 | } | ||
| 40 | |||
| 41 | void Container::OnTerminate() { | ||
| 42 | std::scoped_lock lk{m_lock}; | ||
| 43 | |||
| 44 | m_is_shut_down = true; | ||
| 45 | |||
| 46 | m_layers.ForEachLayer([&](auto& layer) { | ||
| 47 | if (layer.IsOpen()) { | ||
| 48 | this->DestroyBufferQueueLocked(&layer); | ||
| 49 | } | ||
| 50 | }); | ||
| 51 | |||
| 52 | m_displays.ForEachDisplay( | ||
| 53 | [&](auto& display) { m_surface_flinger->RemoveDisplay(display.GetId()); }); | ||
| 54 | } | ||
| 55 | |||
| 56 | SharedBufferManager* Container::GetSharedBufferManager() { | ||
| 57 | return std::addressof(*m_shared_buffer_manager); | ||
| 58 | } | ||
| 59 | |||
| 60 | Result Container::GetBinderDriver( | ||
| 61 | std::shared_ptr<Nvnflinger::IHOSBinderDriver>* out_binder_driver) { | ||
| 62 | *out_binder_driver = m_binder_driver; | ||
| 63 | R_SUCCEED(); | ||
| 64 | } | ||
| 65 | |||
| 66 | Result Container::GetLayerProducerHandle( | ||
| 67 | std::shared_ptr<android::BufferQueueProducer>* out_producer, u64 layer_id) { | ||
| 68 | std::scoped_lock lk{m_lock}; | ||
| 69 | |||
| 70 | auto* const layer = m_layers.GetLayerById(layer_id); | ||
| 71 | R_UNLESS(layer != nullptr, VI::ResultNotFound); | ||
| 72 | |||
| 73 | const auto binder = m_binder_driver->GetServer()->TryGetBinder(layer->GetProducerBinderId()); | ||
| 74 | R_UNLESS(binder != nullptr, VI::ResultNotFound); | ||
| 75 | |||
| 76 | *out_producer = std::static_pointer_cast<android::BufferQueueProducer>(binder); | ||
| 77 | R_SUCCEED(); | ||
| 78 | } | ||
| 79 | |||
| 80 | Result Container::OpenDisplay(u64* out_display_id, const DisplayName& display_name) { | ||
| 81 | auto* const display = m_displays.GetDisplayByName(display_name); | ||
| 82 | R_UNLESS(display != nullptr, VI::ResultNotFound); | ||
| 83 | |||
| 84 | *out_display_id = display->GetId(); | ||
| 85 | R_SUCCEED(); | ||
| 86 | } | ||
| 87 | |||
| 88 | Result Container::CloseDisplay(u64 display_id) { | ||
| 89 | R_SUCCEED(); | ||
| 90 | } | ||
| 91 | |||
| 92 | Result Container::CreateManagedLayer(u64* out_layer_id, u64 display_id, u64 owner_aruid) { | ||
| 93 | std::scoped_lock lk{m_lock}; | ||
| 94 | R_RETURN(this->CreateLayerLocked(out_layer_id, display_id, owner_aruid)); | ||
| 95 | } | ||
| 96 | |||
| 97 | Result Container::DestroyManagedLayer(u64 layer_id) { | ||
| 98 | std::scoped_lock lk{m_lock}; | ||
| 99 | |||
| 100 | // Try to close, if open, but don't fail if not. | ||
| 101 | this->CloseLayerLocked(layer_id); | ||
| 102 | |||
| 103 | R_RETURN(this->DestroyLayerLocked(layer_id)); | ||
| 104 | } | ||
| 105 | |||
| 106 | Result Container::OpenLayer(s32* out_producer_binder_id, u64 layer_id, u64 aruid) { | ||
| 107 | std::scoped_lock lk{m_lock}; | ||
| 108 | R_RETURN(this->OpenLayerLocked(out_producer_binder_id, layer_id, aruid)); | ||
| 109 | } | ||
| 110 | |||
| 111 | Result Container::CloseLayer(u64 layer_id) { | ||
| 112 | std::scoped_lock lk{m_lock}; | ||
| 113 | R_RETURN(this->CloseLayerLocked(layer_id)); | ||
| 114 | } | ||
| 115 | |||
| 116 | Result Container::SetLayerVisibility(u64 layer_id, bool visible) { | ||
| 117 | std::scoped_lock lk{m_lock}; | ||
| 118 | |||
| 119 | auto* const layer = m_layers.GetLayerById(layer_id); | ||
| 120 | R_UNLESS(layer != nullptr, VI::ResultNotFound); | ||
| 121 | |||
| 122 | m_surface_flinger->SetLayerVisibility(layer->GetConsumerBinderId(), visible); | ||
| 123 | R_SUCCEED(); | ||
| 124 | } | ||
| 125 | |||
| 126 | Result Container::SetLayerBlending(u64 layer_id, bool enabled) { | ||
| 127 | std::scoped_lock lk{m_lock}; | ||
| 128 | |||
| 129 | auto* const layer = m_layers.GetLayerById(layer_id); | ||
| 130 | R_UNLESS(layer != nullptr, VI::ResultNotFound); | ||
| 131 | |||
| 132 | m_surface_flinger->SetLayerBlending(layer->GetConsumerBinderId(), | ||
| 133 | enabled ? Nvnflinger::LayerBlending::Coverage | ||
| 134 | : Nvnflinger::LayerBlending::None); | ||
| 135 | R_SUCCEED(); | ||
| 136 | } | ||
| 137 | |||
| 138 | void Container::LinkVsyncEvent(u64 display_id, Event* event) { | ||
| 139 | std::scoped_lock lk{m_lock}; | ||
| 140 | m_conductor->LinkVsyncEvent(display_id, event); | ||
| 141 | } | ||
| 142 | |||
| 143 | void Container::UnlinkVsyncEvent(u64 display_id, Event* event) { | ||
| 144 | std::scoped_lock lk{m_lock}; | ||
| 145 | m_conductor->UnlinkVsyncEvent(display_id, event); | ||
| 146 | } | ||
| 147 | |||
| 148 | Result Container::CreateStrayLayer(s32* out_producer_binder_id, u64* out_layer_id, u64 display_id) { | ||
| 149 | std::scoped_lock lk{m_lock}; | ||
| 150 | R_TRY(this->CreateLayerLocked(out_layer_id, display_id, {})); | ||
| 151 | R_RETURN(this->OpenLayerLocked(out_producer_binder_id, *out_layer_id, {})); | ||
| 152 | } | ||
| 153 | |||
| 154 | Result Container::DestroyStrayLayer(u64 layer_id) { | ||
| 155 | std::scoped_lock lk{m_lock}; | ||
| 156 | R_TRY(this->CloseLayerLocked(layer_id)); | ||
| 157 | R_RETURN(this->DestroyLayerLocked(layer_id)); | ||
| 158 | } | ||
| 159 | |||
| 160 | Result Container::CreateLayerLocked(u64* out_layer_id, u64 display_id, u64 owner_aruid) { | ||
| 161 | auto* const display = m_displays.GetDisplayById(display_id); | ||
| 162 | R_UNLESS(display != nullptr, VI::ResultNotFound); | ||
| 163 | |||
| 164 | auto* const layer = m_layers.CreateLayer(owner_aruid, display); | ||
| 165 | R_UNLESS(layer != nullptr, VI::ResultNotFound); | ||
| 166 | |||
| 167 | *out_layer_id = layer->GetId(); | ||
| 168 | R_SUCCEED(); | ||
| 169 | } | ||
| 170 | |||
| 171 | Result Container::DestroyLayerLocked(u64 layer_id) { | ||
| 172 | R_SUCCEED_IF(m_layers.DestroyLayer(layer_id)); | ||
| 173 | R_THROW(VI::ResultNotFound); | ||
| 174 | } | ||
| 175 | |||
| 176 | Result Container::OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid) { | ||
| 177 | R_UNLESS(!m_is_shut_down, VI::ResultOperationFailed); | ||
| 178 | |||
| 179 | auto* const layer = m_layers.GetLayerById(layer_id); | ||
| 180 | R_UNLESS(layer != nullptr, VI::ResultNotFound); | ||
| 181 | R_UNLESS(!layer->IsOpen(), VI::ResultOperationFailed); | ||
| 182 | R_UNLESS(layer->GetOwnerAruid() == aruid, VI::ResultPermissionDenied); | ||
| 183 | |||
| 184 | this->CreateBufferQueueLocked(layer); | ||
| 185 | *out_producer_binder_id = layer->GetProducerBinderId(); | ||
| 186 | |||
| 187 | R_SUCCEED(); | ||
| 188 | } | ||
| 189 | |||
| 190 | Result Container::CloseLayerLocked(u64 layer_id) { | ||
| 191 | auto* const layer = m_layers.GetLayerById(layer_id); | ||
| 192 | R_UNLESS(layer != nullptr, VI::ResultNotFound); | ||
| 193 | R_UNLESS(layer->IsOpen(), VI::ResultOperationFailed); | ||
| 194 | |||
| 195 | this->DestroyBufferQueueLocked(layer); | ||
| 196 | |||
| 197 | R_SUCCEED(); | ||
| 198 | } | ||
| 199 | |||
| 200 | void Container::CreateBufferQueueLocked(Layer* layer) { | ||
| 201 | s32 consumer_binder_id, producer_binder_id; | ||
| 202 | m_surface_flinger->CreateBufferQueue(&consumer_binder_id, &producer_binder_id); | ||
| 203 | layer->Open(consumer_binder_id, producer_binder_id); | ||
| 204 | |||
| 205 | if (auto* display = layer->GetDisplay(); display != nullptr) { | ||
| 206 | m_surface_flinger->AddLayerToDisplayStack(display->GetId(), consumer_binder_id); | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | void Container::DestroyBufferQueueLocked(Layer* layer) { | ||
| 211 | if (auto* display = layer->GetDisplay(); display != nullptr) { | ||
| 212 | m_surface_flinger->RemoveLayerFromDisplayStack(display->GetId(), | ||
| 213 | layer->GetConsumerBinderId()); | ||
| 214 | } | ||
| 215 | |||
| 216 | layer->Close(); | ||
| 217 | m_surface_flinger->DestroyBufferQueue(layer->GetConsumerBinderId(), | ||
| 218 | layer->GetProducerBinderId()); | ||
| 219 | } | ||
| 220 | |||
| 221 | bool Container::ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, | ||
| 222 | u64 display_id) { | ||
| 223 | std::scoped_lock lk{m_lock}; | ||
| 224 | return m_surface_flinger->ComposeDisplay(out_swap_interval, out_compose_speed_scale, | ||
| 225 | display_id); | ||
| 226 | } | ||
| 227 | |||
| 228 | } // namespace Service::VI | ||
diff --git a/src/core/hle/service/vi/container.h b/src/core/hle/service/vi/container.h new file mode 100644 index 000000000..cd0d2ca86 --- /dev/null +++ b/src/core/hle/service/vi/container.h | |||
| @@ -0,0 +1,92 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | #include <mutex> | ||
| 8 | #include <optional> | ||
| 9 | |||
| 10 | #include "core/hle/service/vi/conductor.h" | ||
| 11 | #include "core/hle/service/vi/display_list.h" | ||
| 12 | #include "core/hle/service/vi/layer_list.h" | ||
| 13 | #include "core/hle/service/vi/shared_buffer_manager.h" | ||
| 14 | |||
| 15 | union Result; | ||
| 16 | |||
| 17 | namespace Service::android { | ||
| 18 | class BufferQueueProducer; | ||
| 19 | } | ||
| 20 | |||
| 21 | namespace Service::Nvnflinger { | ||
| 22 | class IHOSBinderDriver; | ||
| 23 | class SurfaceFlinger; | ||
| 24 | } // namespace Service::Nvnflinger | ||
| 25 | |||
| 26 | namespace Service { | ||
| 27 | class Event; | ||
| 28 | } | ||
| 29 | |||
| 30 | namespace Service::VI { | ||
| 31 | |||
| 32 | class SharedBufferManager; | ||
| 33 | |||
| 34 | class Container { | ||
| 35 | public: | ||
| 36 | explicit Container(Core::System& system); | ||
| 37 | ~Container(); | ||
| 38 | |||
| 39 | void OnTerminate(); | ||
| 40 | |||
| 41 | SharedBufferManager* GetSharedBufferManager(); | ||
| 42 | |||
| 43 | Result GetBinderDriver(std::shared_ptr<Nvnflinger::IHOSBinderDriver>* out_binder_driver); | ||
| 44 | Result GetLayerProducerHandle(std::shared_ptr<android::BufferQueueProducer>* out_producer, | ||
| 45 | u64 layer_id); | ||
| 46 | |||
| 47 | Result OpenDisplay(u64* out_display_id, const DisplayName& display_name); | ||
| 48 | Result CloseDisplay(u64 display_id); | ||
| 49 | |||
| 50 | // Managed layers are created by the interaction between am and ommdisp | ||
| 51 | // on behalf of an applet. Their lifetime ends with the lifetime of the | ||
| 52 | // applet's ISelfController. | ||
| 53 | Result CreateManagedLayer(u64* out_layer_id, u64 display_id, u64 owner_aruid); | ||
| 54 | Result DestroyManagedLayer(u64 layer_id); | ||
| 55 | Result OpenLayer(s32* out_producer_binder_id, u64 layer_id, u64 aruid); | ||
| 56 | Result CloseLayer(u64 layer_id); | ||
| 57 | |||
| 58 | // Stray layers are created by non-applet sysmodules. Their lifetime ends | ||
| 59 | // with the lifetime of the IApplicationDisplayService which created them. | ||
| 60 | Result CreateStrayLayer(s32* out_producer_binder_id, u64* out_layer_id, u64 display_id); | ||
| 61 | Result DestroyStrayLayer(u64 layer_id); | ||
| 62 | |||
| 63 | Result SetLayerVisibility(u64 layer_id, bool visible); | ||
| 64 | Result SetLayerBlending(u64 layer_id, bool enabled); | ||
| 65 | |||
| 66 | void LinkVsyncEvent(u64 display_id, Event* event); | ||
| 67 | void UnlinkVsyncEvent(u64 display_id, Event* event); | ||
| 68 | |||
| 69 | private: | ||
| 70 | Result CreateLayerLocked(u64* out_layer_id, u64 display_id, u64 owner_aruid); | ||
| 71 | Result DestroyLayerLocked(u64 layer_id); | ||
| 72 | Result OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid); | ||
| 73 | Result CloseLayerLocked(u64 layer_id); | ||
| 74 | |||
| 75 | void CreateBufferQueueLocked(Layer* layer); | ||
| 76 | void DestroyBufferQueueLocked(Layer* layer); | ||
| 77 | |||
| 78 | public: | ||
| 79 | bool ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id); | ||
| 80 | |||
| 81 | private: | ||
| 82 | std::mutex m_lock{}; | ||
| 83 | DisplayList m_displays{}; | ||
| 84 | LayerList m_layers{}; | ||
| 85 | std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_driver{}; | ||
| 86 | std::shared_ptr<Nvnflinger::SurfaceFlinger> m_surface_flinger{}; | ||
| 87 | std::optional<SharedBufferManager> m_shared_buffer_manager{}; | ||
| 88 | std::optional<Conductor> m_conductor{}; | ||
| 89 | bool m_is_shut_down{}; | ||
| 90 | }; | ||
| 91 | |||
| 92 | } // namespace Service::VI | ||
diff --git a/src/core/hle/service/vi/display.h b/src/core/hle/service/vi/display.h new file mode 100644 index 000000000..fceda75e3 --- /dev/null +++ b/src/core/hle/service/vi/display.h | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/vi/vi_types.h" | ||
| 7 | |||
| 8 | namespace Service::VI { | ||
| 9 | |||
| 10 | class Display { | ||
| 11 | public: | ||
| 12 | constexpr Display() = default; | ||
| 13 | |||
| 14 | void Initialize(u64 id, const DisplayName& display_name) { | ||
| 15 | m_id = id; | ||
| 16 | m_display_name = display_name; | ||
| 17 | m_is_initialized = true; | ||
| 18 | } | ||
| 19 | |||
| 20 | void Finalize() { | ||
| 21 | m_id = {}; | ||
| 22 | m_display_name = {}; | ||
| 23 | m_is_initialized = {}; | ||
| 24 | } | ||
| 25 | |||
| 26 | u64 GetId() const { | ||
| 27 | return m_id; | ||
| 28 | } | ||
| 29 | |||
| 30 | const DisplayName& GetDisplayName() const { | ||
| 31 | return m_display_name; | ||
| 32 | } | ||
| 33 | |||
| 34 | bool IsInitialized() const { | ||
| 35 | return m_is_initialized; | ||
| 36 | } | ||
| 37 | |||
| 38 | private: | ||
| 39 | u64 m_id{}; | ||
| 40 | DisplayName m_display_name{}; | ||
| 41 | bool m_is_initialized{}; | ||
| 42 | }; | ||
| 43 | |||
| 44 | } // namespace Service::VI | ||
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp deleted file mode 100644 index 7f2af9acc..000000000 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ /dev/null | |||
| @@ -1,143 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | #include <utility> | ||
| 6 | |||
| 7 | #include <fmt/format.h> | ||
| 8 | |||
| 9 | #include "common/assert.h" | ||
| 10 | #include "core/core.h" | ||
| 11 | #include "core/hle/kernel/k_event.h" | ||
| 12 | #include "core/hle/kernel/k_readable_event.h" | ||
| 13 | #include "core/hle/service/kernel_helpers.h" | ||
| 14 | #include "core/hle/service/nvdrv/core/container.h" | ||
| 15 | #include "core/hle/service/nvnflinger/buffer_item_consumer.h" | ||
| 16 | #include "core/hle/service/nvnflinger/buffer_queue_consumer.h" | ||
| 17 | #include "core/hle/service/nvnflinger/buffer_queue_core.h" | ||
| 18 | #include "core/hle/service/nvnflinger/buffer_queue_producer.h" | ||
| 19 | #include "core/hle/service/nvnflinger/hardware_composer.h" | ||
| 20 | #include "core/hle/service/nvnflinger/hos_binder_driver_server.h" | ||
| 21 | #include "core/hle/service/vi/display/vi_display.h" | ||
| 22 | #include "core/hle/service/vi/layer/vi_layer.h" | ||
| 23 | #include "core/hle/service/vi/vi_results.h" | ||
| 24 | |||
| 25 | namespace Service::VI { | ||
| 26 | |||
| 27 | struct BufferQueue { | ||
| 28 | std::shared_ptr<android::BufferQueueCore> core; | ||
| 29 | std::unique_ptr<android::BufferQueueProducer> producer; | ||
| 30 | std::unique_ptr<android::BufferQueueConsumer> consumer; | ||
| 31 | }; | ||
| 32 | |||
| 33 | static BufferQueue CreateBufferQueue(KernelHelpers::ServiceContext& service_context, | ||
| 34 | Service::Nvidia::NvCore::NvMap& nvmap) { | ||
| 35 | auto buffer_queue_core = std::make_shared<android::BufferQueueCore>(); | ||
| 36 | return { | ||
| 37 | buffer_queue_core, | ||
| 38 | std::make_unique<android::BufferQueueProducer>(service_context, buffer_queue_core, nvmap), | ||
| 39 | std::make_unique<android::BufferQueueConsumer>(buffer_queue_core)}; | ||
| 40 | } | ||
| 41 | |||
| 42 | Display::Display(u64 id, std::string name_, | ||
| 43 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_, | ||
| 44 | KernelHelpers::ServiceContext& service_context_, Core::System& system_) | ||
| 45 | : display_id{id}, name{std::move(name_)}, hos_binder_driver_server{hos_binder_driver_server_}, | ||
| 46 | service_context{service_context_} { | ||
| 47 | hardware_composer = std::make_unique<Nvnflinger::HardwareComposer>(); | ||
| 48 | vsync_event = service_context.CreateEvent(fmt::format("Display VSync Event {}", id)); | ||
| 49 | } | ||
| 50 | |||
| 51 | Display::~Display() { | ||
| 52 | service_context.CloseEvent(vsync_event); | ||
| 53 | } | ||
| 54 | |||
| 55 | Layer& Display::GetLayer(std::size_t index) { | ||
| 56 | size_t i = 0; | ||
| 57 | for (auto& layer : layers) { | ||
| 58 | if (!layer->IsOpen() || !layer->IsVisible()) { | ||
| 59 | continue; | ||
| 60 | } | ||
| 61 | |||
| 62 | if (i == index) { | ||
| 63 | return *layer; | ||
| 64 | } | ||
| 65 | |||
| 66 | i++; | ||
| 67 | } | ||
| 68 | |||
| 69 | UNREACHABLE(); | ||
| 70 | } | ||
| 71 | |||
| 72 | size_t Display::GetNumLayers() const { | ||
| 73 | return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen() && l->IsVisible(); }); | ||
| 74 | } | ||
| 75 | |||
| 76 | Kernel::KReadableEvent* Display::GetVSyncEvent() { | ||
| 77 | return &vsync_event->GetReadableEvent(); | ||
| 78 | } | ||
| 79 | |||
| 80 | void Display::SignalVSyncEvent() { | ||
| 81 | vsync_event->Signal(); | ||
| 82 | } | ||
| 83 | |||
| 84 | void Display::CreateLayer(u64 layer_id, u32 binder_id, | ||
| 85 | Service::Nvidia::NvCore::Container& nv_core) { | ||
| 86 | auto [core, producer, consumer] = CreateBufferQueue(service_context, nv_core.GetNvMapFile()); | ||
| 87 | |||
| 88 | auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(consumer)); | ||
| 89 | buffer_item_consumer->Connect(false); | ||
| 90 | |||
| 91 | layers.emplace_back(std::make_unique<Layer>(layer_id, binder_id, *core, *producer, | ||
| 92 | std::move(buffer_item_consumer))); | ||
| 93 | |||
| 94 | if (is_abandoned) { | ||
| 95 | this->FindLayer(layer_id)->GetConsumer().Abandon(); | ||
| 96 | } | ||
| 97 | |||
| 98 | hos_binder_driver_server.RegisterProducer(std::move(producer)); | ||
| 99 | } | ||
| 100 | |||
| 101 | void Display::DestroyLayer(u64 layer_id) { | ||
| 102 | if (auto* layer = this->FindLayer(layer_id); layer != nullptr) { | ||
| 103 | layer->GetConsumer().Abandon(); | ||
| 104 | } | ||
| 105 | |||
| 106 | std::erase_if(layers, | ||
| 107 | [layer_id](const auto& layer) { return layer->GetLayerId() == layer_id; }); | ||
| 108 | } | ||
| 109 | |||
| 110 | void Display::Abandon() { | ||
| 111 | for (auto& layer : layers) { | ||
| 112 | layer->GetConsumer().Abandon(); | ||
| 113 | } | ||
| 114 | is_abandoned = true; | ||
| 115 | } | ||
| 116 | |||
| 117 | Layer* Display::FindLayer(u64 layer_id) { | ||
| 118 | const auto itr = | ||
| 119 | std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) { | ||
| 120 | return layer->GetLayerId() == layer_id; | ||
| 121 | }); | ||
| 122 | |||
| 123 | if (itr == layers.end()) { | ||
| 124 | return nullptr; | ||
| 125 | } | ||
| 126 | |||
| 127 | return itr->get(); | ||
| 128 | } | ||
| 129 | |||
| 130 | const Layer* Display::FindLayer(u64 layer_id) const { | ||
| 131 | const auto itr = | ||
| 132 | std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) { | ||
| 133 | return layer->GetLayerId() == layer_id; | ||
| 134 | }); | ||
| 135 | |||
| 136 | if (itr == layers.end()) { | ||
| 137 | return nullptr; | ||
| 138 | } | ||
| 139 | |||
| 140 | return itr->get(); | ||
| 141 | } | ||
| 142 | |||
| 143 | } // namespace Service::VI | ||
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h deleted file mode 100644 index 220292cff..000000000 --- a/src/core/hle/service/vi/display/vi_display.h +++ /dev/null | |||
| @@ -1,143 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | #include <string> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/common_funcs.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "core/hle/result.h" | ||
| 13 | |||
| 14 | namespace Core { | ||
| 15 | class System; | ||
| 16 | } | ||
| 17 | |||
| 18 | namespace Kernel { | ||
| 19 | class KEvent; | ||
| 20 | class KReadableEvent; | ||
| 21 | } // namespace Kernel | ||
| 22 | |||
| 23 | namespace Service::android { | ||
| 24 | class BufferQueueProducer; | ||
| 25 | } | ||
| 26 | |||
| 27 | namespace Service::KernelHelpers { | ||
| 28 | class ServiceContext; | ||
| 29 | } | ||
| 30 | |||
| 31 | namespace Service::Nvnflinger { | ||
| 32 | class HardwareComposer; | ||
| 33 | class HosBinderDriverServer; | ||
| 34 | } // namespace Service::Nvnflinger | ||
| 35 | |||
| 36 | namespace Service::Nvidia::NvCore { | ||
| 37 | class Container; | ||
| 38 | class NvMap; | ||
| 39 | } // namespace Service::Nvidia::NvCore | ||
| 40 | |||
| 41 | namespace Service::VI { | ||
| 42 | |||
| 43 | class Layer; | ||
| 44 | |||
| 45 | /// Represents a single display type | ||
| 46 | class Display { | ||
| 47 | public: | ||
| 48 | YUZU_NON_COPYABLE(Display); | ||
| 49 | YUZU_NON_MOVEABLE(Display); | ||
| 50 | |||
| 51 | /// Constructs a display with a given unique ID and name. | ||
| 52 | /// | ||
| 53 | /// @param id The unique ID for this display. | ||
| 54 | /// @param hos_binder_driver_server_ Nvnflinger HOSBinderDriver server instance. | ||
| 55 | /// @param service_context_ The ServiceContext for the owning service. | ||
| 56 | /// @param name_ The name for this display. | ||
| 57 | /// @param system_ The global system instance. | ||
| 58 | /// | ||
| 59 | Display(u64 id, std::string name_, Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_, | ||
| 60 | KernelHelpers::ServiceContext& service_context_, Core::System& system_); | ||
| 61 | ~Display(); | ||
| 62 | |||
| 63 | /// Gets the unique ID assigned to this display. | ||
| 64 | u64 GetID() const { | ||
| 65 | return display_id; | ||
| 66 | } | ||
| 67 | |||
| 68 | /// Gets the name of this display | ||
| 69 | const std::string& GetName() const { | ||
| 70 | return name; | ||
| 71 | } | ||
| 72 | |||
| 73 | /// Whether or not this display has any layers added to it. | ||
| 74 | bool HasLayers() const { | ||
| 75 | return GetNumLayers() > 0; | ||
| 76 | } | ||
| 77 | |||
| 78 | /// Gets a layer for this display based off an index. | ||
| 79 | Layer& GetLayer(std::size_t index); | ||
| 80 | |||
| 81 | std::size_t GetNumLayers() const; | ||
| 82 | |||
| 83 | /// Gets the internal vsync event. | ||
| 84 | Kernel::KReadableEvent* GetVSyncEvent(); | ||
| 85 | |||
| 86 | /// Signals the internal vsync event. | ||
| 87 | void SignalVSyncEvent(); | ||
| 88 | |||
| 89 | /// Creates and adds a layer to this display with the given ID. | ||
| 90 | /// | ||
| 91 | /// @param layer_id The ID to assign to the created layer. | ||
| 92 | /// @param binder_id The ID assigned to the buffer queue. | ||
| 93 | /// | ||
| 94 | void CreateLayer(u64 layer_id, u32 binder_id, Service::Nvidia::NvCore::Container& core); | ||
| 95 | |||
| 96 | /// Removes a layer from this display with the given ID. | ||
| 97 | /// | ||
| 98 | /// @param layer_id The ID assigned to the layer to destroy. | ||
| 99 | /// | ||
| 100 | void DestroyLayer(u64 layer_id); | ||
| 101 | |||
| 102 | /// Resets the display for a new connection. | ||
| 103 | void Reset() { | ||
| 104 | layers.clear(); | ||
| 105 | } | ||
| 106 | |||
| 107 | void Abandon(); | ||
| 108 | |||
| 109 | /// Attempts to find a layer with the given ID. | ||
| 110 | /// | ||
| 111 | /// @param layer_id The layer ID. | ||
| 112 | /// | ||
| 113 | /// @returns If found, the Layer instance with the given ID. | ||
| 114 | /// If not found, then nullptr is returned. | ||
| 115 | /// | ||
| 116 | Layer* FindLayer(u64 layer_id); | ||
| 117 | |||
| 118 | /// Attempts to find a layer with the given ID. | ||
| 119 | /// | ||
| 120 | /// @param layer_id The layer ID. | ||
| 121 | /// | ||
| 122 | /// @returns If found, the Layer instance with the given ID. | ||
| 123 | /// If not found, then nullptr is returned. | ||
| 124 | /// | ||
| 125 | const Layer* FindLayer(u64 layer_id) const; | ||
| 126 | |||
| 127 | Nvnflinger::HardwareComposer& GetComposer() const { | ||
| 128 | return *hardware_composer; | ||
| 129 | } | ||
| 130 | |||
| 131 | private: | ||
| 132 | u64 display_id; | ||
| 133 | std::string name; | ||
| 134 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server; | ||
| 135 | KernelHelpers::ServiceContext& service_context; | ||
| 136 | |||
| 137 | std::vector<std::unique_ptr<Layer>> layers; | ||
| 138 | std::unique_ptr<Nvnflinger::HardwareComposer> hardware_composer; | ||
| 139 | Kernel::KEvent* vsync_event{}; | ||
| 140 | bool is_abandoned{}; | ||
| 141 | }; | ||
| 142 | |||
| 143 | } // namespace Service::VI | ||
diff --git a/src/core/hle/service/vi/display_list.h b/src/core/hle/service/vi/display_list.h new file mode 100644 index 000000000..f710ac472 --- /dev/null +++ b/src/core/hle/service/vi/display_list.h | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <cstring> | ||
| 7 | |||
| 8 | #include "core/hle/service/vi/display.h" | ||
| 9 | |||
| 10 | namespace Service::VI { | ||
| 11 | |||
| 12 | class DisplayList { | ||
| 13 | public: | ||
| 14 | constexpr DisplayList() = default; | ||
| 15 | |||
| 16 | bool CreateDisplay(const DisplayName& name) { | ||
| 17 | Display* const display = this->GetFreeDisplay(); | ||
| 18 | if (!display) { | ||
| 19 | return false; | ||
| 20 | } | ||
| 21 | |||
| 22 | display->Initialize(m_next_id++, name); | ||
| 23 | return true; | ||
| 24 | } | ||
| 25 | |||
| 26 | bool DestroyDisplay(u64 display_id) { | ||
| 27 | Display* display = this->GetDisplayById(display_id); | ||
| 28 | if (!display) { | ||
| 29 | return false; | ||
| 30 | } | ||
| 31 | |||
| 32 | display->Finalize(); | ||
| 33 | return true; | ||
| 34 | } | ||
| 35 | |||
| 36 | Display* GetDisplayByName(const DisplayName& name) { | ||
| 37 | for (auto& display : m_displays) { | ||
| 38 | if (display.IsInitialized() && | ||
| 39 | std::strncmp(name.data(), display.GetDisplayName().data(), sizeof(DisplayName)) == | ||
| 40 | 0) { | ||
| 41 | return &display; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | return nullptr; | ||
| 46 | } | ||
| 47 | |||
| 48 | Display* GetDisplayById(u64 display_id) { | ||
| 49 | for (auto& display : m_displays) { | ||
| 50 | if (display.IsInitialized() && display.GetId() == display_id) { | ||
| 51 | return &display; | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | return nullptr; | ||
| 56 | } | ||
| 57 | |||
| 58 | template <typename F> | ||
| 59 | void ForEachDisplay(F&& cb) { | ||
| 60 | for (auto& display : m_displays) { | ||
| 61 | if (display.IsInitialized()) { | ||
| 62 | cb(display); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | private: | ||
| 68 | Display* GetFreeDisplay() { | ||
| 69 | for (auto& display : m_displays) { | ||
| 70 | if (!display.IsInitialized()) { | ||
| 71 | return &display; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | return nullptr; | ||
| 76 | } | ||
| 77 | |||
| 78 | private: | ||
| 79 | std::array<Display, 8> m_displays{}; | ||
| 80 | u64 m_next_id{}; | ||
| 81 | }; | ||
| 82 | |||
| 83 | } // namespace Service::VI | ||
diff --git a/src/core/hle/service/vi/layer.h b/src/core/hle/service/vi/layer.h new file mode 100644 index 000000000..b85c8df61 --- /dev/null +++ b/src/core/hle/service/vi/layer.h | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/common_types.h" | ||
| 7 | |||
| 8 | namespace Service::VI { | ||
| 9 | |||
| 10 | class Display; | ||
| 11 | |||
| 12 | class Layer { | ||
| 13 | public: | ||
| 14 | constexpr Layer() = default; | ||
| 15 | |||
| 16 | void Initialize(u64 id, u64 owner_aruid, Display* display) { | ||
| 17 | m_id = id; | ||
| 18 | m_owner_aruid = owner_aruid; | ||
| 19 | m_display = display; | ||
| 20 | m_is_initialized = true; | ||
| 21 | } | ||
| 22 | |||
| 23 | void Finalize() { | ||
| 24 | m_id = {}; | ||
| 25 | m_display = {}; | ||
| 26 | m_is_initialized = {}; | ||
| 27 | } | ||
| 28 | |||
| 29 | void Open(s32 consumer_binder_id, s32 producer_binder_id) { | ||
| 30 | m_consumer_binder_id = consumer_binder_id; | ||
| 31 | m_producer_binder_id = producer_binder_id; | ||
| 32 | m_is_open = true; | ||
| 33 | } | ||
| 34 | |||
| 35 | void Close() { | ||
| 36 | m_producer_binder_id = {}; | ||
| 37 | m_consumer_binder_id = {}; | ||
| 38 | m_is_open = {}; | ||
| 39 | } | ||
| 40 | |||
| 41 | u64 GetId() const { | ||
| 42 | return m_id; | ||
| 43 | } | ||
| 44 | |||
| 45 | u64 GetOwnerAruid() const { | ||
| 46 | return m_owner_aruid; | ||
| 47 | } | ||
| 48 | |||
| 49 | Display* GetDisplay() const { | ||
| 50 | return m_display; | ||
| 51 | } | ||
| 52 | |||
| 53 | s32 GetConsumerBinderId() const { | ||
| 54 | return m_consumer_binder_id; | ||
| 55 | } | ||
| 56 | |||
| 57 | s32 GetProducerBinderId() const { | ||
| 58 | return m_producer_binder_id; | ||
| 59 | } | ||
| 60 | |||
| 61 | bool IsInitialized() const { | ||
| 62 | return m_is_initialized; | ||
| 63 | } | ||
| 64 | |||
| 65 | bool IsOpen() const { | ||
| 66 | return m_is_open; | ||
| 67 | } | ||
| 68 | |||
| 69 | private: | ||
| 70 | u64 m_id{}; | ||
| 71 | u64 m_owner_aruid{}; | ||
| 72 | Display* m_display{}; | ||
| 73 | s32 m_consumer_binder_id{}; | ||
| 74 | s32 m_producer_binder_id{}; | ||
| 75 | bool m_is_initialized{}; | ||
| 76 | bool m_is_open{}; | ||
| 77 | }; | ||
| 78 | |||
| 79 | } // namespace Service::VI | ||
diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp deleted file mode 100644 index eca35d82a..000000000 --- a/src/core/hle/service/vi/layer/vi_layer.cpp +++ /dev/null | |||
| @@ -1,18 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/nvnflinger/hwc_layer.h" | ||
| 5 | #include "core/hle/service/vi/layer/vi_layer.h" | ||
| 6 | |||
| 7 | namespace Service::VI { | ||
| 8 | |||
| 9 | Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_, | ||
| 10 | android::BufferQueueProducer& binder_, | ||
| 11 | std::shared_ptr<android::BufferItemConsumer>&& consumer_) | ||
| 12 | : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, consumer{std::move( | ||
| 13 | consumer_)}, | ||
| 14 | blending{Nvnflinger::LayerBlending::None}, open{false}, visible{true} {} | ||
| 15 | |||
| 16 | Layer::~Layer() = default; | ||
| 17 | |||
| 18 | } // namespace Service::VI | ||
diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h deleted file mode 100644 index 14e229903..000000000 --- a/src/core/hle/service/vi/layer/vi_layer.h +++ /dev/null | |||
| @@ -1,118 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | #include <utility> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | namespace Service::android { | ||
| 12 | class BufferItemConsumer; | ||
| 13 | class BufferQueueCore; | ||
| 14 | class BufferQueueProducer; | ||
| 15 | } // namespace Service::android | ||
| 16 | |||
| 17 | namespace Service::Nvnflinger { | ||
| 18 | enum class LayerBlending : u32; | ||
| 19 | } | ||
| 20 | |||
| 21 | namespace Service::VI { | ||
| 22 | |||
| 23 | /// Represents a single display layer. | ||
| 24 | class Layer { | ||
| 25 | public: | ||
| 26 | /// Constructs a layer with a given ID and buffer queue. | ||
| 27 | /// | ||
| 28 | /// @param layer_id_ The ID to assign to this layer. | ||
| 29 | /// @param binder_id_ The binder ID to assign to this layer. | ||
| 30 | /// @param binder_ The buffer producer queue for this layer to use. | ||
| 31 | /// | ||
| 32 | Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_, | ||
| 33 | android::BufferQueueProducer& binder_, | ||
| 34 | std::shared_ptr<android::BufferItemConsumer>&& consumer_); | ||
| 35 | ~Layer(); | ||
| 36 | |||
| 37 | Layer(const Layer&) = delete; | ||
| 38 | Layer& operator=(const Layer&) = delete; | ||
| 39 | |||
| 40 | Layer(Layer&&) = default; | ||
| 41 | Layer& operator=(Layer&&) = delete; | ||
| 42 | |||
| 43 | /// Gets the ID for this layer. | ||
| 44 | u64 GetLayerId() const { | ||
| 45 | return layer_id; | ||
| 46 | } | ||
| 47 | |||
| 48 | /// Gets the binder ID for this layer. | ||
| 49 | u32 GetBinderId() const { | ||
| 50 | return binder_id; | ||
| 51 | } | ||
| 52 | |||
| 53 | /// Gets a reference to the buffer queue this layer is using. | ||
| 54 | android::BufferQueueProducer& GetBufferQueue() { | ||
| 55 | return binder; | ||
| 56 | } | ||
| 57 | |||
| 58 | /// Gets a const reference to the buffer queue this layer is using. | ||
| 59 | const android::BufferQueueProducer& GetBufferQueue() const { | ||
| 60 | return binder; | ||
| 61 | } | ||
| 62 | |||
| 63 | android::BufferItemConsumer& GetConsumer() { | ||
| 64 | return *consumer; | ||
| 65 | } | ||
| 66 | |||
| 67 | const android::BufferItemConsumer& GetConsumer() const { | ||
| 68 | return *consumer; | ||
| 69 | } | ||
| 70 | |||
| 71 | android::BufferQueueCore& Core() { | ||
| 72 | return core; | ||
| 73 | } | ||
| 74 | |||
| 75 | const android::BufferQueueCore& Core() const { | ||
| 76 | return core; | ||
| 77 | } | ||
| 78 | |||
| 79 | bool IsVisible() const { | ||
| 80 | return visible; | ||
| 81 | } | ||
| 82 | |||
| 83 | void SetVisibility(bool v) { | ||
| 84 | visible = v; | ||
| 85 | } | ||
| 86 | |||
| 87 | bool IsOpen() const { | ||
| 88 | return open; | ||
| 89 | } | ||
| 90 | |||
| 91 | bool Close() { | ||
| 92 | return std::exchange(open, false); | ||
| 93 | } | ||
| 94 | |||
| 95 | bool Open() { | ||
| 96 | return !std::exchange(open, true); | ||
| 97 | } | ||
| 98 | |||
| 99 | Nvnflinger::LayerBlending GetBlending() { | ||
| 100 | return blending; | ||
| 101 | } | ||
| 102 | |||
| 103 | void SetBlending(Nvnflinger::LayerBlending b) { | ||
| 104 | blending = b; | ||
| 105 | } | ||
| 106 | |||
| 107 | private: | ||
| 108 | const u64 layer_id; | ||
| 109 | const u32 binder_id; | ||
| 110 | android::BufferQueueCore& core; | ||
| 111 | android::BufferQueueProducer& binder; | ||
| 112 | std::shared_ptr<android::BufferItemConsumer> consumer; | ||
| 113 | Service::Nvnflinger::LayerBlending blending; | ||
| 114 | bool open; | ||
| 115 | bool visible; | ||
| 116 | }; | ||
| 117 | |||
| 118 | } // namespace Service::VI | ||
diff --git a/src/core/hle/service/vi/layer_list.h b/src/core/hle/service/vi/layer_list.h new file mode 100644 index 000000000..1738ede9a --- /dev/null +++ b/src/core/hle/service/vi/layer_list.h | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/service/vi/layer.h" | ||
| 7 | |||
| 8 | namespace Service::VI { | ||
| 9 | |||
| 10 | class LayerList { | ||
| 11 | public: | ||
| 12 | constexpr LayerList() = default; | ||
| 13 | |||
| 14 | Layer* CreateLayer(u64 owner_aruid, Display* display) { | ||
| 15 | Layer* const layer = GetFreeLayer(); | ||
| 16 | if (!layer) { | ||
| 17 | return nullptr; | ||
| 18 | } | ||
| 19 | |||
| 20 | layer->Initialize(++m_next_id, owner_aruid, display); | ||
| 21 | return layer; | ||
| 22 | } | ||
| 23 | |||
| 24 | bool DestroyLayer(u64 layer_id) { | ||
| 25 | Layer* const layer = GetLayerById(layer_id); | ||
| 26 | if (!layer) { | ||
| 27 | return false; | ||
| 28 | } | ||
| 29 | |||
| 30 | layer->Finalize(); | ||
| 31 | return true; | ||
| 32 | } | ||
| 33 | |||
| 34 | Layer* GetLayerById(u64 layer_id) { | ||
| 35 | for (auto& layer : m_layers) { | ||
| 36 | if (layer.IsInitialized() && layer.GetId() == layer_id) { | ||
| 37 | return &layer; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | return nullptr; | ||
| 42 | } | ||
| 43 | |||
| 44 | template <typename F> | ||
| 45 | void ForEachLayer(F&& cb) { | ||
| 46 | for (auto& layer : m_layers) { | ||
| 47 | if (layer.IsInitialized()) { | ||
| 48 | cb(layer); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | private: | ||
| 54 | Layer* GetFreeLayer() { | ||
| 55 | for (auto& layer : m_layers) { | ||
| 56 | if (!layer.IsInitialized()) { | ||
| 57 | return &layer; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | return nullptr; | ||
| 62 | } | ||
| 63 | |||
| 64 | private: | ||
| 65 | std::array<Layer, 8> m_layers{}; | ||
| 66 | u64 m_next_id{}; | ||
| 67 | }; | ||
| 68 | |||
| 69 | } // namespace Service::VI | ||
diff --git a/src/core/hle/service/vi/manager_display_service.cpp b/src/core/hle/service/vi/manager_display_service.cpp index 17f2f3b8f..9f856282e 100644 --- a/src/core/hle/service/vi/manager_display_service.cpp +++ b/src/core/hle/service/vi/manager_display_service.cpp | |||
| @@ -2,22 +2,21 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "core/hle/service/cmif_serialization.h" | 4 | #include "core/hle/service/cmif_serialization.h" |
| 5 | #include "core/hle/service/nvnflinger/nvnflinger.h" | 5 | #include "core/hle/service/vi/container.h" |
| 6 | #include "core/hle/service/vi/manager_display_service.h" | 6 | #include "core/hle/service/vi/manager_display_service.h" |
| 7 | #include "core/hle/service/vi/vi_results.h" | ||
| 8 | 7 | ||
| 9 | namespace Service::VI { | 8 | namespace Service::VI { |
| 10 | 9 | ||
| 11 | IManagerDisplayService::IManagerDisplayService(Core::System& system_, | 10 | IManagerDisplayService::IManagerDisplayService(Core::System& system_, |
| 12 | Nvnflinger::Nvnflinger& nvnflinger) | 11 | std::shared_ptr<Container> container) |
| 13 | : ServiceFramework{system_, "IManagerDisplayService"}, m_nvnflinger{nvnflinger} { | 12 | : ServiceFramework{system_, "IManagerDisplayService"}, m_container{std::move(container)} { |
| 14 | // clang-format off | 13 | // clang-format off |
| 15 | static const FunctionInfo functions[] = { | 14 | static const FunctionInfo functions[] = { |
| 16 | {200, nullptr, "AllocateProcessHeapBlock"}, | 15 | {200, nullptr, "AllocateProcessHeapBlock"}, |
| 17 | {201, nullptr, "FreeProcessHeapBlock"}, | 16 | {201, nullptr, "FreeProcessHeapBlock"}, |
| 18 | {1102, nullptr, "GetDisplayResolution"}, | 17 | {1102, nullptr, "GetDisplayResolution"}, |
| 19 | {2010, C<&IManagerDisplayService::CreateManagedLayer>, "CreateManagedLayer"}, | 18 | {2010, C<&IManagerDisplayService::CreateManagedLayer>, "CreateManagedLayer"}, |
| 20 | {2011, nullptr, "DestroyManagedLayer"}, | 19 | {2011, C<&IManagerDisplayService::DestroyManagedLayer>, "DestroyManagedLayer"}, |
| 21 | {2012, nullptr, "CreateStrayLayer"}, | 20 | {2012, nullptr, "CreateStrayLayer"}, |
| 22 | {2050, nullptr, "CreateIndirectLayer"}, | 21 | {2050, nullptr, "CreateIndirectLayer"}, |
| 23 | {2051, nullptr, "DestroyIndirectLayer"}, | 22 | {2051, nullptr, "DestroyIndirectLayer"}, |
| @@ -102,19 +101,30 @@ IManagerDisplayService::IManagerDisplayService(Core::System& system_, | |||
| 102 | 101 | ||
| 103 | IManagerDisplayService::~IManagerDisplayService() = default; | 102 | IManagerDisplayService::~IManagerDisplayService() = default; |
| 104 | 103 | ||
| 105 | Result IManagerDisplayService::CreateManagedLayer(Out<u64> out_layer_id, u32 unknown, | 104 | Result IManagerDisplayService::CreateSharedLayerSession(Kernel::KProcess* owner_process, |
| 106 | u64 display_id, AppletResourceUserId aruid) { | 105 | u64* out_buffer_id, u64* out_layer_handle, |
| 107 | LOG_WARNING(Service_VI, "(STUBBED) called. unknown={}, display={}, aruid={}", unknown, | 106 | u64 display_id, bool enable_blending) { |
| 108 | display_id, aruid.pid); | 107 | R_RETURN(m_container->GetSharedBufferManager()->CreateSession( |
| 108 | owner_process, out_buffer_id, out_layer_handle, display_id, enable_blending)); | ||
| 109 | } | ||
| 109 | 110 | ||
| 110 | const auto layer_id = m_nvnflinger.CreateLayer(display_id); | 111 | void IManagerDisplayService::DestroySharedLayerSession(Kernel::KProcess* owner_process) { |
| 111 | if (!layer_id) { | 112 | m_container->GetSharedBufferManager()->DestroySession(owner_process); |
| 112 | LOG_ERROR(Service_VI, "Layer not found! display={}", display_id); | 113 | } |
| 113 | R_THROW(VI::ResultNotFound); | ||
| 114 | } | ||
| 115 | 114 | ||
| 116 | *out_layer_id = *layer_id; | 115 | Result IManagerDisplayService::SetLayerBlending(bool enabled, u64 layer_id) { |
| 117 | R_SUCCEED(); | 116 | R_RETURN(m_container->SetLayerBlending(layer_id, enabled)); |
| 117 | } | ||
| 118 | |||
| 119 | Result IManagerDisplayService::CreateManagedLayer(Out<u64> out_layer_id, u32 flags, u64 display_id, | ||
| 120 | AppletResourceUserId aruid) { | ||
| 121 | LOG_DEBUG(Service_VI, "called. flags={}, display={}, aruid={}", flags, display_id, aruid.pid); | ||
| 122 | R_RETURN(m_container->CreateManagedLayer(out_layer_id, display_id, aruid.pid)); | ||
| 123 | } | ||
| 124 | |||
| 125 | Result IManagerDisplayService::DestroyManagedLayer(u64 layer_id) { | ||
| 126 | LOG_DEBUG(Service_VI, "called. layer_id={}", layer_id); | ||
| 127 | R_RETURN(m_container->DestroyManagedLayer(layer_id)); | ||
| 118 | } | 128 | } |
| 119 | 129 | ||
| 120 | Result IManagerDisplayService::AddToLayerStack(u32 stack_id, u64 layer_id) { | 130 | Result IManagerDisplayService::AddToLayerStack(u32 stack_id, u64 layer_id) { |
| @@ -123,8 +133,8 @@ Result IManagerDisplayService::AddToLayerStack(u32 stack_id, u64 layer_id) { | |||
| 123 | } | 133 | } |
| 124 | 134 | ||
| 125 | Result IManagerDisplayService::SetLayerVisibility(bool visible, u64 layer_id) { | 135 | Result IManagerDisplayService::SetLayerVisibility(bool visible, u64 layer_id) { |
| 126 | LOG_WARNING(Service_VI, "(STUBBED) called, layer_id={}, visible={}", layer_id, visible); | 136 | LOG_DEBUG(Service_VI, "called, layer_id={}, visible={}", layer_id, visible); |
| 127 | R_SUCCEED(); | 137 | R_RETURN(m_container->SetLayerVisibility(layer_id, visible)); |
| 128 | } | 138 | } |
| 129 | 139 | ||
| 130 | } // namespace Service::VI | 140 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/manager_display_service.h b/src/core/hle/service/vi/manager_display_service.h index 60e646ee0..b1bdf7f41 100644 --- a/src/core/hle/service/vi/manager_display_service.h +++ b/src/core/hle/service/vi/manager_display_service.h | |||
| @@ -4,21 +4,34 @@ | |||
| 4 | #include "core/hle/service/cmif_types.h" | 4 | #include "core/hle/service/cmif_types.h" |
| 5 | #include "core/hle/service/service.h" | 5 | #include "core/hle/service/service.h" |
| 6 | 6 | ||
| 7 | namespace Kernel { | ||
| 8 | class KProcess; | ||
| 9 | } | ||
| 10 | |||
| 7 | namespace Service::VI { | 11 | namespace Service::VI { |
| 8 | 12 | ||
| 13 | class Container; | ||
| 14 | |||
| 9 | class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { | 15 | class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { |
| 10 | public: | 16 | public: |
| 11 | explicit IManagerDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger); | 17 | explicit IManagerDisplayService(Core::System& system_, std::shared_ptr<Container> container); |
| 12 | ~IManagerDisplayService() override; | 18 | ~IManagerDisplayService() override; |
| 13 | 19 | ||
| 14 | private: | 20 | Result CreateSharedLayerSession(Kernel::KProcess* owner_process, u64* out_buffer_id, |
| 15 | Result CreateManagedLayer(Out<u64> out_layer_id, u32 unknown, u64 display_id, | 21 | u64* out_layer_handle, u64 display_id, bool enable_blending); |
| 22 | void DestroySharedLayerSession(Kernel::KProcess* owner_process); | ||
| 23 | |||
| 24 | Result SetLayerBlending(bool enabled, u64 layer_id); | ||
| 25 | |||
| 26 | public: | ||
| 27 | Result CreateManagedLayer(Out<u64> out_layer_id, u32 flags, u64 display_id, | ||
| 16 | AppletResourceUserId aruid); | 28 | AppletResourceUserId aruid); |
| 29 | Result DestroyManagedLayer(u64 layer_id); | ||
| 17 | Result AddToLayerStack(u32 stack_id, u64 layer_id); | 30 | Result AddToLayerStack(u32 stack_id, u64 layer_id); |
| 18 | Result SetLayerVisibility(bool visible, u64 layer_id); | 31 | Result SetLayerVisibility(bool visible, u64 layer_id); |
| 19 | 32 | ||
| 20 | private: | 33 | private: |
| 21 | Nvnflinger::Nvnflinger& m_nvnflinger; | 34 | const std::shared_ptr<Container> m_container; |
| 22 | }; | 35 | }; |
| 23 | 36 | ||
| 24 | } // namespace Service::VI | 37 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/manager_root_service.cpp b/src/core/hle/service/vi/manager_root_service.cpp index a7eee4f04..0f16a15b4 100644 --- a/src/core/hle/service/vi/manager_root_service.cpp +++ b/src/core/hle/service/vi/manager_root_service.cpp | |||
| @@ -2,7 +2,9 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "core/hle/service/cmif_serialization.h" | 4 | #include "core/hle/service/cmif_serialization.h" |
| 5 | #include "core/hle/service/nvnflinger/hos_binder_driver.h" | ||
| 5 | #include "core/hle/service/vi/application_display_service.h" | 6 | #include "core/hle/service/vi/application_display_service.h" |
| 7 | #include "core/hle/service/vi/container.h" | ||
| 6 | #include "core/hle/service/vi/manager_root_service.h" | 8 | #include "core/hle/service/vi/manager_root_service.h" |
| 7 | #include "core/hle/service/vi/service_creator.h" | 9 | #include "core/hle/service/vi/service_creator.h" |
| 8 | #include "core/hle/service/vi/vi.h" | 10 | #include "core/hle/service/vi/vi.h" |
| @@ -10,11 +12,9 @@ | |||
| 10 | 12 | ||
| 11 | namespace Service::VI { | 13 | namespace Service::VI { |
| 12 | 14 | ||
| 13 | IManagerRootService::IManagerRootService( | 15 | IManagerRootService::IManagerRootService(Core::System& system_, |
| 14 | Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, | 16 | std::shared_ptr<Container> container) |
| 15 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) | 17 | : ServiceFramework{system_, "vi:m"}, m_container{std::move(container)} { |
| 16 | : ServiceFramework{system_, "vi:m"}, m_nvnflinger{nvnflinger}, m_hos_binder_driver_server{ | ||
| 17 | hos_binder_driver_server} { | ||
| 18 | static const FunctionInfo functions[] = { | 18 | static const FunctionInfo functions[] = { |
| 19 | {2, C<&IManagerRootService::GetDisplayService>, "GetDisplayService"}, | 19 | {2, C<&IManagerRootService::GetDisplayService>, "GetDisplayService"}, |
| 20 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, | 20 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, |
| @@ -31,8 +31,8 @@ IManagerRootService::~IManagerRootService() = default; | |||
| 31 | Result IManagerRootService::GetDisplayService( | 31 | Result IManagerRootService::GetDisplayService( |
| 32 | Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) { | 32 | Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) { |
| 33 | LOG_DEBUG(Service_VI, "called"); | 33 | LOG_DEBUG(Service_VI, "called"); |
| 34 | R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_nvnflinger, | 34 | R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_container, |
| 35 | m_hos_binder_driver_server, Permission::Manager, policy)); | 35 | Permission::Manager, policy)); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | } // namespace Service::VI | 38 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/manager_root_service.h b/src/core/hle/service/vi/manager_root_service.h index e6cb77aeb..77cd32869 100644 --- a/src/core/hle/service/vi/manager_root_service.h +++ b/src/core/hle/service/vi/manager_root_service.h | |||
| @@ -10,29 +10,23 @@ namespace Core { | |||
| 10 | class System; | 10 | class System; |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | namespace Service::Nvnflinger { | ||
| 14 | class HosBinderDriverServer; | ||
| 15 | class Nvnflinger; | ||
| 16 | } // namespace Service::Nvnflinger | ||
| 17 | |||
| 18 | namespace Service::VI { | 13 | namespace Service::VI { |
| 19 | 14 | ||
| 15 | class Container; | ||
| 20 | class IApplicationDisplayService; | 16 | class IApplicationDisplayService; |
| 21 | enum class Policy : u32; | 17 | enum class Policy : u32; |
| 22 | 18 | ||
| 23 | class IManagerRootService final : public ServiceFramework<IManagerRootService> { | 19 | class IManagerRootService final : public ServiceFramework<IManagerRootService> { |
| 24 | public: | 20 | public: |
| 25 | explicit IManagerRootService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, | 21 | explicit IManagerRootService(Core::System& system_, std::shared_ptr<Container> container); |
| 26 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server); | ||
| 27 | ~IManagerRootService() override; | 22 | ~IManagerRootService() override; |
| 28 | 23 | ||
| 29 | private: | ||
| 30 | Result GetDisplayService( | 24 | Result GetDisplayService( |
| 31 | Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, | 25 | Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, |
| 32 | Policy policy); | 26 | Policy policy); |
| 33 | 27 | ||
| 34 | Nvnflinger::Nvnflinger& m_nvnflinger; | 28 | private: |
| 35 | Nvnflinger::HosBinderDriverServer& m_hos_binder_driver_server; | 29 | const std::shared_ptr<Container> m_container; |
| 36 | }; | 30 | }; |
| 37 | 31 | ||
| 38 | } // namespace Service::VI | 32 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/service_creator.cpp b/src/core/hle/service/vi/service_creator.cpp index 1de9d61a4..2b8e5f957 100644 --- a/src/core/hle/service/vi/service_creator.cpp +++ b/src/core/hle/service/vi/service_creator.cpp | |||
| @@ -22,8 +22,7 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) { | |||
| 22 | 22 | ||
| 23 | Result GetApplicationDisplayService( | 23 | Result GetApplicationDisplayService( |
| 24 | std::shared_ptr<IApplicationDisplayService>* out_application_display_service, | 24 | std::shared_ptr<IApplicationDisplayService>* out_application_display_service, |
| 25 | Core::System& system, Nvnflinger::Nvnflinger& nvnflinger, | 25 | Core::System& system, std::shared_ptr<Container> container, Permission permission, |
| 26 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server, Permission permission, | ||
| 27 | Policy policy) { | 26 | Policy policy) { |
| 28 | 27 | ||
| 29 | if (!IsValidServiceAccess(permission, policy)) { | 28 | if (!IsValidServiceAccess(permission, policy)) { |
| @@ -32,7 +31,7 @@ Result GetApplicationDisplayService( | |||
| 32 | } | 31 | } |
| 33 | 32 | ||
| 34 | *out_application_display_service = | 33 | *out_application_display_service = |
| 35 | std::make_shared<IApplicationDisplayService>(system, nvnflinger, hos_binder_driver_server); | 34 | std::make_shared<IApplicationDisplayService>(system, std::move(container)); |
| 36 | R_SUCCEED(); | 35 | R_SUCCEED(); |
| 37 | } | 36 | } |
| 38 | 37 | ||
diff --git a/src/core/hle/service/vi/service_creator.h b/src/core/hle/service/vi/service_creator.h index 8963bcd26..c6ba1797d 100644 --- a/src/core/hle/service/vi/service_creator.h +++ b/src/core/hle/service/vi/service_creator.h | |||
| @@ -11,23 +11,18 @@ namespace Core { | |||
| 11 | class System; | 11 | class System; |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | namespace Service::Nvnflinger { | ||
| 15 | class HosBinderDriverServer; | ||
| 16 | class Nvnflinger; | ||
| 17 | } // namespace Service::Nvnflinger | ||
| 18 | |||
| 19 | union Result; | 14 | union Result; |
| 20 | 15 | ||
| 21 | namespace Service::VI { | 16 | namespace Service::VI { |
| 22 | 17 | ||
| 18 | class Container; | ||
| 23 | class IApplicationDisplayService; | 19 | class IApplicationDisplayService; |
| 24 | enum class Permission; | 20 | enum class Permission; |
| 25 | enum class Policy : u32; | 21 | enum class Policy : u32; |
| 26 | 22 | ||
| 27 | Result GetApplicationDisplayService( | 23 | Result GetApplicationDisplayService( |
| 28 | std::shared_ptr<IApplicationDisplayService>* out_application_display_service, | 24 | std::shared_ptr<IApplicationDisplayService>* out_application_display_service, |
| 29 | Core::System& system, Nvnflinger::Nvnflinger& nvnflinger, | 25 | Core::System& system, std::shared_ptr<Container> container, Permission permission, |
| 30 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server, Permission permission, | ||
| 31 | Policy policy); | 26 | Policy policy); |
| 32 | 27 | ||
| 33 | } // namespace Service::VI | 28 | } // namespace Service::VI |
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/vi/shared_buffer_manager.cpp index 90f7248a0..869b18961 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp +++ b/src/core/hle/service/vi/shared_buffer_manager.cpp | |||
| @@ -9,15 +9,15 @@ | |||
| 9 | #include "core/hle/service/nvdrv/devices/nvmap.h" | 9 | #include "core/hle/service/nvdrv/devices/nvmap.h" |
| 10 | #include "core/hle/service/nvdrv/nvdrv.h" | 10 | #include "core/hle/service/nvdrv/nvdrv.h" |
| 11 | #include "core/hle/service/nvnflinger/buffer_queue_producer.h" | 11 | #include "core/hle/service/nvnflinger/buffer_queue_producer.h" |
| 12 | #include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" | ||
| 13 | #include "core/hle/service/nvnflinger/pixel_format.h" | 12 | #include "core/hle/service/nvnflinger/pixel_format.h" |
| 14 | #include "core/hle/service/nvnflinger/ui/graphic_buffer.h" | 13 | #include "core/hle/service/nvnflinger/ui/graphic_buffer.h" |
| 15 | #include "core/hle/service/vi/layer/vi_layer.h" | 14 | #include "core/hle/service/vi/container.h" |
| 15 | #include "core/hle/service/vi/shared_buffer_manager.h" | ||
| 16 | #include "core/hle/service/vi/vi_results.h" | 16 | #include "core/hle/service/vi/vi_results.h" |
| 17 | #include "video_core/gpu.h" | 17 | #include "video_core/gpu.h" |
| 18 | #include "video_core/host1x/host1x.h" | 18 | #include "video_core/host1x/host1x.h" |
| 19 | 19 | ||
| 20 | namespace Service::Nvnflinger { | 20 | namespace Service::VI { |
| 21 | 21 | ||
| 22 | namespace { | 22 | namespace { |
| 23 | 23 | ||
| @@ -26,7 +26,6 @@ Result AllocateSharedBufferMemory(std::unique_ptr<Kernel::KPageGroup>* out_page_ | |||
| 26 | using Core::Memory::YUZU_PAGESIZE; | 26 | using Core::Memory::YUZU_PAGESIZE; |
| 27 | 27 | ||
| 28 | // Allocate memory for the system shared buffer. | 28 | // Allocate memory for the system shared buffer. |
| 29 | // FIXME: This memory belongs to vi's .data section. | ||
| 30 | auto& kernel = system.Kernel(); | 29 | auto& kernel = system.Kernel(); |
| 31 | 30 | ||
| 32 | // Hold a temporary page group reference while we try to map it. | 31 | // Hold a temporary page group reference while we try to map it. |
| @@ -204,15 +203,15 @@ void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 han | |||
| 204 | 203 | ||
| 205 | } // namespace | 204 | } // namespace |
| 206 | 205 | ||
| 207 | FbShareBufferManager::FbShareBufferManager(Core::System& system, Nvnflinger& flinger, | 206 | SharedBufferManager::SharedBufferManager(Core::System& system, Container& container, |
| 208 | std::shared_ptr<Nvidia::Module> nvdrv) | 207 | std::shared_ptr<Nvidia::Module> nvdrv) |
| 209 | : m_system(system), m_flinger(flinger), m_nvdrv(std::move(nvdrv)) {} | 208 | : m_system(system), m_container(container), m_nvdrv(std::move(nvdrv)) {} |
| 210 | 209 | ||
| 211 | FbShareBufferManager::~FbShareBufferManager() = default; | 210 | SharedBufferManager::~SharedBufferManager() = default; |
| 212 | 211 | ||
| 213 | Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, | 212 | Result SharedBufferManager::CreateSession(Kernel::KProcess* owner_process, u64* out_buffer_id, |
| 214 | u64* out_layer_handle, u64 display_id, | 213 | u64* out_layer_handle, u64 display_id, |
| 215 | LayerBlending blending) { | 214 | bool enable_blending) { |
| 216 | std::scoped_lock lk{m_guard}; | 215 | std::scoped_lock lk{m_guard}; |
| 217 | 216 | ||
| 218 | // Ensure we haven't already created. | 217 | // Ensure we haven't already created. |
| @@ -237,7 +236,7 @@ Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou | |||
| 237 | owner_process, m_system)); | 236 | owner_process, m_system)); |
| 238 | 237 | ||
| 239 | // Create new session. | 238 | // Create new session. |
| 240 | auto [it, was_emplaced] = m_sessions.emplace(aruid, FbShareSession{}); | 239 | auto [it, was_emplaced] = m_sessions.emplace(aruid, SharedBufferSession{}); |
| 241 | auto& session = it->second; | 240 | auto& session = it->second; |
| 242 | 241 | ||
| 243 | auto& container = m_nvdrv->GetContainer(); | 242 | auto& container = m_nvdrv->GetContainer(); |
| @@ -249,17 +248,18 @@ Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou | |||
| 249 | session.nvmap_fd, map_address, SharedBufferSize)); | 248 | session.nvmap_fd, map_address, SharedBufferSize)); |
| 250 | 249 | ||
| 251 | // Create and open a layer for the display. | 250 | // Create and open a layer for the display. |
| 252 | session.layer_id = m_flinger.CreateLayer(m_display_id, blending).value(); | 251 | s32 producer_binder_id; |
| 253 | m_flinger.OpenLayer(session.layer_id); | 252 | R_TRY(m_container.CreateStrayLayer(std::addressof(producer_binder_id), |
| 253 | std::addressof(session.layer_id), display_id)); | ||
| 254 | 254 | ||
| 255 | // Get the layer. | 255 | // Configure blending. |
| 256 | VI::Layer* layer = m_flinger.FindLayer(m_display_id, session.layer_id); | 256 | R_ASSERT(m_container.SetLayerBlending(session.layer_id, enable_blending)); |
| 257 | ASSERT(layer != nullptr); | ||
| 258 | 257 | ||
| 259 | // Get the producer and set preallocated buffers. | 258 | // Get the producer and set preallocated buffers. |
| 260 | auto& producer = layer->GetBufferQueue(); | 259 | std::shared_ptr<android::BufferQueueProducer> producer; |
| 261 | MakeGraphicBuffer(producer, 0, session.buffer_nvmap_handle); | 260 | R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), session.layer_id)); |
| 262 | MakeGraphicBuffer(producer, 1, session.buffer_nvmap_handle); | 261 | MakeGraphicBuffer(*producer, 0, session.buffer_nvmap_handle); |
| 262 | MakeGraphicBuffer(*producer, 1, session.buffer_nvmap_handle); | ||
| 263 | 263 | ||
| 264 | // Assign outputs. | 264 | // Assign outputs. |
| 265 | *out_buffer_id = m_buffer_id; | 265 | *out_buffer_id = m_buffer_id; |
| @@ -269,7 +269,7 @@ Result FbShareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou | |||
| 269 | R_SUCCEED(); | 269 | R_SUCCEED(); |
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | void FbShareBufferManager::Finalize(Kernel::KProcess* owner_process) { | 272 | void SharedBufferManager::DestroySession(Kernel::KProcess* owner_process) { |
| 273 | std::scoped_lock lk{m_guard}; | 273 | std::scoped_lock lk{m_guard}; |
| 274 | 274 | ||
| 275 | if (m_buffer_id == 0) { | 275 | if (m_buffer_id == 0) { |
| @@ -285,7 +285,7 @@ void FbShareBufferManager::Finalize(Kernel::KProcess* owner_process) { | |||
| 285 | auto& session = it->second; | 285 | auto& session = it->second; |
| 286 | 286 | ||
| 287 | // Destroy the layer. | 287 | // Destroy the layer. |
| 288 | m_flinger.DestroyLayer(session.layer_id); | 288 | R_ASSERT(m_container.DestroyStrayLayer(session.layer_id)); |
| 289 | 289 | ||
| 290 | // Close nvmap handle. | 290 | // Close nvmap handle. |
| 291 | FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd); | 291 | FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd); |
| @@ -301,11 +301,11 @@ void FbShareBufferManager::Finalize(Kernel::KProcess* owner_process) { | |||
| 301 | m_sessions.erase(it); | 301 | m_sessions.erase(it); |
| 302 | } | 302 | } |
| 303 | 303 | ||
| 304 | Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size, | 304 | Result SharedBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size, |
| 305 | s32* out_nvmap_handle, | 305 | s32* out_nvmap_handle, |
| 306 | SharedMemoryPoolLayout* out_pool_layout, | 306 | SharedMemoryPoolLayout* out_pool_layout, |
| 307 | u64 buffer_id, | 307 | u64 buffer_id, |
| 308 | u64 applet_resource_user_id) { | 308 | u64 applet_resource_user_id) { |
| 309 | std::scoped_lock lk{m_guard}; | 309 | std::scoped_lock lk{m_guard}; |
| 310 | 310 | ||
| 311 | R_UNLESS(m_buffer_id > 0, VI::ResultNotFound); | 311 | R_UNLESS(m_buffer_id > 0, VI::ResultNotFound); |
| @@ -319,36 +319,20 @@ Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size, | |||
| 319 | R_SUCCEED(); | 319 | R_SUCCEED(); |
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | Result FbShareBufferManager::GetLayerFromId(VI::Layer** out_layer, u64 layer_id) { | 322 | Result SharedBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence, |
| 323 | // Ensure the layer id is valid. | 323 | std::array<s32, 4>& out_slot_indexes, |
| 324 | R_UNLESS(layer_id > 0, VI::ResultNotFound); | 324 | s64* out_target_slot, u64 layer_id) { |
| 325 | |||
| 326 | // Get the layer. | ||
| 327 | VI::Layer* layer = m_flinger.FindLayer(m_display_id, layer_id); | ||
| 328 | R_UNLESS(layer != nullptr, VI::ResultNotFound); | ||
| 329 | |||
| 330 | // We succeeded. | ||
| 331 | *out_layer = layer; | ||
| 332 | R_SUCCEED(); | ||
| 333 | } | ||
| 334 | |||
| 335 | Result FbShareBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence, | ||
| 336 | std::array<s32, 4>& out_slot_indexes, | ||
| 337 | s64* out_target_slot, u64 layer_id) { | ||
| 338 | std::scoped_lock lk{m_guard}; | 325 | std::scoped_lock lk{m_guard}; |
| 339 | 326 | ||
| 340 | // Get the layer. | ||
| 341 | VI::Layer* layer; | ||
| 342 | R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id)); | ||
| 343 | |||
| 344 | // Get the producer. | 327 | // Get the producer. |
| 345 | auto& producer = layer->GetBufferQueue(); | 328 | std::shared_ptr<android::BufferQueueProducer> producer; |
| 329 | R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); | ||
| 346 | 330 | ||
| 347 | // Get the next buffer from the producer. | 331 | // Get the next buffer from the producer. |
| 348 | s32 slot; | 332 | s32 slot; |
| 349 | R_UNLESS(producer.DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0, | 333 | R_UNLESS(producer->DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0, |
| 350 | SharedBufferWidth, SharedBufferHeight, | 334 | SharedBufferWidth, SharedBufferHeight, |
| 351 | SharedBufferBlockLinearFormat, 0) == android::Status::NoError, | 335 | SharedBufferBlockLinearFormat, 0) == android::Status::NoError, |
| 352 | VI::ResultOperationFailed); | 336 | VI::ResultOperationFailed); |
| 353 | 337 | ||
| 354 | // Assign remaining outputs. | 338 | // Assign remaining outputs. |
| @@ -359,27 +343,24 @@ Result FbShareBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence, | |||
| 359 | R_SUCCEED(); | 343 | R_SUCCEED(); |
| 360 | } | 344 | } |
| 361 | 345 | ||
| 362 | Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence, | 346 | Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence, |
| 363 | Common::Rectangle<s32> crop_region, | 347 | Common::Rectangle<s32> crop_region, |
| 364 | u32 transform, s32 swap_interval, | 348 | u32 transform, s32 swap_interval, u64 layer_id, |
| 365 | u64 layer_id, s64 slot) { | 349 | s64 slot) { |
| 366 | std::scoped_lock lk{m_guard}; | 350 | std::scoped_lock lk{m_guard}; |
| 367 | 351 | ||
| 368 | // Get the layer. | ||
| 369 | VI::Layer* layer; | ||
| 370 | R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id)); | ||
| 371 | |||
| 372 | // Get the producer. | 352 | // Get the producer. |
| 373 | auto& producer = layer->GetBufferQueue(); | 353 | std::shared_ptr<android::BufferQueueProducer> producer; |
| 354 | R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); | ||
| 374 | 355 | ||
| 375 | // Request to queue the buffer. | 356 | // Request to queue the buffer. |
| 376 | std::shared_ptr<android::GraphicBuffer> buffer; | 357 | std::shared_ptr<android::GraphicBuffer> buffer; |
| 377 | R_UNLESS(producer.RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) == | 358 | R_UNLESS(producer->RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) == |
| 378 | android::Status::NoError, | 359 | android::Status::NoError, |
| 379 | VI::ResultOperationFailed); | 360 | VI::ResultOperationFailed); |
| 380 | 361 | ||
| 381 | ON_RESULT_FAILURE { | 362 | ON_RESULT_FAILURE { |
| 382 | producer.CancelBuffer(static_cast<s32>(slot), fence); | 363 | producer->CancelBuffer(static_cast<s32>(slot), fence); |
| 383 | }; | 364 | }; |
| 384 | 365 | ||
| 385 | // Queue the buffer to the producer. | 366 | // Queue the buffer to the producer. |
| @@ -389,7 +370,7 @@ Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence, | |||
| 389 | input.fence = fence; | 370 | input.fence = fence; |
| 390 | input.transform = static_cast<android::NativeWindowTransform>(transform); | 371 | input.transform = static_cast<android::NativeWindowTransform>(transform); |
| 391 | input.swap_interval = swap_interval; | 372 | input.swap_interval = swap_interval; |
| 392 | R_UNLESS(producer.QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) == | 373 | R_UNLESS(producer->QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) == |
| 393 | android::Status::NoError, | 374 | android::Status::NoError, |
| 394 | VI::ResultOperationFailed); | 375 | VI::ResultOperationFailed); |
| 395 | 376 | ||
| @@ -397,25 +378,36 @@ Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence, | |||
| 397 | R_SUCCEED(); | 378 | R_SUCCEED(); |
| 398 | } | 379 | } |
| 399 | 380 | ||
| 400 | Result FbShareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, | 381 | Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) { |
| 401 | u64 layer_id) { | ||
| 402 | std::scoped_lock lk{m_guard}; | 382 | std::scoped_lock lk{m_guard}; |
| 403 | 383 | ||
| 404 | // Get the layer. | 384 | // Get the producer. |
| 405 | VI::Layer* layer; | 385 | std::shared_ptr<android::BufferQueueProducer> producer; |
| 406 | R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id)); | 386 | R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); |
| 387 | |||
| 388 | // Cancel. | ||
| 389 | producer->CancelBuffer(static_cast<s32>(slot), android::Fence::NoFence()); | ||
| 390 | |||
| 391 | // We succeeded. | ||
| 392 | R_SUCCEED(); | ||
| 393 | } | ||
| 394 | |||
| 395 | Result SharedBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, | ||
| 396 | u64 layer_id) { | ||
| 397 | std::scoped_lock lk{m_guard}; | ||
| 407 | 398 | ||
| 408 | // Get the producer. | 399 | // Get the producer. |
| 409 | auto& producer = layer->GetBufferQueue(); | 400 | std::shared_ptr<android::BufferQueueProducer> producer; |
| 401 | R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); | ||
| 410 | 402 | ||
| 411 | // Set the event. | 403 | // Set the event. |
| 412 | *out_event = std::addressof(producer.GetNativeHandle()); | 404 | *out_event = producer->GetNativeHandle({}); |
| 413 | 405 | ||
| 414 | // We succeeded. | 406 | // We succeeded. |
| 415 | R_SUCCEED(); | 407 | R_SUCCEED(); |
| 416 | } | 408 | } |
| 417 | 409 | ||
| 418 | Result FbShareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) { | 410 | Result SharedBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) { |
| 419 | std::vector<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer()); | 411 | std::vector<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer()); |
| 420 | Common::ScratchBuffer<u32> scratch; | 412 | Common::ScratchBuffer<u32> scratch; |
| 421 | 413 | ||
| @@ -444,4 +436,4 @@ Result FbShareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32 | |||
| 444 | R_SUCCEED(); | 436 | R_SUCCEED(); |
| 445 | } | 437 | } |
| 446 | 438 | ||
| 447 | } // namespace Service::Nvnflinger | 439 | } // namespace Service::VI |
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h b/src/core/hle/service/vi/shared_buffer_manager.h index b79a7d23a..7c9bb7199 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h +++ b/src/core/hle/service/vi/shared_buffer_manager.h | |||
| @@ -8,15 +8,27 @@ | |||
| 8 | #include "common/math_util.h" | 8 | #include "common/math_util.h" |
| 9 | #include "core/hle/service/nvdrv/core/container.h" | 9 | #include "core/hle/service/nvdrv/core/container.h" |
| 10 | #include "core/hle/service/nvdrv/nvdata.h" | 10 | #include "core/hle/service/nvdrv/nvdata.h" |
| 11 | #include "core/hle/service/nvnflinger/hwc_layer.h" | ||
| 12 | #include "core/hle/service/nvnflinger/nvnflinger.h" | 11 | #include "core/hle/service/nvnflinger/nvnflinger.h" |
| 13 | #include "core/hle/service/nvnflinger/ui/fence.h" | 12 | #include "core/hle/service/nvnflinger/ui/fence.h" |
| 14 | 13 | ||
| 15 | namespace Kernel { | 14 | namespace Kernel { |
| 16 | class KPageGroup; | 15 | class KPageGroup; |
| 16 | class KReadableEvent; | ||
| 17 | } // namespace Kernel | ||
| 18 | |||
| 19 | namespace Service::android { | ||
| 20 | class BufferQueueProducer; | ||
| 21 | } | ||
| 22 | |||
| 23 | namespace Service::Nvidia { | ||
| 24 | class Module; | ||
| 17 | } | 25 | } |
| 18 | 26 | ||
| 19 | namespace Service::Nvnflinger { | 27 | union Result; |
| 28 | |||
| 29 | namespace Service::VI { | ||
| 30 | |||
| 31 | class Container; | ||
| 20 | 32 | ||
| 21 | struct SharedMemorySlot { | 33 | struct SharedMemorySlot { |
| 22 | u64 buffer_offset; | 34 | u64 buffer_offset; |
| @@ -32,17 +44,17 @@ struct SharedMemoryPoolLayout { | |||
| 32 | }; | 44 | }; |
| 33 | static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size"); | 45 | static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size"); |
| 34 | 46 | ||
| 35 | struct FbShareSession; | 47 | struct SharedBufferSession; |
| 36 | 48 | ||
| 37 | class FbShareBufferManager final { | 49 | class SharedBufferManager final { |
| 38 | public: | 50 | public: |
| 39 | explicit FbShareBufferManager(Core::System& system, Nvnflinger& flinger, | 51 | explicit SharedBufferManager(Core::System& system, Container& container, |
| 40 | std::shared_ptr<Nvidia::Module> nvdrv); | 52 | std::shared_ptr<Nvidia::Module> nvdrv); |
| 41 | ~FbShareBufferManager(); | 53 | ~SharedBufferManager(); |
| 42 | 54 | ||
| 43 | Result Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle, | 55 | Result CreateSession(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle, |
| 44 | u64 display_id, LayerBlending blending); | 56 | u64 display_id, bool enable_blending); |
| 45 | void Finalize(Kernel::KProcess* owner_process); | 57 | void DestroySession(Kernel::KProcess* owner_process); |
| 46 | 58 | ||
| 47 | Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle, | 59 | Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle, |
| 48 | SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id, | 60 | SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id, |
| @@ -51,32 +63,30 @@ public: | |||
| 51 | s64* out_target_slot, u64 layer_id); | 63 | s64* out_target_slot, u64 layer_id); |
| 52 | Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region, | 64 | Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region, |
| 53 | u32 transform, s32 swap_interval, u64 layer_id, s64 slot); | 65 | u32 transform, s32 swap_interval, u64 layer_id, s64 slot); |
| 66 | Result CancelSharedFrameBuffer(u64 layer_id, s64 slot); | ||
| 54 | Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id); | 67 | Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id); |
| 55 | 68 | ||
| 56 | Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index); | 69 | Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index); |
| 57 | 70 | ||
| 58 | private: | 71 | private: |
| 59 | Result GetLayerFromId(VI::Layer** out_layer, u64 layer_id); | ||
| 60 | |||
| 61 | private: | ||
| 62 | u64 m_next_buffer_id = 1; | 72 | u64 m_next_buffer_id = 1; |
| 63 | u64 m_display_id = 0; | 73 | u64 m_display_id = 0; |
| 64 | u64 m_buffer_id = 0; | 74 | u64 m_buffer_id = 0; |
| 65 | SharedMemoryPoolLayout m_pool_layout = {}; | 75 | SharedMemoryPoolLayout m_pool_layout = {}; |
| 66 | std::map<u64, FbShareSession> m_sessions; | 76 | std::map<u64, SharedBufferSession> m_sessions; |
| 67 | std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group; | 77 | std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group; |
| 68 | 78 | ||
| 69 | std::mutex m_guard; | 79 | std::mutex m_guard; |
| 70 | Core::System& m_system; | 80 | Core::System& m_system; |
| 71 | Nvnflinger& m_flinger; | 81 | Container& m_container; |
| 72 | std::shared_ptr<Nvidia::Module> m_nvdrv; | 82 | const std::shared_ptr<Nvidia::Module> m_nvdrv; |
| 73 | }; | 83 | }; |
| 74 | 84 | ||
| 75 | struct FbShareSession { | 85 | struct SharedBufferSession { |
| 76 | Nvidia::DeviceFD nvmap_fd = {}; | 86 | Nvidia::DeviceFD nvmap_fd = {}; |
| 77 | Nvidia::NvCore::SessionId session_id = {}; | 87 | Nvidia::NvCore::SessionId session_id = {}; |
| 78 | u64 layer_id = {}; | 88 | u64 layer_id = {}; |
| 79 | u32 buffer_nvmap_handle = 0; | 89 | u32 buffer_nvmap_handle = 0; |
| 80 | }; | 90 | }; |
| 81 | 91 | ||
| 82 | } // namespace Service::Nvnflinger | 92 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/system_display_service.cpp b/src/core/hle/service/vi/system_display_service.cpp index 1e1cfc817..c3c50b07b 100644 --- a/src/core/hle/service/vi/system_display_service.cpp +++ b/src/core/hle/service/vi/system_display_service.cpp | |||
| @@ -3,15 +3,15 @@ | |||
| 3 | 3 | ||
| 4 | #include "common/settings.h" | 4 | #include "common/settings.h" |
| 5 | #include "core/hle/service/cmif_serialization.h" | 5 | #include "core/hle/service/cmif_serialization.h" |
| 6 | #include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" | 6 | #include "core/hle/service/vi/container.h" |
| 7 | #include "core/hle/service/vi/system_display_service.h" | 7 | #include "core/hle/service/vi/system_display_service.h" |
| 8 | #include "core/hle/service/vi/vi_types.h" | 8 | #include "core/hle/service/vi/vi_types.h" |
| 9 | 9 | ||
| 10 | namespace Service::VI { | 10 | namespace Service::VI { |
| 11 | 11 | ||
| 12 | ISystemDisplayService::ISystemDisplayService(Core::System& system_, | 12 | ISystemDisplayService::ISystemDisplayService(Core::System& system_, |
| 13 | Nvnflinger::Nvnflinger& nvnflinger) | 13 | std::shared_ptr<Container> container) |
| 14 | : ServiceFramework{system_, "ISystemDisplayService"}, m_nvnflinger{nvnflinger} { | 14 | : ServiceFramework{system_, "ISystemDisplayService"}, m_container{std::move(container)} { |
| 15 | // clang-format off | 15 | // clang-format off |
| 16 | static const FunctionInfo functions[] = { | 16 | static const FunctionInfo functions[] = { |
| 17 | {1200, nullptr, "GetZOrderCountMin"}, | 17 | {1200, nullptr, "GetZOrderCountMin"}, |
| @@ -29,7 +29,7 @@ ISystemDisplayService::ISystemDisplayService(Core::System& system_, | |||
| 29 | {2400, nullptr, "OpenIndirectLayer"}, | 29 | {2400, nullptr, "OpenIndirectLayer"}, |
| 30 | {2401, nullptr, "CloseIndirectLayer"}, | 30 | {2401, nullptr, "CloseIndirectLayer"}, |
| 31 | {2402, nullptr, "FlipIndirectLayer"}, | 31 | {2402, nullptr, "FlipIndirectLayer"}, |
| 32 | {3000, nullptr, "ListDisplayModes"}, | 32 | {3000, C<&ISystemDisplayService::ListDisplayModes>, "ListDisplayModes"}, |
| 33 | {3001, nullptr, "ListDisplayRgbRanges"}, | 33 | {3001, nullptr, "ListDisplayRgbRanges"}, |
| 34 | {3002, nullptr, "ListDisplayContentTypes"}, | 34 | {3002, nullptr, "ListDisplayContentTypes"}, |
| 35 | {3200, C<&ISystemDisplayService::GetDisplayMode>, "GetDisplayMode"}, | 35 | {3200, C<&ISystemDisplayService::GetDisplayMode>, "GetDisplayMode"}, |
| @@ -59,7 +59,7 @@ ISystemDisplayService::ISystemDisplayService(Core::System& system_, | |||
| 59 | {8255, C<&ISystemDisplayService::PresentSharedFrameBuffer>, "PresentSharedFrameBuffer"}, | 59 | {8255, C<&ISystemDisplayService::PresentSharedFrameBuffer>, "PresentSharedFrameBuffer"}, |
| 60 | {8256, C<&ISystemDisplayService::GetSharedFrameBufferAcquirableEvent>, "GetSharedFrameBufferAcquirableEvent"}, | 60 | {8256, C<&ISystemDisplayService::GetSharedFrameBufferAcquirableEvent>, "GetSharedFrameBufferAcquirableEvent"}, |
| 61 | {8257, nullptr, "FillSharedFrameBufferColor"}, | 61 | {8257, nullptr, "FillSharedFrameBufferColor"}, |
| 62 | {8258, nullptr, "CancelSharedFrameBuffer"}, | 62 | {8258, C<&ISystemDisplayService::CancelSharedFrameBuffer>, "CancelSharedFrameBuffer"}, |
| 63 | {9000, nullptr, "GetDp2hdmiController"}, | 63 | {9000, nullptr, "GetDp2hdmiController"}, |
| 64 | }; | 64 | }; |
| 65 | // clang-format on | 65 | // clang-format on |
| @@ -80,31 +80,50 @@ Result ISystemDisplayService::SetLayerVisibility(bool visible, u64 layer_id) { | |||
| 80 | R_SUCCEED(); | 80 | R_SUCCEED(); |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | Result ISystemDisplayService::GetDisplayMode(Out<u32> out_width, Out<u32> out_height, | 83 | Result ISystemDisplayService::ListDisplayModes( |
| 84 | Out<f32> out_refresh_rate, Out<u32> out_unknown) { | 84 | Out<u64> out_count, u64 display_id, |
| 85 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 85 | OutArray<DisplayMode, BufferAttr_HipcMapAlias> out_display_modes) { |
| 86 | LOG_WARNING(Service_VI, "(STUBBED) called, display_id={}", display_id); | ||
| 87 | |||
| 88 | if (!out_display_modes.empty()) { | ||
| 89 | out_display_modes[0] = { | ||
| 90 | .width = 1920, | ||
| 91 | .height = 1080, | ||
| 92 | .refresh_rate = 60.f, | ||
| 93 | .unknown = {}, | ||
| 94 | }; | ||
| 95 | *out_count = 1; | ||
| 96 | } else { | ||
| 97 | *out_count = 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | R_SUCCEED(); | ||
| 101 | } | ||
| 102 | |||
| 103 | Result ISystemDisplayService::GetDisplayMode(Out<DisplayMode> out_display_mode, u64 display_id) { | ||
| 104 | LOG_WARNING(Service_VI, "(STUBBED) called, display_id={}", display_id); | ||
| 86 | 105 | ||
| 87 | if (Settings::IsDockedMode()) { | 106 | if (Settings::IsDockedMode()) { |
| 88 | *out_width = static_cast<u32>(DisplayResolution::DockedWidth); | 107 | out_display_mode->width = static_cast<u32>(DisplayResolution::DockedWidth); |
| 89 | *out_height = static_cast<u32>(DisplayResolution::DockedHeight); | 108 | out_display_mode->height = static_cast<u32>(DisplayResolution::DockedHeight); |
| 90 | } else { | 109 | } else { |
| 91 | *out_width = static_cast<u32>(DisplayResolution::UndockedWidth); | 110 | out_display_mode->width = static_cast<u32>(DisplayResolution::UndockedWidth); |
| 92 | *out_height = static_cast<u32>(DisplayResolution::UndockedHeight); | 111 | out_display_mode->height = static_cast<u32>(DisplayResolution::UndockedHeight); |
| 93 | } | 112 | } |
| 94 | 113 | ||
| 95 | *out_refresh_rate = 60.f; // This wouldn't seem to be correct for 30 fps games. | 114 | out_display_mode->refresh_rate = 60.f; // This wouldn't seem to be correct for 30 fps games. |
| 96 | *out_unknown = 0; | 115 | out_display_mode->unknown = 0; |
| 97 | 116 | ||
| 98 | R_SUCCEED(); | 117 | R_SUCCEED(); |
| 99 | } | 118 | } |
| 100 | 119 | ||
| 101 | Result ISystemDisplayService::GetSharedBufferMemoryHandleId( | 120 | Result ISystemDisplayService::GetSharedBufferMemoryHandleId( |
| 102 | Out<s32> out_nvmap_handle, Out<u64> out_size, | 121 | Out<s32> out_nvmap_handle, Out<u64> out_size, |
| 103 | OutLargeData<Nvnflinger::SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout, | 122 | OutLargeData<SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout, u64 buffer_id, |
| 104 | u64 buffer_id, ClientAppletResourceUserId aruid) { | 123 | ClientAppletResourceUserId aruid) { |
| 105 | LOG_INFO(Service_VI, "called. buffer_id={}, aruid={:#x}", buffer_id, aruid.pid); | 124 | LOG_INFO(Service_VI, "called. buffer_id={}, aruid={:#x}", buffer_id, aruid.pid); |
| 106 | 125 | ||
| 107 | R_RETURN(m_nvnflinger.GetSystemBufferManager().GetSharedBufferMemoryHandleId( | 126 | R_RETURN(m_container->GetSharedBufferManager()->GetSharedBufferMemoryHandleId( |
| 108 | out_size, out_nvmap_handle, out_pool_layout, buffer_id, aruid.pid)); | 127 | out_size, out_nvmap_handle, out_pool_layout, buffer_id, aruid.pid)); |
| 109 | } | 128 | } |
| 110 | 129 | ||
| @@ -122,7 +141,7 @@ Result ISystemDisplayService::AcquireSharedFrameBuffer(Out<android::Fence> out_f | |||
| 122 | Out<std::array<s32, 4>> out_slots, | 141 | Out<std::array<s32, 4>> out_slots, |
| 123 | Out<s64> out_target_slot, u64 layer_id) { | 142 | Out<s64> out_target_slot, u64 layer_id) { |
| 124 | LOG_DEBUG(Service_VI, "called"); | 143 | LOG_DEBUG(Service_VI, "called"); |
| 125 | R_RETURN(m_nvnflinger.GetSystemBufferManager().AcquireSharedFrameBuffer( | 144 | R_RETURN(m_container->GetSharedBufferManager()->AcquireSharedFrameBuffer( |
| 126 | out_fence, *out_slots, out_target_slot, layer_id)); | 145 | out_fence, *out_slots, out_target_slot, layer_id)); |
| 127 | } | 146 | } |
| 128 | 147 | ||
| @@ -131,15 +150,20 @@ Result ISystemDisplayService::PresentSharedFrameBuffer(android::Fence fence, | |||
| 131 | u32 window_transform, s32 swap_interval, | 150 | u32 window_transform, s32 swap_interval, |
| 132 | u64 layer_id, s64 surface_id) { | 151 | u64 layer_id, s64 surface_id) { |
| 133 | LOG_DEBUG(Service_VI, "called"); | 152 | LOG_DEBUG(Service_VI, "called"); |
| 134 | R_RETURN(m_nvnflinger.GetSystemBufferManager().PresentSharedFrameBuffer( | 153 | R_RETURN(m_container->GetSharedBufferManager()->PresentSharedFrameBuffer( |
| 135 | fence, crop_region, window_transform, swap_interval, layer_id, surface_id)); | 154 | fence, crop_region, window_transform, swap_interval, layer_id, surface_id)); |
| 136 | } | 155 | } |
| 137 | 156 | ||
| 138 | Result ISystemDisplayService::GetSharedFrameBufferAcquirableEvent( | 157 | Result ISystemDisplayService::GetSharedFrameBufferAcquirableEvent( |
| 139 | OutCopyHandle<Kernel::KReadableEvent> out_event, u64 layer_id) { | 158 | OutCopyHandle<Kernel::KReadableEvent> out_event, u64 layer_id) { |
| 140 | LOG_DEBUG(Service_VI, "called"); | 159 | LOG_DEBUG(Service_VI, "called"); |
| 141 | R_RETURN(m_nvnflinger.GetSystemBufferManager().GetSharedFrameBufferAcquirableEvent(out_event, | 160 | R_RETURN(m_container->GetSharedBufferManager()->GetSharedFrameBufferAcquirableEvent(out_event, |
| 142 | layer_id)); | 161 | layer_id)); |
| 162 | } | ||
| 163 | |||
| 164 | Result ISystemDisplayService::CancelSharedFrameBuffer(u64 layer_id, s64 slot) { | ||
| 165 | LOG_DEBUG(Service_VI, "called"); | ||
| 166 | R_RETURN(m_container->GetSharedBufferManager()->CancelSharedFrameBuffer(layer_id, slot)); | ||
| 143 | } | 167 | } |
| 144 | 168 | ||
| 145 | } // namespace Service::VI | 169 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/system_display_service.h b/src/core/hle/service/vi/system_display_service.h index cfcb196fd..7228d826e 100644 --- a/src/core/hle/service/vi/system_display_service.h +++ b/src/core/hle/service/vi/system_display_service.h | |||
| @@ -5,27 +5,28 @@ | |||
| 5 | #include "core/hle/service/cmif_types.h" | 5 | #include "core/hle/service/cmif_types.h" |
| 6 | #include "core/hle/service/nvnflinger/ui/fence.h" | 6 | #include "core/hle/service/nvnflinger/ui/fence.h" |
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | #include "core/hle/service/vi/shared_buffer_manager.h" | |
| 9 | namespace Service::Nvnflinger { | ||
| 10 | struct SharedMemoryPoolLayout; | ||
| 11 | } | ||
| 12 | 9 | ||
| 13 | namespace Service::VI { | 10 | namespace Service::VI { |
| 11 | struct DisplayMode; | ||
| 12 | |||
| 13 | class Container; | ||
| 14 | 14 | ||
| 15 | class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> { | 15 | class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> { |
| 16 | public: | 16 | public: |
| 17 | explicit ISystemDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger); | 17 | explicit ISystemDisplayService(Core::System& system_, std::shared_ptr<Container> container); |
| 18 | ~ISystemDisplayService() override; | 18 | ~ISystemDisplayService() override; |
| 19 | 19 | ||
| 20 | private: | 20 | private: |
| 21 | Result SetLayerZ(u32 z_value, u64 layer_id); | 21 | Result SetLayerZ(u32 z_value, u64 layer_id); |
| 22 | Result SetLayerVisibility(bool visible, u64 layer_id); | 22 | Result SetLayerVisibility(bool visible, u64 layer_id); |
| 23 | Result GetDisplayMode(Out<u32> out_width, Out<u32> out_height, Out<f32> out_refresh_rate, | 23 | Result ListDisplayModes(Out<u64> out_count, u64 display_id, |
| 24 | Out<u32> out_unknown); | 24 | OutArray<DisplayMode, BufferAttr_HipcMapAlias> out_display_modes); |
| 25 | Result GetDisplayMode(Out<DisplayMode> out_display_mode, u64 display_id); | ||
| 25 | 26 | ||
| 26 | Result GetSharedBufferMemoryHandleId( | 27 | Result GetSharedBufferMemoryHandleId( |
| 27 | Out<s32> out_nvmap_handle, Out<u64> out_size, | 28 | Out<s32> out_nvmap_handle, Out<u64> out_size, |
| 28 | OutLargeData<Nvnflinger::SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout, | 29 | OutLargeData<SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout, |
| 29 | u64 buffer_id, ClientAppletResourceUserId aruid); | 30 | u64 buffer_id, ClientAppletResourceUserId aruid); |
| 30 | Result OpenSharedLayer(u64 layer_id); | 31 | Result OpenSharedLayer(u64 layer_id); |
| 31 | Result ConnectSharedLayer(u64 layer_id); | 32 | Result ConnectSharedLayer(u64 layer_id); |
| @@ -37,9 +38,10 @@ private: | |||
| 37 | Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region, | 38 | Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region, |
| 38 | u32 window_transform, s32 swap_interval, u64 layer_id, | 39 | u32 window_transform, s32 swap_interval, u64 layer_id, |
| 39 | s64 surface_id); | 40 | s64 surface_id); |
| 41 | Result CancelSharedFrameBuffer(u64 layer_id, s64 slot); | ||
| 40 | 42 | ||
| 41 | private: | 43 | private: |
| 42 | Nvnflinger::Nvnflinger& m_nvnflinger; | 44 | const std::shared_ptr<Container> m_container; |
| 43 | }; | 45 | }; |
| 44 | 46 | ||
| 45 | } // namespace Service::VI | 47 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/system_root_service.cpp b/src/core/hle/service/vi/system_root_service.cpp index 8789b4cfb..3489727d8 100644 --- a/src/core/hle/service/vi/system_root_service.cpp +++ b/src/core/hle/service/vi/system_root_service.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include "core/hle/service/cmif_serialization.h" | 4 | #include "core/hle/service/cmif_serialization.h" |
| 5 | #include "core/hle/service/vi/application_display_service.h" | 5 | #include "core/hle/service/vi/application_display_service.h" |
| 6 | #include "core/hle/service/vi/container.h" | ||
| 6 | #include "core/hle/service/vi/service_creator.h" | 7 | #include "core/hle/service/vi/service_creator.h" |
| 7 | #include "core/hle/service/vi/system_root_service.h" | 8 | #include "core/hle/service/vi/system_root_service.h" |
| 8 | #include "core/hle/service/vi/vi.h" | 9 | #include "core/hle/service/vi/vi.h" |
| @@ -10,10 +11,8 @@ | |||
| 10 | 11 | ||
| 11 | namespace Service::VI { | 12 | namespace Service::VI { |
| 12 | 13 | ||
| 13 | ISystemRootService::ISystemRootService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, | 14 | ISystemRootService::ISystemRootService(Core::System& system_, std::shared_ptr<Container> container) |
| 14 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) | 15 | : ServiceFramework{system_, "vi:s"}, m_container{std::move(container)} { |
| 15 | : ServiceFramework{system_, "vi:s"}, m_nvnflinger{nvnflinger}, m_hos_binder_driver_server{ | ||
| 16 | hos_binder_driver_server} { | ||
| 17 | static const FunctionInfo functions[] = { | 16 | static const FunctionInfo functions[] = { |
| 18 | {1, C<&ISystemRootService::GetDisplayService>, "GetDisplayService"}, | 17 | {1, C<&ISystemRootService::GetDisplayService>, "GetDisplayService"}, |
| 19 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, | 18 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, |
| @@ -26,8 +25,8 @@ ISystemRootService::~ISystemRootService() = default; | |||
| 26 | Result ISystemRootService::GetDisplayService( | 25 | Result ISystemRootService::GetDisplayService( |
| 27 | Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) { | 26 | Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) { |
| 28 | LOG_DEBUG(Service_VI, "called"); | 27 | LOG_DEBUG(Service_VI, "called"); |
| 29 | R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_nvnflinger, | 28 | R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_container, |
| 30 | m_hos_binder_driver_server, Permission::System, policy)); | 29 | Permission::System, policy)); |
| 31 | } | 30 | } |
| 32 | 31 | ||
| 33 | } // namespace Service::VI | 32 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/system_root_service.h b/src/core/hle/service/vi/system_root_service.h index 2c547faa5..9d5aa53d3 100644 --- a/src/core/hle/service/vi/system_root_service.h +++ b/src/core/hle/service/vi/system_root_service.h | |||
| @@ -10,20 +10,15 @@ namespace Core { | |||
| 10 | class System; | 10 | class System; |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | namespace Service::Nvnflinger { | ||
| 14 | class HosBinderDriverServer; | ||
| 15 | class Nvnflinger; | ||
| 16 | } // namespace Service::Nvnflinger | ||
| 17 | |||
| 18 | namespace Service::VI { | 13 | namespace Service::VI { |
| 19 | 14 | ||
| 15 | class Container; | ||
| 20 | class IApplicationDisplayService; | 16 | class IApplicationDisplayService; |
| 21 | enum class Policy : u32; | 17 | enum class Policy : u32; |
| 22 | 18 | ||
| 23 | class ISystemRootService final : public ServiceFramework<ISystemRootService> { | 19 | class ISystemRootService final : public ServiceFramework<ISystemRootService> { |
| 24 | public: | 20 | public: |
| 25 | explicit ISystemRootService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger, | 21 | explicit ISystemRootService(Core::System& system_, std::shared_ptr<Container> container); |
| 26 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server); | ||
| 27 | ~ISystemRootService() override; | 22 | ~ISystemRootService() override; |
| 28 | 23 | ||
| 29 | private: | 24 | private: |
| @@ -31,8 +26,7 @@ private: | |||
| 31 | Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, | 26 | Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, |
| 32 | Policy policy); | 27 | Policy policy); |
| 33 | 28 | ||
| 34 | Nvnflinger::Nvnflinger& m_nvnflinger; | 29 | const std::shared_ptr<Container> m_container; |
| 35 | Nvnflinger::HosBinderDriverServer& m_hos_binder_driver_server; | ||
| 36 | }; | 30 | }; |
| 37 | 31 | ||
| 38 | } // namespace Service::VI | 32 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 304e589b7..b388efaf6 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp | |||
| @@ -1,25 +1,30 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "core/core.h" | ||
| 4 | #include "core/hle/service/server_manager.h" | 5 | #include "core/hle/service/server_manager.h" |
| 5 | #include "core/hle/service/vi/application_display_service.h" | ||
| 6 | #include "core/hle/service/vi/application_root_service.h" | 6 | #include "core/hle/service/vi/application_root_service.h" |
| 7 | #include "core/hle/service/vi/container.h" | ||
| 7 | #include "core/hle/service/vi/manager_root_service.h" | 8 | #include "core/hle/service/vi/manager_root_service.h" |
| 8 | #include "core/hle/service/vi/system_root_service.h" | 9 | #include "core/hle/service/vi/system_root_service.h" |
| 9 | #include "core/hle/service/vi/vi.h" | 10 | #include "core/hle/service/vi/vi.h" |
| 10 | 11 | ||
| 11 | namespace Service::VI { | 12 | namespace Service::VI { |
| 12 | 13 | ||
| 13 | void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger, | 14 | void LoopProcess(Core::System& system, std::stop_token token) { |
| 14 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) { | 15 | const auto container = std::make_shared<Container>(system); |
| 16 | |||
| 15 | auto server_manager = std::make_unique<ServerManager>(system); | 17 | auto server_manager = std::make_unique<ServerManager>(system); |
| 16 | 18 | ||
| 17 | server_manager->RegisterNamedService("vi:m", std::make_shared<IManagerRootService>( | 19 | server_manager->RegisterNamedService("vi:m", |
| 18 | system, nvnflinger, hos_binder_driver_server)); | 20 | std::make_shared<IManagerRootService>(system, container)); |
| 21 | server_manager->RegisterNamedService("vi:s", | ||
| 22 | std::make_shared<ISystemRootService>(system, container)); | ||
| 19 | server_manager->RegisterNamedService( | 23 | server_manager->RegisterNamedService( |
| 20 | "vi:s", std::make_shared<ISystemRootService>(system, nvnflinger, hos_binder_driver_server)); | 24 | "vi:u", std::make_shared<IApplicationRootService>(system, container)); |
| 21 | server_manager->RegisterNamedService("vi:u", std::make_shared<IApplicationRootService>( | 25 | |
| 22 | system, nvnflinger, hos_binder_driver_server)); | 26 | std::stop_callback cb(token, [=] { container->OnTerminate(); }); |
| 27 | |||
| 23 | ServerManager::RunServer(std::move(server_manager)); | 28 | ServerManager::RunServer(std::move(server_manager)); |
| 24 | } | 29 | } |
| 25 | 30 | ||
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index 8e681370d..7c1f350d8 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h | |||
| @@ -3,18 +3,14 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include "common/polyfill_thread.h" | ||
| 7 | |||
| 6 | namespace Core { | 8 | namespace Core { |
| 7 | class System; | 9 | class System; |
| 8 | } | 10 | } |
| 9 | 11 | ||
| 10 | namespace Service::Nvnflinger { | ||
| 11 | class HosBinderDriverServer; | ||
| 12 | class Nvnflinger; | ||
| 13 | } // namespace Service::Nvnflinger | ||
| 14 | |||
| 15 | namespace Service::VI { | 12 | namespace Service::VI { |
| 16 | 13 | ||
| 17 | void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger, | 14 | void LoopProcess(Core::System& system, std::stop_token token); |
| 18 | Nvnflinger::HosBinderDriverServer& hos_binder_driver_server); | ||
| 19 | 15 | ||
| 20 | } // namespace Service::VI | 16 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/vi_types.h b/src/core/hle/service/vi/vi_types.h index 91e4b380c..95ff66358 100644 --- a/src/core/hle/service/vi/vi_types.h +++ b/src/core/hle/service/vi/vi_types.h | |||
| @@ -66,9 +66,17 @@ struct DisplayInfo { | |||
| 66 | }; | 66 | }; |
| 67 | static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size"); | 67 | static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size"); |
| 68 | 68 | ||
| 69 | struct DisplayMode { | ||
| 70 | u32 width; | ||
| 71 | u32 height; | ||
| 72 | f32 refresh_rate; | ||
| 73 | u32 unknown; | ||
| 74 | }; | ||
| 75 | static_assert(sizeof(DisplayMode) == 0x10, "DisplayMode has wrong size"); | ||
| 76 | |||
| 69 | class NativeWindow final { | 77 | class NativeWindow final { |
| 70 | public: | 78 | public: |
| 71 | constexpr explicit NativeWindow(u32 id_) : id{id_} {} | 79 | constexpr explicit NativeWindow(s32 id_) : id{static_cast<u64>(id_)} {} |
| 72 | constexpr explicit NativeWindow(const NativeWindow& other) = default; | 80 | constexpr explicit NativeWindow(const NativeWindow& other) = default; |
| 73 | 81 | ||
| 74 | private: | 82 | private: |
diff --git a/src/core/hle/service/vi/vsync_manager.cpp b/src/core/hle/service/vi/vsync_manager.cpp new file mode 100644 index 000000000..bdc4dfa96 --- /dev/null +++ b/src/core/hle/service/vi/vsync_manager.cpp | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/os/event.h" | ||
| 5 | #include "core/hle/service/vi/vsync_manager.h" | ||
| 6 | |||
| 7 | namespace Service::VI { | ||
| 8 | |||
| 9 | VsyncManager::VsyncManager() = default; | ||
| 10 | VsyncManager::~VsyncManager() = default; | ||
| 11 | |||
| 12 | void VsyncManager::SignalVsync() { | ||
| 13 | for (auto* event : m_vsync_events) { | ||
| 14 | event->Signal(); | ||
| 15 | } | ||
| 16 | } | ||
| 17 | |||
| 18 | void VsyncManager::LinkVsyncEvent(Event* event) { | ||
| 19 | m_vsync_events.insert(event); | ||
| 20 | } | ||
| 21 | |||
| 22 | void VsyncManager::UnlinkVsyncEvent(Event* event) { | ||
| 23 | m_vsync_events.erase(event); | ||
| 24 | } | ||
| 25 | |||
| 26 | } // namespace Service::VI | ||
diff --git a/src/core/hle/service/vi/vsync_manager.h b/src/core/hle/service/vi/vsync_manager.h new file mode 100644 index 000000000..5d45bb5ee --- /dev/null +++ b/src/core/hle/service/vi/vsync_manager.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <set> | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | class Event; | ||
| 10 | } | ||
| 11 | |||
| 12 | namespace Service::VI { | ||
| 13 | |||
| 14 | class DisplayList; | ||
| 15 | |||
| 16 | class VsyncManager { | ||
| 17 | public: | ||
| 18 | explicit VsyncManager(); | ||
| 19 | ~VsyncManager(); | ||
| 20 | |||
| 21 | void SignalVsync(); | ||
| 22 | void LinkVsyncEvent(Event* event); | ||
| 23 | void UnlinkVsyncEvent(Event* event); | ||
| 24 | |||
| 25 | private: | ||
| 26 | std::set<Event*> m_vsync_events; | ||
| 27 | }; | ||
| 28 | |||
| 29 | } // namespace Service::VI | ||
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index 2a32b1276..de27ec49e 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp | |||
| @@ -118,7 +118,9 @@ ResultStatus AppLoader_NCA::VerifyIntegrity(std::function<bool(size_t, size_t)> | |||
| 118 | mbedtls_sha256_starts_ret(&ctx, 0); | 118 | mbedtls_sha256_starts_ret(&ctx, 0); |
| 119 | 119 | ||
| 120 | // Ensure we maintain a clean state on exit. | 120 | // Ensure we maintain a clean state on exit. |
| 121 | SCOPE_EXIT({ mbedtls_sha256_free(&ctx); }); | 121 | SCOPE_EXIT { |
| 122 | mbedtls_sha256_free(&ctx); | ||
| 123 | }; | ||
| 122 | 124 | ||
| 123 | // Declare counters. | 125 | // Declare counters. |
| 124 | const size_t total_size = file->GetSize(); | 126 | const size_t total_size = file->GetSize(); |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index e10a4601e..8775369a4 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -831,11 +831,11 @@ struct Memory::Impl { | |||
| 831 | if (core == sys_core) [[unlikely]] { | 831 | if (core == sys_core) [[unlikely]] { |
| 832 | sys_core_guard.lock(); | 832 | sys_core_guard.lock(); |
| 833 | } | 833 | } |
| 834 | SCOPE_EXIT({ | 834 | SCOPE_EXIT { |
| 835 | if (core == sys_core) [[unlikely]] { | 835 | if (core == sys_core) [[unlikely]] { |
| 836 | sys_core_guard.unlock(); | 836 | sys_core_guard.unlock(); |
| 837 | } | 837 | } |
| 838 | }); | 838 | }; |
| 839 | gpu_device_memory->ApplyOpOnPointer(p, scratch_buffers[core], [&](DAddr address) { | 839 | gpu_device_memory->ApplyOpOnPointer(p, scratch_buffers[core], [&](DAddr address) { |
| 840 | auto& current_area = rasterizer_write_areas[core]; | 840 | auto& current_area = rasterizer_write_areas[core]; |
| 841 | PAddr subaddress = address >> YUZU_PAGEBITS; | 841 | PAddr subaddress = address >> YUZU_PAGEBITS; |
| @@ -866,11 +866,11 @@ struct Memory::Impl { | |||
| 866 | if (core == sys_core) [[unlikely]] { | 866 | if (core == sys_core) [[unlikely]] { |
| 867 | sys_core_guard.lock(); | 867 | sys_core_guard.lock(); |
| 868 | } | 868 | } |
| 869 | SCOPE_EXIT({ | 869 | SCOPE_EXIT { |
| 870 | if (core == sys_core) [[unlikely]] { | 870 | if (core == sys_core) [[unlikely]] { |
| 871 | sys_core_guard.unlock(); | 871 | sys_core_guard.unlock(); |
| 872 | } | 872 | } |
| 873 | }); | 873 | }; |
| 874 | auto& gpu = system.GPU(); | 874 | auto& gpu = system.GPU(); |
| 875 | gpu_device_memory->ApplyOpOnPointer( | 875 | gpu_device_memory->ApplyOpOnPointer( |
| 876 | p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size); }); | 876 | p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size); }); |
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index b84b57d92..d8921e565 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp | |||
| @@ -117,9 +117,9 @@ bool StandardVmCallbacks::IsAddressInRange(VAddr in) const { | |||
| 117 | (in < metadata.heap_extents.base || | 117 | (in < metadata.heap_extents.base || |
| 118 | in >= metadata.heap_extents.base + metadata.heap_extents.size) && | 118 | in >= metadata.heap_extents.base + metadata.heap_extents.size) && |
| 119 | (in < metadata.alias_extents.base || | 119 | (in < metadata.alias_extents.base || |
| 120 | in >= metadata.heap_extents.base + metadata.alias_extents.size) && | 120 | in >= metadata.alias_extents.base + metadata.alias_extents.size) && |
| 121 | (in < metadata.aslr_extents.base || | 121 | (in < metadata.aslr_extents.base || |
| 122 | in >= metadata.heap_extents.base + metadata.aslr_extents.size)) { | 122 | in >= metadata.aslr_extents.base + metadata.aslr_extents.size)) { |
| 123 | LOG_DEBUG(CheatEngine, | 123 | LOG_DEBUG(CheatEngine, |
| 124 | "Cheat attempting to access memory at invalid address={:016X}, if this " | 124 | "Cheat attempting to access memory at invalid address={:016X}, if this " |
| 125 | "persists, " | 125 | "persists, " |
diff --git a/src/core/memory/dmnt_cheat_vm.cpp b/src/core/memory/dmnt_cheat_vm.cpp index f7097d01d..caceeec4f 100644 --- a/src/core/memory/dmnt_cheat_vm.cpp +++ b/src/core/memory/dmnt_cheat_vm.cpp | |||
| @@ -224,12 +224,12 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) { | |||
| 224 | // If we've ever seen a decode failure, return false. | 224 | // If we've ever seen a decode failure, return false. |
| 225 | bool valid = decode_success; | 225 | bool valid = decode_success; |
| 226 | CheatVmOpcode opcode = {}; | 226 | CheatVmOpcode opcode = {}; |
| 227 | SCOPE_EXIT({ | 227 | SCOPE_EXIT { |
| 228 | decode_success &= valid; | 228 | decode_success &= valid; |
| 229 | if (valid) { | 229 | if (valid) { |
| 230 | out = opcode; | 230 | out = opcode; |
| 231 | } | 231 | } |
| 232 | }); | 232 | }; |
| 233 | 233 | ||
| 234 | // Helper function for getting instruction dwords. | 234 | // Helper function for getting instruction dwords. |
| 235 | const auto GetNextDword = [&] { | 235 | const auto GetNextDword = [&] { |
diff --git a/src/frontend_common/config.cpp b/src/frontend_common/config.cpp index 2bebfeef9..95f8c8c36 100644 --- a/src/frontend_common/config.cpp +++ b/src/frontend_common/config.cpp | |||
| @@ -138,6 +138,7 @@ void Config::ReadPlayerValues(const std::size_t player_index) { | |||
| 138 | if (profile_name.empty()) { | 138 | if (profile_name.empty()) { |
| 139 | // Use the global input config | 139 | // Use the global input config |
| 140 | player = Settings::values.players.GetValue(true)[player_index]; | 140 | player = Settings::values.players.GetValue(true)[player_index]; |
| 141 | player.profile_name = ""; | ||
| 141 | return; | 142 | return; |
| 142 | } | 143 | } |
| 143 | player.profile_name = profile_name; | 144 | player.profile_name = profile_name; |
diff --git a/src/frontend_common/content_manager.h b/src/frontend_common/content_manager.h index f3efe3465..c4e97a47b 100644 --- a/src/frontend_common/content_manager.h +++ b/src/frontend_common/content_manager.h | |||
| @@ -251,11 +251,12 @@ inline InstallResult InstallNCA(FileSys::VfsFilesystem& vfs, const std::string& | |||
| 251 | * \param callback Callback to report the progress of the installation. The first size_t | 251 | * \param callback Callback to report the progress of the installation. The first size_t |
| 252 | * parameter is the total size of the installed contents and the second is the current progress. If | 252 | * parameter is the total size of the installed contents and the second is the current progress. If |
| 253 | * you return true to the callback, it will cancel the installation as soon as possible. | 253 | * you return true to the callback, it will cancel the installation as soon as possible. |
| 254 | * \param firmware_only Set to true to only scan system nand NCAs (firmware), post firmware install. | ||
| 254 | * \return A list of entries that failed to install. Returns an empty vector if successful. | 255 | * \return A list of entries that failed to install. Returns an empty vector if successful. |
| 255 | */ | 256 | */ |
| 256 | inline std::vector<std::string> VerifyInstalledContents( | 257 | inline std::vector<std::string> VerifyInstalledContents( |
| 257 | Core::System& system, FileSys::ManualContentProvider& provider, | 258 | Core::System& system, FileSys::ManualContentProvider& provider, |
| 258 | const std::function<bool(size_t, size_t)>& callback) { | 259 | const std::function<bool(size_t, size_t)>& callback, bool firmware_only = false) { |
| 259 | // Get content registries. | 260 | // Get content registries. |
| 260 | auto bis_contents = system.GetFileSystemController().GetSystemNANDContents(); | 261 | auto bis_contents = system.GetFileSystemController().GetSystemNANDContents(); |
| 261 | auto user_contents = system.GetFileSystemController().GetUserNANDContents(); | 262 | auto user_contents = system.GetFileSystemController().GetUserNANDContents(); |
| @@ -264,7 +265,7 @@ inline std::vector<std::string> VerifyInstalledContents( | |||
| 264 | if (bis_contents) { | 265 | if (bis_contents) { |
| 265 | content_providers.push_back(bis_contents); | 266 | content_providers.push_back(bis_contents); |
| 266 | } | 267 | } |
| 267 | if (user_contents) { | 268 | if (user_contents && !firmware_only) { |
| 268 | content_providers.push_back(user_contents); | 269 | content_providers.push_back(user_contents); |
| 269 | } | 270 | } |
| 270 | 271 | ||
diff --git a/src/hid_core/frontend/emulated_controller.cpp b/src/hid_core/frontend/emulated_controller.cpp index 819460eb5..5cd26819c 100644 --- a/src/hid_core/frontend/emulated_controller.cpp +++ b/src/hid_core/frontend/emulated_controller.cpp | |||
| @@ -174,18 +174,25 @@ void EmulatedController::LoadDevices() { | |||
| 174 | // Only map virtual devices to the first controller | 174 | // Only map virtual devices to the first controller |
| 175 | if (npad_id_type == NpadIdType::Player1 || npad_id_type == NpadIdType::Handheld) { | 175 | if (npad_id_type == NpadIdType::Player1 || npad_id_type == NpadIdType::Handheld) { |
| 176 | camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"}; | 176 | camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"}; |
| 177 | ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"}; | ||
| 178 | nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"}; | 177 | nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"}; |
| 178 | #ifdef HAVE_LIBUSB | ||
| 179 | ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"}; | ||
| 180 | #endif | ||
| 181 | #ifdef ANDROID | ||
| 182 | android_params = Common::ParamPackage{"engine:android,port:100"}; | ||
| 183 | #endif | ||
| 179 | } | 184 | } |
| 180 | 185 | ||
| 181 | output_params[LeftIndex] = left_joycon; | 186 | output_params[LeftIndex] = left_joycon; |
| 182 | output_params[RightIndex] = right_joycon; | 187 | output_params[RightIndex] = right_joycon; |
| 183 | output_params[2] = camera_params[1]; | 188 | output_params[2] = camera_params[1]; |
| 184 | output_params[3] = nfc_params[0]; | 189 | output_params[3] = nfc_params[0]; |
| 190 | output_params[4] = android_params; | ||
| 185 | output_params[LeftIndex].Set("output", true); | 191 | output_params[LeftIndex].Set("output", true); |
| 186 | output_params[RightIndex].Set("output", true); | 192 | output_params[RightIndex].Set("output", true); |
| 187 | output_params[2].Set("output", true); | 193 | output_params[2].Set("output", true); |
| 188 | output_params[3].Set("output", true); | 194 | output_params[3].Set("output", true); |
| 195 | output_params[4].Set("output", true); | ||
| 189 | 196 | ||
| 190 | LoadTASParams(); | 197 | LoadTASParams(); |
| 191 | LoadVirtualGamepadParams(); | 198 | LoadVirtualGamepadParams(); |
| @@ -578,6 +585,9 @@ void EmulatedController::DisableConfiguration() { | |||
| 578 | 585 | ||
| 579 | // Get Joycon colors before turning on the controller | 586 | // Get Joycon colors before turning on the controller |
| 580 | for (const auto& color_device : color_devices) { | 587 | for (const auto& color_device : color_devices) { |
| 588 | if (color_device == nullptr) { | ||
| 589 | continue; | ||
| 590 | } | ||
| 581 | color_device->ForceUpdate(); | 591 | color_device->ForceUpdate(); |
| 582 | } | 592 | } |
| 583 | 593 | ||
| @@ -923,8 +933,9 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, | |||
| 923 | if (index >= controller.stick_values.size()) { | 933 | if (index >= controller.stick_values.size()) { |
| 924 | return; | 934 | return; |
| 925 | } | 935 | } |
| 926 | auto trigger_guard = | 936 | auto trigger_guard = SCOPE_GUARD { |
| 927 | SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); }); | 937 | TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); |
| 938 | }; | ||
| 928 | std::scoped_lock lock{mutex}; | 939 | std::scoped_lock lock{mutex}; |
| 929 | const auto stick_value = TransformToStick(callback); | 940 | const auto stick_value = TransformToStick(callback); |
| 930 | 941 | ||
| @@ -979,8 +990,9 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac | |||
| 979 | if (index >= controller.trigger_values.size()) { | 990 | if (index >= controller.trigger_values.size()) { |
| 980 | return; | 991 | return; |
| 981 | } | 992 | } |
| 982 | auto trigger_guard = | 993 | auto trigger_guard = SCOPE_GUARD { |
| 983 | SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); }); | 994 | TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); |
| 995 | }; | ||
| 984 | std::scoped_lock lock{mutex}; | 996 | std::scoped_lock lock{mutex}; |
| 985 | const auto trigger_value = TransformToTrigger(callback); | 997 | const auto trigger_value = TransformToTrigger(callback); |
| 986 | 998 | ||
| @@ -1026,7 +1038,9 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback | |||
| 1026 | if (index >= controller.motion_values.size()) { | 1038 | if (index >= controller.motion_values.size()) { |
| 1027 | return; | 1039 | return; |
| 1028 | } | 1040 | } |
| 1029 | SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Motion, !is_configuring); }); | 1041 | SCOPE_EXIT { |
| 1042 | TriggerOnChange(ControllerTriggerType::Motion, !is_configuring); | ||
| 1043 | }; | ||
| 1030 | std::scoped_lock lock{mutex}; | 1044 | std::scoped_lock lock{mutex}; |
| 1031 | auto& raw_status = controller.motion_values[index].raw_status; | 1045 | auto& raw_status = controller.motion_values[index].raw_status; |
| 1032 | auto& emulated = controller.motion_values[index].emulated; | 1046 | auto& emulated = controller.motion_values[index].emulated; |
| @@ -1060,8 +1074,9 @@ void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback | |||
| 1060 | if (index >= controller.color_values.size()) { | 1074 | if (index >= controller.color_values.size()) { |
| 1061 | return; | 1075 | return; |
| 1062 | } | 1076 | } |
| 1063 | auto trigger_guard = | 1077 | auto trigger_guard = SCOPE_GUARD { |
| 1064 | SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Color, !is_configuring); }); | 1078 | TriggerOnChange(ControllerTriggerType::Color, !is_configuring); |
| 1079 | }; | ||
| 1065 | std::scoped_lock lock{mutex}; | 1080 | std::scoped_lock lock{mutex}; |
| 1066 | controller.color_values[index] = TransformToColor(callback); | 1081 | controller.color_values[index] = TransformToColor(callback); |
| 1067 | 1082 | ||
| @@ -1110,7 +1125,9 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac | |||
| 1110 | if (index >= controller.battery_values.size()) { | 1125 | if (index >= controller.battery_values.size()) { |
| 1111 | return; | 1126 | return; |
| 1112 | } | 1127 | } |
| 1113 | SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Battery, !is_configuring); }); | 1128 | SCOPE_EXIT { |
| 1129 | TriggerOnChange(ControllerTriggerType::Battery, !is_configuring); | ||
| 1130 | }; | ||
| 1114 | std::scoped_lock lock{mutex}; | 1131 | std::scoped_lock lock{mutex}; |
| 1115 | controller.battery_values[index] = TransformToBattery(callback); | 1132 | controller.battery_values[index] = TransformToBattery(callback); |
| 1116 | 1133 | ||
| @@ -1173,7 +1190,9 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac | |||
| 1173 | } | 1190 | } |
| 1174 | 1191 | ||
| 1175 | void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) { | 1192 | void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) { |
| 1176 | SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring); }); | 1193 | SCOPE_EXIT { |
| 1194 | TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring); | ||
| 1195 | }; | ||
| 1177 | std::scoped_lock lock{mutex}; | 1196 | std::scoped_lock lock{mutex}; |
| 1178 | controller.camera_values = TransformToCamera(callback); | 1197 | controller.camera_values = TransformToCamera(callback); |
| 1179 | 1198 | ||
| @@ -1188,7 +1207,9 @@ void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback | |||
| 1188 | } | 1207 | } |
| 1189 | 1208 | ||
| 1190 | void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& callback) { | 1209 | void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& callback) { |
| 1191 | SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::RingController, !is_configuring); }); | 1210 | SCOPE_EXIT { |
| 1211 | TriggerOnChange(ControllerTriggerType::RingController, !is_configuring); | ||
| 1212 | }; | ||
| 1192 | std::scoped_lock lock{mutex}; | 1213 | std::scoped_lock lock{mutex}; |
| 1193 | const auto force_value = TransformToStick(callback); | 1214 | const auto force_value = TransformToStick(callback); |
| 1194 | 1215 | ||
| @@ -1202,7 +1223,9 @@ void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& call | |||
| 1202 | } | 1223 | } |
| 1203 | 1224 | ||
| 1204 | void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) { | 1225 | void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) { |
| 1205 | SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring); }); | 1226 | SCOPE_EXIT { |
| 1227 | TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring); | ||
| 1228 | }; | ||
| 1206 | std::scoped_lock lock{mutex}; | 1229 | std::scoped_lock lock{mutex}; |
| 1207 | controller.nfc_values = TransformToNfc(callback); | 1230 | controller.nfc_values = TransformToNfc(callback); |
| 1208 | 1231 | ||
| @@ -1277,6 +1300,10 @@ bool EmulatedController::SetVibration(DeviceIndex device_index, const VibrationV | |||
| 1277 | .high_frequency = vibration.high_frequency, | 1300 | .high_frequency = vibration.high_frequency, |
| 1278 | .type = type, | 1301 | .type = type, |
| 1279 | }; | 1302 | }; |
| 1303 | |||
| 1304 | // Send vibrations to Android's input overlay | ||
| 1305 | output_devices[4]->SetVibration(status); | ||
| 1306 | |||
| 1280 | return output_devices[index]->SetVibration(status) == Common::Input::DriverResult::Success; | 1307 | return output_devices[index]->SetVibration(status) == Common::Input::DriverResult::Success; |
| 1281 | } | 1308 | } |
| 1282 | 1309 | ||
| @@ -1671,8 +1698,9 @@ void EmulatedController::Connect(bool use_temporary_value) { | |||
| 1671 | return; | 1698 | return; |
| 1672 | } | 1699 | } |
| 1673 | 1700 | ||
| 1674 | auto trigger_guard = | 1701 | auto trigger_guard = SCOPE_GUARD { |
| 1675 | SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected, !is_configuring); }); | 1702 | TriggerOnChange(ControllerTriggerType::Connected, !is_configuring); |
| 1703 | }; | ||
| 1676 | std::scoped_lock lock{connect_mutex, mutex}; | 1704 | std::scoped_lock lock{connect_mutex, mutex}; |
| 1677 | if (is_configuring) { | 1705 | if (is_configuring) { |
| 1678 | tmp_is_connected = true; | 1706 | tmp_is_connected = true; |
| @@ -1687,8 +1715,9 @@ void EmulatedController::Connect(bool use_temporary_value) { | |||
| 1687 | } | 1715 | } |
| 1688 | 1716 | ||
| 1689 | void EmulatedController::Disconnect() { | 1717 | void EmulatedController::Disconnect() { |
| 1690 | auto trigger_guard = | 1718 | auto trigger_guard = SCOPE_GUARD { |
| 1691 | SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring); }); | 1719 | TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring); |
| 1720 | }; | ||
| 1692 | std::scoped_lock lock{connect_mutex, mutex}; | 1721 | std::scoped_lock lock{connect_mutex, mutex}; |
| 1693 | if (is_configuring) { | 1722 | if (is_configuring) { |
| 1694 | tmp_is_connected = false; | 1723 | tmp_is_connected = false; |
| @@ -1724,8 +1753,9 @@ NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) c | |||
| 1724 | } | 1753 | } |
| 1725 | 1754 | ||
| 1726 | void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) { | 1755 | void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) { |
| 1727 | auto trigger_guard = | 1756 | auto trigger_guard = SCOPE_GUARD { |
| 1728 | SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type, !is_configuring); }); | 1757 | TriggerOnChange(ControllerTriggerType::Type, !is_configuring); |
| 1758 | }; | ||
| 1729 | std::scoped_lock lock{mutex, npad_mutex}; | 1759 | std::scoped_lock lock{mutex, npad_mutex}; |
| 1730 | 1760 | ||
| 1731 | if (is_configuring) { | 1761 | if (is_configuring) { |
diff --git a/src/hid_core/frontend/emulated_controller.h b/src/hid_core/frontend/emulated_controller.h index 701b38300..ab3c6fcd3 100644 --- a/src/hid_core/frontend/emulated_controller.h +++ b/src/hid_core/frontend/emulated_controller.h | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | 21 | ||
| 22 | namespace Core::HID { | 22 | namespace Core::HID { |
| 23 | const std::size_t max_emulated_controllers = 2; | 23 | const std::size_t max_emulated_controllers = 2; |
| 24 | const std::size_t output_devices_size = 4; | 24 | const std::size_t output_devices_size = 5; |
| 25 | struct ControllerMotionInfo { | 25 | struct ControllerMotionInfo { |
| 26 | Common::Input::MotionStatus raw_status{}; | 26 | Common::Input::MotionStatus raw_status{}; |
| 27 | MotionInput emulated{}; | 27 | MotionInput emulated{}; |
| @@ -597,6 +597,7 @@ private: | |||
| 597 | CameraParams camera_params; | 597 | CameraParams camera_params; |
| 598 | RingAnalogParams ring_params; | 598 | RingAnalogParams ring_params; |
| 599 | NfcParams nfc_params; | 599 | NfcParams nfc_params; |
| 600 | Common::ParamPackage android_params; | ||
| 600 | OutputParams output_params; | 601 | OutputParams output_params; |
| 601 | 602 | ||
| 602 | ButtonDevices button_devices; | 603 | ButtonDevices button_devices; |
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index d0a71a15b..d455323e0 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt | |||
| @@ -2,8 +2,6 @@ | |||
| 2 | # SPDX-License-Identifier: GPL-2.0-or-later | 2 | # SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | add_library(input_common STATIC | 4 | add_library(input_common STATIC |
| 5 | drivers/android.cpp | ||
| 6 | drivers/android.h | ||
| 7 | drivers/camera.cpp | 5 | drivers/camera.cpp |
| 8 | drivers/camera.h | 6 | drivers/camera.h |
| 9 | drivers/keyboard.cpp | 7 | drivers/keyboard.cpp |
| @@ -94,3 +92,11 @@ target_link_libraries(input_common PUBLIC hid_core PRIVATE common Boost::headers | |||
| 94 | if (YUZU_USE_PRECOMPILED_HEADERS) | 92 | if (YUZU_USE_PRECOMPILED_HEADERS) |
| 95 | target_precompile_headers(input_common PRIVATE precompiled_headers.h) | 93 | target_precompile_headers(input_common PRIVATE precompiled_headers.h) |
| 96 | endif() | 94 | endif() |
| 95 | |||
| 96 | if (ANDROID) | ||
| 97 | target_sources(input_common PRIVATE | ||
| 98 | drivers/android.cpp | ||
| 99 | drivers/android.h | ||
| 100 | ) | ||
| 101 | target_link_libraries(input_common PRIVATE android) | ||
| 102 | endif() | ||
diff --git a/src/input_common/drivers/android.cpp b/src/input_common/drivers/android.cpp index b6a03fdc0..e859cc538 100644 --- a/src/input_common/drivers/android.cpp +++ b/src/input_common/drivers/android.cpp | |||
| @@ -1,30 +1,47 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | 2 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 3 | 3 | ||
| 4 | #include <set> | ||
| 5 | #include <common/settings_input.h> | ||
| 6 | #include <jni.h> | ||
| 7 | #include "common/android/android_common.h" | ||
| 8 | #include "common/android/id_cache.h" | ||
| 4 | #include "input_common/drivers/android.h" | 9 | #include "input_common/drivers/android.h" |
| 5 | 10 | ||
| 6 | namespace InputCommon { | 11 | namespace InputCommon { |
| 7 | 12 | ||
| 8 | Android::Android(std::string input_engine_) : InputEngine(std::move(input_engine_)) {} | 13 | Android::Android(std::string input_engine_) : InputEngine(std::move(input_engine_)) {} |
| 9 | 14 | ||
| 10 | void Android::RegisterController(std::size_t controller_number) { | 15 | void Android::RegisterController(jobject j_input_device) { |
| 11 | PreSetController(GetIdentifier(controller_number)); | 16 | auto env = Common::Android::GetEnvForThread(); |
| 17 | const std::string guid = Common::Android::GetJString( | ||
| 18 | env, static_cast<jstring>( | ||
| 19 | env->CallObjectMethod(j_input_device, Common::Android::GetYuzuDeviceGetGUID()))); | ||
| 20 | const s32 port = env->CallIntMethod(j_input_device, Common::Android::GetYuzuDeviceGetPort()); | ||
| 21 | const auto identifier = GetIdentifier(guid, static_cast<size_t>(port)); | ||
| 22 | PreSetController(identifier); | ||
| 23 | |||
| 24 | if (input_devices.find(identifier) != input_devices.end()) { | ||
| 25 | env->DeleteGlobalRef(input_devices[identifier]); | ||
| 26 | } | ||
| 27 | auto new_device = env->NewGlobalRef(j_input_device); | ||
| 28 | input_devices[identifier] = new_device; | ||
| 12 | } | 29 | } |
| 13 | 30 | ||
| 14 | void Android::SetButtonState(std::size_t controller_number, int button_id, bool value) { | 31 | void Android::SetButtonState(std::string guid, size_t port, int button_id, bool value) { |
| 15 | const auto identifier = GetIdentifier(controller_number); | 32 | const auto identifier = GetIdentifier(guid, port); |
| 16 | SetButton(identifier, button_id, value); | 33 | SetButton(identifier, button_id, value); |
| 17 | } | 34 | } |
| 18 | 35 | ||
| 19 | void Android::SetAxisState(std::size_t controller_number, int axis_id, float value) { | 36 | void Android::SetAxisPosition(std::string guid, size_t port, int axis_id, float value) { |
| 20 | const auto identifier = GetIdentifier(controller_number); | 37 | const auto identifier = GetIdentifier(guid, port); |
| 21 | SetAxis(identifier, axis_id, value); | 38 | SetAxis(identifier, axis_id, value); |
| 22 | } | 39 | } |
| 23 | 40 | ||
| 24 | void Android::SetMotionState(std::size_t controller_number, u64 delta_timestamp, float gyro_x, | 41 | void Android::SetMotionState(std::string guid, size_t port, u64 delta_timestamp, float gyro_x, |
| 25 | float gyro_y, float gyro_z, float accel_x, float accel_y, | 42 | float gyro_y, float gyro_z, float accel_x, float accel_y, |
| 26 | float accel_z) { | 43 | float accel_z) { |
| 27 | const auto identifier = GetIdentifier(controller_number); | 44 | const auto identifier = GetIdentifier(guid, port); |
| 28 | const BasicMotion motion_data{ | 45 | const BasicMotion motion_data{ |
| 29 | .gyro_x = gyro_x, | 46 | .gyro_x = gyro_x, |
| 30 | .gyro_y = gyro_y, | 47 | .gyro_y = gyro_y, |
| @@ -37,10 +54,295 @@ void Android::SetMotionState(std::size_t controller_number, u64 delta_timestamp, | |||
| 37 | SetMotion(identifier, 0, motion_data); | 54 | SetMotion(identifier, 0, motion_data); |
| 38 | } | 55 | } |
| 39 | 56 | ||
| 40 | PadIdentifier Android::GetIdentifier(std::size_t controller_number) const { | 57 | Common::Input::DriverResult Android::SetVibration( |
| 58 | [[maybe_unused]] const PadIdentifier& identifier, | ||
| 59 | [[maybe_unused]] const Common::Input::VibrationStatus& vibration) { | ||
| 60 | auto device = input_devices.find(identifier); | ||
| 61 | if (device != input_devices.end()) { | ||
| 62 | Common::Android::RunJNIOnFiber<void>([&](JNIEnv* env) { | ||
| 63 | float average_intensity = | ||
| 64 | static_cast<float>((vibration.high_amplitude + vibration.low_amplitude) / 2.0); | ||
| 65 | env->CallVoidMethod(device->second, Common::Android::GetYuzuDeviceVibrate(), | ||
| 66 | average_intensity); | ||
| 67 | }); | ||
| 68 | return Common::Input::DriverResult::Success; | ||
| 69 | } | ||
| 70 | return Common::Input::DriverResult::NotSupported; | ||
| 71 | } | ||
| 72 | |||
| 73 | bool Android::IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) { | ||
| 74 | auto device = input_devices.find(identifier); | ||
| 75 | if (device != input_devices.end()) { | ||
| 76 | return Common::Android::RunJNIOnFiber<bool>([&](JNIEnv* env) { | ||
| 77 | return static_cast<bool>(env->CallBooleanMethod( | ||
| 78 | device->second, Common::Android::GetYuzuDeviceGetSupportsVibration())); | ||
| 79 | }); | ||
| 80 | } | ||
| 81 | return false; | ||
| 82 | } | ||
| 83 | |||
| 84 | std::vector<Common::ParamPackage> Android::GetInputDevices() const { | ||
| 85 | std::vector<Common::ParamPackage> devices; | ||
| 86 | auto env = Common::Android::GetEnvForThread(); | ||
| 87 | for (const auto& [key, value] : input_devices) { | ||
| 88 | auto name_object = static_cast<jstring>( | ||
| 89 | env->CallObjectMethod(value, Common::Android::GetYuzuDeviceGetName())); | ||
| 90 | const std::string name = | ||
| 91 | fmt::format("{} {}", Common::Android::GetJString(env, name_object), key.port); | ||
| 92 | devices.emplace_back(Common::ParamPackage{ | ||
| 93 | {"engine", GetEngineName()}, | ||
| 94 | {"display", std::move(name)}, | ||
| 95 | {"guid", key.guid.RawString()}, | ||
| 96 | {"port", std::to_string(key.port)}, | ||
| 97 | }); | ||
| 98 | } | ||
| 99 | return devices; | ||
| 100 | } | ||
| 101 | |||
| 102 | std::set<s32> Android::GetDeviceAxes(JNIEnv* env, jobject& j_device) const { | ||
| 103 | auto j_axes = static_cast<jobjectArray>( | ||
| 104 | env->CallObjectMethod(j_device, Common::Android::GetYuzuDeviceGetAxes())); | ||
| 105 | std::set<s32> axes; | ||
| 106 | for (int i = 0; i < env->GetArrayLength(j_axes); ++i) { | ||
| 107 | jobject axis = env->GetObjectArrayElement(j_axes, i); | ||
| 108 | axes.insert(env->GetIntField(axis, Common::Android::GetIntegerValueField())); | ||
| 109 | } | ||
| 110 | return axes; | ||
| 111 | } | ||
| 112 | |||
| 113 | Common::ParamPackage Android::BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x, | ||
| 114 | int axis_y) const { | ||
| 115 | Common::ParamPackage params; | ||
| 116 | params.Set("engine", GetEngineName()); | ||
| 117 | params.Set("port", static_cast<int>(identifier.port)); | ||
| 118 | params.Set("guid", identifier.guid.RawString()); | ||
| 119 | params.Set("axis_x", axis_x); | ||
| 120 | params.Set("axis_y", axis_y); | ||
| 121 | params.Set("offset_x", 0); | ||
| 122 | params.Set("offset_y", 0); | ||
| 123 | params.Set("invert_x", "+"); | ||
| 124 | |||
| 125 | // Invert Y-Axis by default | ||
| 126 | params.Set("invert_y", "-"); | ||
| 127 | return params; | ||
| 128 | } | ||
| 129 | |||
| 130 | Common::ParamPackage Android::BuildAnalogParamPackageForButton(PadIdentifier identifier, s32 axis, | ||
| 131 | bool invert) const { | ||
| 132 | Common::ParamPackage params{}; | ||
| 133 | params.Set("engine", GetEngineName()); | ||
| 134 | params.Set("port", static_cast<int>(identifier.port)); | ||
| 135 | params.Set("guid", identifier.guid.RawString()); | ||
| 136 | params.Set("axis", axis); | ||
| 137 | params.Set("threshold", "0.5"); | ||
| 138 | params.Set("invert", invert ? "-" : "+"); | ||
| 139 | return params; | ||
| 140 | } | ||
| 141 | |||
| 142 | Common::ParamPackage Android::BuildButtonParamPackageForButton(PadIdentifier identifier, | ||
| 143 | s32 button) const { | ||
| 144 | Common::ParamPackage params{}; | ||
| 145 | params.Set("engine", GetEngineName()); | ||
| 146 | params.Set("port", static_cast<int>(identifier.port)); | ||
| 147 | params.Set("guid", identifier.guid.RawString()); | ||
| 148 | params.Set("button", button); | ||
| 149 | return params; | ||
| 150 | } | ||
| 151 | |||
| 152 | bool Android::MatchVID(Common::UUID device, const std::vector<std::string>& vids) const { | ||
| 153 | for (size_t i = 0; i < vids.size(); ++i) { | ||
| 154 | auto fucker = device.RawString(); | ||
| 155 | if (fucker.find(vids[i]) != std::string::npos) { | ||
| 156 | return true; | ||
| 157 | } | ||
| 158 | } | ||
| 159 | return false; | ||
| 160 | } | ||
| 161 | |||
| 162 | AnalogMapping Android::GetAnalogMappingForDevice(const Common::ParamPackage& params) { | ||
| 163 | if (!params.Has("guid") || !params.Has("port")) { | ||
| 164 | return {}; | ||
| 165 | } | ||
| 166 | |||
| 167 | auto identifier = | ||
| 168 | GetIdentifier(params.Get("guid", ""), static_cast<size_t>(params.Get("port", 0))); | ||
| 169 | auto& j_device = input_devices[identifier]; | ||
| 170 | if (j_device == nullptr) { | ||
| 171 | return {}; | ||
| 172 | } | ||
| 173 | |||
| 174 | auto env = Common::Android::GetEnvForThread(); | ||
| 175 | std::set<s32> axes = GetDeviceAxes(env, j_device); | ||
| 176 | if (axes.size() == 0) { | ||
| 177 | return {}; | ||
| 178 | } | ||
| 179 | |||
| 180 | AnalogMapping mapping = {}; | ||
| 181 | if (axes.find(AXIS_X) != axes.end() && axes.find(AXIS_Y) != axes.end()) { | ||
| 182 | mapping.insert_or_assign(Settings::NativeAnalog::LStick, | ||
| 183 | BuildParamPackageForAnalog(identifier, AXIS_X, AXIS_Y)); | ||
| 184 | } | ||
| 185 | |||
| 186 | if (axes.find(AXIS_RX) != axes.end() && axes.find(AXIS_RY) != axes.end()) { | ||
| 187 | mapping.insert_or_assign(Settings::NativeAnalog::RStick, | ||
| 188 | BuildParamPackageForAnalog(identifier, AXIS_RX, AXIS_RY)); | ||
| 189 | } else if (axes.find(AXIS_Z) != axes.end() && axes.find(AXIS_RZ) != axes.end()) { | ||
| 190 | mapping.insert_or_assign(Settings::NativeAnalog::RStick, | ||
| 191 | BuildParamPackageForAnalog(identifier, AXIS_Z, AXIS_RZ)); | ||
| 192 | } | ||
| 193 | return mapping; | ||
| 194 | } | ||
| 195 | |||
| 196 | ButtonMapping Android::GetButtonMappingForDevice(const Common::ParamPackage& params) { | ||
| 197 | if (!params.Has("guid") || !params.Has("port")) { | ||
| 198 | return {}; | ||
| 199 | } | ||
| 200 | |||
| 201 | auto identifier = | ||
| 202 | GetIdentifier(params.Get("guid", ""), static_cast<size_t>(params.Get("port", 0))); | ||
| 203 | auto& j_device = input_devices[identifier]; | ||
| 204 | if (j_device == nullptr) { | ||
| 205 | return {}; | ||
| 206 | } | ||
| 207 | |||
| 208 | auto env = Common::Android::GetEnvForThread(); | ||
| 209 | jintArray j_keys = env->NewIntArray(static_cast<int>(keycode_ids.size())); | ||
| 210 | env->SetIntArrayRegion(j_keys, 0, static_cast<int>(keycode_ids.size()), keycode_ids.data()); | ||
| 211 | auto j_has_keys_object = static_cast<jbooleanArray>( | ||
| 212 | env->CallObjectMethod(j_device, Common::Android::GetYuzuDeviceHasKeys(), j_keys)); | ||
| 213 | jboolean isCopy = false; | ||
| 214 | jboolean* j_has_keys = env->GetBooleanArrayElements(j_has_keys_object, &isCopy); | ||
| 215 | |||
| 216 | std::set<s32> available_keys; | ||
| 217 | for (size_t i = 0; i < keycode_ids.size(); ++i) { | ||
| 218 | if (j_has_keys[i]) { | ||
| 219 | available_keys.insert(keycode_ids[i]); | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | // Some devices use axes instead of buttons for certain controls so we need all the axes here | ||
| 224 | std::set<s32> axes = GetDeviceAxes(env, j_device); | ||
| 225 | |||
| 226 | ButtonMapping mapping = {}; | ||
| 227 | if (axes.find(AXIS_HAT_X) != axes.end() && axes.find(AXIS_HAT_Y) != axes.end()) { | ||
| 228 | mapping.insert_or_assign(Settings::NativeButton::DUp, | ||
| 229 | BuildAnalogParamPackageForButton(identifier, AXIS_HAT_Y, true)); | ||
| 230 | mapping.insert_or_assign(Settings::NativeButton::DDown, | ||
| 231 | BuildAnalogParamPackageForButton(identifier, AXIS_HAT_Y, false)); | ||
| 232 | mapping.insert_or_assign(Settings::NativeButton::DLeft, | ||
| 233 | BuildAnalogParamPackageForButton(identifier, AXIS_HAT_X, true)); | ||
| 234 | mapping.insert_or_assign(Settings::NativeButton::DRight, | ||
| 235 | BuildAnalogParamPackageForButton(identifier, AXIS_HAT_X, false)); | ||
| 236 | } else if (available_keys.find(KEYCODE_DPAD_UP) != available_keys.end() && | ||
| 237 | available_keys.find(KEYCODE_DPAD_DOWN) != available_keys.end() && | ||
| 238 | available_keys.find(KEYCODE_DPAD_LEFT) != available_keys.end() && | ||
| 239 | available_keys.find(KEYCODE_DPAD_RIGHT) != available_keys.end()) { | ||
| 240 | mapping.insert_or_assign(Settings::NativeButton::DUp, | ||
| 241 | BuildButtonParamPackageForButton(identifier, KEYCODE_DPAD_UP)); | ||
| 242 | mapping.insert_or_assign(Settings::NativeButton::DDown, | ||
| 243 | BuildButtonParamPackageForButton(identifier, KEYCODE_DPAD_DOWN)); | ||
| 244 | mapping.insert_or_assign(Settings::NativeButton::DLeft, | ||
| 245 | BuildButtonParamPackageForButton(identifier, KEYCODE_DPAD_LEFT)); | ||
| 246 | mapping.insert_or_assign(Settings::NativeButton::DRight, | ||
| 247 | BuildButtonParamPackageForButton(identifier, KEYCODE_DPAD_RIGHT)); | ||
| 248 | } | ||
| 249 | |||
| 250 | if (axes.find(AXIS_LTRIGGER) != axes.end()) { | ||
| 251 | mapping.insert_or_assign(Settings::NativeButton::ZL, BuildAnalogParamPackageForButton( | ||
| 252 | identifier, AXIS_LTRIGGER, false)); | ||
| 253 | } else if (available_keys.find(KEYCODE_BUTTON_L2) != available_keys.end()) { | ||
| 254 | mapping.insert_or_assign(Settings::NativeButton::ZL, | ||
| 255 | BuildButtonParamPackageForButton(identifier, KEYCODE_BUTTON_L2)); | ||
| 256 | } | ||
| 257 | |||
| 258 | if (axes.find(AXIS_RTRIGGER) != axes.end()) { | ||
| 259 | mapping.insert_or_assign(Settings::NativeButton::ZR, BuildAnalogParamPackageForButton( | ||
| 260 | identifier, AXIS_RTRIGGER, false)); | ||
| 261 | } else if (available_keys.find(KEYCODE_BUTTON_R2) != available_keys.end()) { | ||
| 262 | mapping.insert_or_assign(Settings::NativeButton::ZR, | ||
| 263 | BuildButtonParamPackageForButton(identifier, KEYCODE_BUTTON_R2)); | ||
| 264 | } | ||
| 265 | |||
| 266 | if (available_keys.find(KEYCODE_BUTTON_A) != available_keys.end()) { | ||
| 267 | if (MatchVID(identifier.guid, flipped_ab_vids)) { | ||
| 268 | mapping.insert_or_assign(Settings::NativeButton::B, BuildButtonParamPackageForButton( | ||
| 269 | identifier, KEYCODE_BUTTON_A)); | ||
| 270 | } else { | ||
| 271 | mapping.insert_or_assign(Settings::NativeButton::A, BuildButtonParamPackageForButton( | ||
| 272 | identifier, KEYCODE_BUTTON_A)); | ||
| 273 | } | ||
| 274 | } | ||
| 275 | if (available_keys.find(KEYCODE_BUTTON_B) != available_keys.end()) { | ||
| 276 | if (MatchVID(identifier.guid, flipped_ab_vids)) { | ||
| 277 | mapping.insert_or_assign(Settings::NativeButton::A, BuildButtonParamPackageForButton( | ||
| 278 | identifier, KEYCODE_BUTTON_B)); | ||
| 279 | } else { | ||
| 280 | mapping.insert_or_assign(Settings::NativeButton::B, BuildButtonParamPackageForButton( | ||
| 281 | identifier, KEYCODE_BUTTON_B)); | ||
| 282 | } | ||
| 283 | } | ||
| 284 | if (available_keys.find(KEYCODE_BUTTON_X) != available_keys.end()) { | ||
| 285 | if (MatchVID(identifier.guid, flipped_xy_vids)) { | ||
| 286 | mapping.insert_or_assign(Settings::NativeButton::Y, BuildButtonParamPackageForButton( | ||
| 287 | identifier, KEYCODE_BUTTON_X)); | ||
| 288 | } else { | ||
| 289 | mapping.insert_or_assign(Settings::NativeButton::X, BuildButtonParamPackageForButton( | ||
| 290 | identifier, KEYCODE_BUTTON_X)); | ||
| 291 | } | ||
| 292 | } | ||
| 293 | if (available_keys.find(KEYCODE_BUTTON_Y) != available_keys.end()) { | ||
| 294 | if (MatchVID(identifier.guid, flipped_xy_vids)) { | ||
| 295 | mapping.insert_or_assign(Settings::NativeButton::X, BuildButtonParamPackageForButton( | ||
| 296 | identifier, KEYCODE_BUTTON_Y)); | ||
| 297 | } else { | ||
| 298 | mapping.insert_or_assign(Settings::NativeButton::Y, BuildButtonParamPackageForButton( | ||
| 299 | identifier, KEYCODE_BUTTON_Y)); | ||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | if (available_keys.find(KEYCODE_BUTTON_L1) != available_keys.end()) { | ||
| 304 | mapping.insert_or_assign(Settings::NativeButton::L, | ||
| 305 | BuildButtonParamPackageForButton(identifier, KEYCODE_BUTTON_L1)); | ||
| 306 | } | ||
| 307 | if (available_keys.find(KEYCODE_BUTTON_R1) != available_keys.end()) { | ||
| 308 | mapping.insert_or_assign(Settings::NativeButton::R, | ||
| 309 | BuildButtonParamPackageForButton(identifier, KEYCODE_BUTTON_R1)); | ||
| 310 | } | ||
| 311 | |||
| 312 | if (available_keys.find(KEYCODE_BUTTON_THUMBL) != available_keys.end()) { | ||
| 313 | mapping.insert_or_assign( | ||
| 314 | Settings::NativeButton::LStick, | ||
| 315 | BuildButtonParamPackageForButton(identifier, KEYCODE_BUTTON_THUMBL)); | ||
| 316 | } | ||
| 317 | if (available_keys.find(KEYCODE_BUTTON_THUMBR) != available_keys.end()) { | ||
| 318 | mapping.insert_or_assign( | ||
| 319 | Settings::NativeButton::RStick, | ||
| 320 | BuildButtonParamPackageForButton(identifier, KEYCODE_BUTTON_THUMBR)); | ||
| 321 | } | ||
| 322 | |||
| 323 | if (available_keys.find(KEYCODE_BUTTON_START) != available_keys.end()) { | ||
| 324 | mapping.insert_or_assign( | ||
| 325 | Settings::NativeButton::Plus, | ||
| 326 | BuildButtonParamPackageForButton(identifier, KEYCODE_BUTTON_START)); | ||
| 327 | } | ||
| 328 | if (available_keys.find(KEYCODE_BUTTON_SELECT) != available_keys.end()) { | ||
| 329 | mapping.insert_or_assign( | ||
| 330 | Settings::NativeButton::Minus, | ||
| 331 | BuildButtonParamPackageForButton(identifier, KEYCODE_BUTTON_SELECT)); | ||
| 332 | } | ||
| 333 | |||
| 334 | return mapping; | ||
| 335 | } | ||
| 336 | |||
| 337 | Common::Input::ButtonNames Android::GetUIName( | ||
| 338 | [[maybe_unused]] const Common::ParamPackage& params) const { | ||
| 339 | return Common::Input::ButtonNames::Value; | ||
| 340 | } | ||
| 341 | |||
| 342 | PadIdentifier Android::GetIdentifier(const std::string& guid, size_t port) const { | ||
| 41 | return { | 343 | return { |
| 42 | .guid = Common::UUID{}, | 344 | .guid = Common::UUID{guid}, |
| 43 | .port = controller_number, | 345 | .port = port, |
| 44 | .pad = 0, | 346 | .pad = 0, |
| 45 | }; | 347 | }; |
| 46 | } | 348 | } |
diff --git a/src/input_common/drivers/android.h b/src/input_common/drivers/android.h index 3f01817f6..8a386c1b1 100644 --- a/src/input_common/drivers/android.h +++ b/src/input_common/drivers/android.h | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <set> | ||
| 7 | #include <jni.h> | ||
| 6 | #include "input_common/input_engine.h" | 8 | #include "input_common/input_engine.h" |
| 7 | 9 | ||
| 8 | namespace InputCommon { | 10 | namespace InputCommon { |
| @@ -15,40 +17,122 @@ public: | |||
| 15 | explicit Android(std::string input_engine_); | 17 | explicit Android(std::string input_engine_); |
| 16 | 18 | ||
| 17 | /** | 19 | /** |
| 18 | * Registers controller number to accept new inputs | 20 | * Registers controller number to accept new inputs. |
| 19 | * @param controller_number the controller number that will take this action | 21 | * @param j_input_device YuzuInputDevice object from the Android frontend to register. |
| 20 | */ | 22 | */ |
| 21 | void RegisterController(std::size_t controller_number); | 23 | void RegisterController(jobject j_input_device); |
| 22 | 24 | ||
| 23 | /** | 25 | /** |
| 24 | * Sets the status of all buttons bound with the key to pressed | 26 | * Sets the status of a button on a specific controller. |
| 25 | * @param controller_number the controller number that will take this action | 27 | * @param guid 32 character hexadecimal string consisting of the controller's PID+VID. |
| 26 | * @param button_id the id of the button | 28 | * @param port Port determined by controller connection order. |
| 27 | * @param value indicates if the button is pressed or not | 29 | * @param button_id The Android Keycode corresponding to this event. |
| 30 | * @param value Whether the button is pressed or not. | ||
| 28 | */ | 31 | */ |
| 29 | void SetButtonState(std::size_t controller_number, int button_id, bool value); | 32 | void SetButtonState(std::string guid, size_t port, int button_id, bool value); |
| 30 | 33 | ||
| 31 | /** | 34 | /** |
| 32 | * Sets the status of a analog input to a specific player index | 35 | * Sets the status of an axis on a specific controller. |
| 33 | * @param controller_number the controller number that will take this action | 36 | * @param guid 32 character hexadecimal string consisting of the controller's PID+VID. |
| 34 | * @param axis_id the id of the axis to move | 37 | * @param port Port determined by controller connection order. |
| 35 | * @param value the analog position of the axis | 38 | * @param axis_id The Android axis ID corresponding to this event. |
| 39 | * @param value Value along the given axis. | ||
| 36 | */ | 40 | */ |
| 37 | void SetAxisState(std::size_t controller_number, int axis_id, float value); | 41 | void SetAxisPosition(std::string guid, size_t port, int axis_id, float value); |
| 38 | 42 | ||
| 39 | /** | 43 | /** |
| 40 | * Sets the status of the motion sensor to a specific player index | 44 | * Sets the status of the motion sensor on a specific controller |
| 41 | * @param controller_number the controller number that will take this action | 45 | * @param guid 32 character hexadecimal string consisting of the controller's PID+VID. |
| 42 | * @param delta_timestamp time passed since last reading | 46 | * @param port Port determined by controller connection order. |
| 43 | * @param gyro_x,gyro_y,gyro_z the gyro sensor readings | 47 | * @param delta_timestamp Time passed since the last read. |
| 44 | * @param accel_x,accel_y,accel_z the accelerometer reading | 48 | * @param gyro_x,gyro_y,gyro_z Gyro sensor readings. |
| 49 | * @param accel_x,accel_y,accel_z Accelerometer sensor readings. | ||
| 45 | */ | 50 | */ |
| 46 | void SetMotionState(std::size_t controller_number, u64 delta_timestamp, float gyro_x, | 51 | void SetMotionState(std::string guid, size_t port, u64 delta_timestamp, float gyro_x, |
| 47 | float gyro_y, float gyro_z, float accel_x, float accel_y, float accel_z); | 52 | float gyro_y, float gyro_z, float accel_x, float accel_y, float accel_z); |
| 48 | 53 | ||
| 54 | Common::Input::DriverResult SetVibration( | ||
| 55 | const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; | ||
| 56 | |||
| 57 | bool IsVibrationEnabled(const PadIdentifier& identifier) override; | ||
| 58 | |||
| 59 | std::vector<Common::ParamPackage> GetInputDevices() const override; | ||
| 60 | |||
| 61 | /** | ||
| 62 | * Gets the axes reported by the YuzuInputDevice. | ||
| 63 | * @param env JNI environment pointer. | ||
| 64 | * @param j_device YuzuInputDevice from the Android frontend. | ||
| 65 | * @return Set of the axes reported by the underlying Android InputDevice | ||
| 66 | */ | ||
| 67 | std::set<s32> GetDeviceAxes(JNIEnv* env, jobject& j_device) const; | ||
| 68 | |||
| 69 | Common::ParamPackage BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x, | ||
| 70 | int axis_y) const; | ||
| 71 | |||
| 72 | Common::ParamPackage BuildAnalogParamPackageForButton(PadIdentifier identifier, s32 axis, | ||
| 73 | bool invert) const; | ||
| 74 | |||
| 75 | Common::ParamPackage BuildButtonParamPackageForButton(PadIdentifier identifier, | ||
| 76 | s32 button) const; | ||
| 77 | |||
| 78 | bool MatchVID(Common::UUID device, const std::vector<std::string>& vids) const; | ||
| 79 | |||
| 80 | AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; | ||
| 81 | |||
| 82 | ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; | ||
| 83 | |||
| 84 | Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override; | ||
| 85 | |||
| 49 | private: | 86 | private: |
| 87 | std::unordered_map<PadIdentifier, jobject> input_devices; | ||
| 88 | |||
| 50 | /// Returns the correct identifier corresponding to the player index | 89 | /// Returns the correct identifier corresponding to the player index |
| 51 | PadIdentifier GetIdentifier(std::size_t controller_number) const; | 90 | PadIdentifier GetIdentifier(const std::string& guid, size_t port) const; |
| 91 | |||
| 92 | static constexpr s32 AXIS_X = 0; | ||
| 93 | static constexpr s32 AXIS_Y = 1; | ||
| 94 | static constexpr s32 AXIS_Z = 11; | ||
| 95 | static constexpr s32 AXIS_RX = 12; | ||
| 96 | static constexpr s32 AXIS_RY = 13; | ||
| 97 | static constexpr s32 AXIS_RZ = 14; | ||
| 98 | static constexpr s32 AXIS_HAT_X = 15; | ||
| 99 | static constexpr s32 AXIS_HAT_Y = 16; | ||
| 100 | static constexpr s32 AXIS_LTRIGGER = 17; | ||
| 101 | static constexpr s32 AXIS_RTRIGGER = 18; | ||
| 102 | |||
| 103 | static constexpr s32 KEYCODE_DPAD_UP = 19; | ||
| 104 | static constexpr s32 KEYCODE_DPAD_DOWN = 20; | ||
| 105 | static constexpr s32 KEYCODE_DPAD_LEFT = 21; | ||
| 106 | static constexpr s32 KEYCODE_DPAD_RIGHT = 22; | ||
| 107 | static constexpr s32 KEYCODE_BUTTON_A = 96; | ||
| 108 | static constexpr s32 KEYCODE_BUTTON_B = 97; | ||
| 109 | static constexpr s32 KEYCODE_BUTTON_X = 99; | ||
| 110 | static constexpr s32 KEYCODE_BUTTON_Y = 100; | ||
| 111 | static constexpr s32 KEYCODE_BUTTON_L1 = 102; | ||
| 112 | static constexpr s32 KEYCODE_BUTTON_R1 = 103; | ||
| 113 | static constexpr s32 KEYCODE_BUTTON_L2 = 104; | ||
| 114 | static constexpr s32 KEYCODE_BUTTON_R2 = 105; | ||
| 115 | static constexpr s32 KEYCODE_BUTTON_THUMBL = 106; | ||
| 116 | static constexpr s32 KEYCODE_BUTTON_THUMBR = 107; | ||
| 117 | static constexpr s32 KEYCODE_BUTTON_START = 108; | ||
| 118 | static constexpr s32 KEYCODE_BUTTON_SELECT = 109; | ||
| 119 | const std::vector<s32> keycode_ids{ | ||
| 120 | KEYCODE_DPAD_UP, KEYCODE_DPAD_DOWN, KEYCODE_DPAD_LEFT, KEYCODE_DPAD_RIGHT, | ||
| 121 | KEYCODE_BUTTON_A, KEYCODE_BUTTON_B, KEYCODE_BUTTON_X, KEYCODE_BUTTON_Y, | ||
| 122 | KEYCODE_BUTTON_L1, KEYCODE_BUTTON_R1, KEYCODE_BUTTON_L2, KEYCODE_BUTTON_R2, | ||
| 123 | KEYCODE_BUTTON_THUMBL, KEYCODE_BUTTON_THUMBR, KEYCODE_BUTTON_START, KEYCODE_BUTTON_SELECT, | ||
| 124 | }; | ||
| 125 | |||
| 126 | const std::string sony_vid{"054c"}; | ||
| 127 | const std::string nintendo_vid{"057e"}; | ||
| 128 | const std::string razer_vid{"1532"}; | ||
| 129 | const std::string redmagic_vid{"3537"}; | ||
| 130 | const std::string backbone_labs_vid{"358a"}; | ||
| 131 | const std::string xbox_vid{"045e"}; | ||
| 132 | const std::vector<std::string> flipped_ab_vids{sony_vid, nintendo_vid, razer_vid, | ||
| 133 | redmagic_vid, backbone_labs_vid, xbox_vid}; | ||
| 134 | const std::vector<std::string> flipped_xy_vids{sony_vid, razer_vid, redmagic_vid, | ||
| 135 | backbone_labs_vid, xbox_vid}; | ||
| 52 | }; | 136 | }; |
| 53 | 137 | ||
| 54 | } // namespace InputCommon | 138 | } // namespace InputCommon |
diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index c9f903213..0dd1c958a 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp | |||
| @@ -268,7 +268,9 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { | |||
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | Common::Input::DriverResult JoyconDriver::SetPollingMode() { | 270 | Common::Input::DriverResult JoyconDriver::SetPollingMode() { |
| 271 | SCOPE_EXIT({ disable_input_thread = false; }); | 271 | SCOPE_EXIT { |
| 272 | disable_input_thread = false; | ||
| 273 | }; | ||
| 272 | disable_input_thread = true; | 274 | disable_input_thread = true; |
| 273 | 275 | ||
| 274 | rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); | 276 | rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); |
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index f8749ebbf..62a7ae40f 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | #include <memory> | 4 | #include <memory> |
| 5 | #include "common/input.h" | 5 | #include "common/input.h" |
| 6 | #include "common/param_package.h" | 6 | #include "common/param_package.h" |
| 7 | #include "input_common/drivers/android.h" | ||
| 8 | #include "input_common/drivers/camera.h" | 7 | #include "input_common/drivers/camera.h" |
| 9 | #include "input_common/drivers/keyboard.h" | 8 | #include "input_common/drivers/keyboard.h" |
| 10 | #include "input_common/drivers/mouse.h" | 9 | #include "input_common/drivers/mouse.h" |
| @@ -28,6 +27,10 @@ | |||
| 28 | #include "input_common/drivers/sdl_driver.h" | 27 | #include "input_common/drivers/sdl_driver.h" |
| 29 | #endif | 28 | #endif |
| 30 | 29 | ||
| 30 | #ifdef ANDROID | ||
| 31 | #include "input_common/drivers/android.h" | ||
| 32 | #endif | ||
| 33 | |||
| 31 | namespace InputCommon { | 34 | namespace InputCommon { |
| 32 | 35 | ||
| 33 | /// Dummy engine to get periodic updates | 36 | /// Dummy engine to get periodic updates |
| @@ -79,7 +82,9 @@ struct InputSubsystem::Impl { | |||
| 79 | RegisterEngine("cemuhookudp", udp_client); | 82 | RegisterEngine("cemuhookudp", udp_client); |
| 80 | RegisterEngine("tas", tas_input); | 83 | RegisterEngine("tas", tas_input); |
| 81 | RegisterEngine("camera", camera); | 84 | RegisterEngine("camera", camera); |
| 85 | #ifdef ANDROID | ||
| 82 | RegisterEngine("android", android); | 86 | RegisterEngine("android", android); |
| 87 | #endif | ||
| 83 | RegisterEngine("virtual_amiibo", virtual_amiibo); | 88 | RegisterEngine("virtual_amiibo", virtual_amiibo); |
| 84 | RegisterEngine("virtual_gamepad", virtual_gamepad); | 89 | RegisterEngine("virtual_gamepad", virtual_gamepad); |
| 85 | #ifdef HAVE_SDL2 | 90 | #ifdef HAVE_SDL2 |
| @@ -111,7 +116,9 @@ struct InputSubsystem::Impl { | |||
| 111 | UnregisterEngine(udp_client); | 116 | UnregisterEngine(udp_client); |
| 112 | UnregisterEngine(tas_input); | 117 | UnregisterEngine(tas_input); |
| 113 | UnregisterEngine(camera); | 118 | UnregisterEngine(camera); |
| 119 | #ifdef ANDROID | ||
| 114 | UnregisterEngine(android); | 120 | UnregisterEngine(android); |
| 121 | #endif | ||
| 115 | UnregisterEngine(virtual_amiibo); | 122 | UnregisterEngine(virtual_amiibo); |
| 116 | UnregisterEngine(virtual_gamepad); | 123 | UnregisterEngine(virtual_gamepad); |
| 117 | #ifdef HAVE_SDL2 | 124 | #ifdef HAVE_SDL2 |
| @@ -128,12 +135,16 @@ struct InputSubsystem::Impl { | |||
| 128 | Common::ParamPackage{{"display", "Any"}, {"engine", "any"}}, | 135 | Common::ParamPackage{{"display", "Any"}, {"engine", "any"}}, |
| 129 | }; | 136 | }; |
| 130 | 137 | ||
| 138 | #ifndef ANDROID | ||
| 131 | auto keyboard_devices = keyboard->GetInputDevices(); | 139 | auto keyboard_devices = keyboard->GetInputDevices(); |
| 132 | devices.insert(devices.end(), keyboard_devices.begin(), keyboard_devices.end()); | 140 | devices.insert(devices.end(), keyboard_devices.begin(), keyboard_devices.end()); |
| 133 | auto mouse_devices = mouse->GetInputDevices(); | 141 | auto mouse_devices = mouse->GetInputDevices(); |
| 134 | devices.insert(devices.end(), mouse_devices.begin(), mouse_devices.end()); | 142 | devices.insert(devices.end(), mouse_devices.begin(), mouse_devices.end()); |
| 143 | #endif | ||
| 144 | #ifdef ANDROID | ||
| 135 | auto android_devices = android->GetInputDevices(); | 145 | auto android_devices = android->GetInputDevices(); |
| 136 | devices.insert(devices.end(), android_devices.begin(), android_devices.end()); | 146 | devices.insert(devices.end(), android_devices.begin(), android_devices.end()); |
| 147 | #endif | ||
| 137 | #ifdef HAVE_LIBUSB | 148 | #ifdef HAVE_LIBUSB |
| 138 | auto gcadapter_devices = gcadapter->GetInputDevices(); | 149 | auto gcadapter_devices = gcadapter->GetInputDevices(); |
| 139 | devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end()); | 150 | devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end()); |
| @@ -162,9 +173,11 @@ struct InputSubsystem::Impl { | |||
| 162 | if (engine == mouse->GetEngineName()) { | 173 | if (engine == mouse->GetEngineName()) { |
| 163 | return mouse; | 174 | return mouse; |
| 164 | } | 175 | } |
| 176 | #ifdef ANDROID | ||
| 165 | if (engine == android->GetEngineName()) { | 177 | if (engine == android->GetEngineName()) { |
| 166 | return android; | 178 | return android; |
| 167 | } | 179 | } |
| 180 | #endif | ||
| 168 | #ifdef HAVE_LIBUSB | 181 | #ifdef HAVE_LIBUSB |
| 169 | if (engine == gcadapter->GetEngineName()) { | 182 | if (engine == gcadapter->GetEngineName()) { |
| 170 | return gcadapter; | 183 | return gcadapter; |
| @@ -245,9 +258,11 @@ struct InputSubsystem::Impl { | |||
| 245 | if (engine == mouse->GetEngineName()) { | 258 | if (engine == mouse->GetEngineName()) { |
| 246 | return true; | 259 | return true; |
| 247 | } | 260 | } |
| 261 | #ifdef ANDROID | ||
| 248 | if (engine == android->GetEngineName()) { | 262 | if (engine == android->GetEngineName()) { |
| 249 | return true; | 263 | return true; |
| 250 | } | 264 | } |
| 265 | #endif | ||
| 251 | #ifdef HAVE_LIBUSB | 266 | #ifdef HAVE_LIBUSB |
| 252 | if (engine == gcadapter->GetEngineName()) { | 267 | if (engine == gcadapter->GetEngineName()) { |
| 253 | return true; | 268 | return true; |
| @@ -276,7 +291,9 @@ struct InputSubsystem::Impl { | |||
| 276 | void BeginConfiguration() { | 291 | void BeginConfiguration() { |
| 277 | keyboard->BeginConfiguration(); | 292 | keyboard->BeginConfiguration(); |
| 278 | mouse->BeginConfiguration(); | 293 | mouse->BeginConfiguration(); |
| 294 | #ifdef ANDROID | ||
| 279 | android->BeginConfiguration(); | 295 | android->BeginConfiguration(); |
| 296 | #endif | ||
| 280 | #ifdef HAVE_LIBUSB | 297 | #ifdef HAVE_LIBUSB |
| 281 | gcadapter->BeginConfiguration(); | 298 | gcadapter->BeginConfiguration(); |
| 282 | #endif | 299 | #endif |
| @@ -290,7 +307,9 @@ struct InputSubsystem::Impl { | |||
| 290 | void EndConfiguration() { | 307 | void EndConfiguration() { |
| 291 | keyboard->EndConfiguration(); | 308 | keyboard->EndConfiguration(); |
| 292 | mouse->EndConfiguration(); | 309 | mouse->EndConfiguration(); |
| 310 | #ifdef ANDROID | ||
| 293 | android->EndConfiguration(); | 311 | android->EndConfiguration(); |
| 312 | #endif | ||
| 294 | #ifdef HAVE_LIBUSB | 313 | #ifdef HAVE_LIBUSB |
| 295 | gcadapter->EndConfiguration(); | 314 | gcadapter->EndConfiguration(); |
| 296 | #endif | 315 | #endif |
| @@ -321,7 +340,6 @@ struct InputSubsystem::Impl { | |||
| 321 | std::shared_ptr<TasInput::Tas> tas_input; | 340 | std::shared_ptr<TasInput::Tas> tas_input; |
| 322 | std::shared_ptr<CemuhookUDP::UDPClient> udp_client; | 341 | std::shared_ptr<CemuhookUDP::UDPClient> udp_client; |
| 323 | std::shared_ptr<Camera> camera; | 342 | std::shared_ptr<Camera> camera; |
| 324 | std::shared_ptr<Android> android; | ||
| 325 | std::shared_ptr<VirtualAmiibo> virtual_amiibo; | 343 | std::shared_ptr<VirtualAmiibo> virtual_amiibo; |
| 326 | std::shared_ptr<VirtualGamepad> virtual_gamepad; | 344 | std::shared_ptr<VirtualGamepad> virtual_gamepad; |
| 327 | 345 | ||
| @@ -333,6 +351,10 @@ struct InputSubsystem::Impl { | |||
| 333 | std::shared_ptr<SDLDriver> sdl; | 351 | std::shared_ptr<SDLDriver> sdl; |
| 334 | std::shared_ptr<Joycons> joycon; | 352 | std::shared_ptr<Joycons> joycon; |
| 335 | #endif | 353 | #endif |
| 354 | |||
| 355 | #ifdef ANDROID | ||
| 356 | std::shared_ptr<Android> android; | ||
| 357 | #endif | ||
| 336 | }; | 358 | }; |
| 337 | 359 | ||
| 338 | InputSubsystem::InputSubsystem() : impl{std::make_unique<Impl>()} {} | 360 | InputSubsystem::InputSubsystem() : impl{std::make_unique<Impl>()} {} |
| @@ -387,6 +409,7 @@ const Camera* InputSubsystem::GetCamera() const { | |||
| 387 | return impl->camera.get(); | 409 | return impl->camera.get(); |
| 388 | } | 410 | } |
| 389 | 411 | ||
| 412 | #ifdef ANDROID | ||
| 390 | Android* InputSubsystem::GetAndroid() { | 413 | Android* InputSubsystem::GetAndroid() { |
| 391 | return impl->android.get(); | 414 | return impl->android.get(); |
| 392 | } | 415 | } |
| @@ -394,6 +417,7 @@ Android* InputSubsystem::GetAndroid() { | |||
| 394 | const Android* InputSubsystem::GetAndroid() const { | 417 | const Android* InputSubsystem::GetAndroid() const { |
| 395 | return impl->android.get(); | 418 | return impl->android.get(); |
| 396 | } | 419 | } |
| 420 | #endif | ||
| 397 | 421 | ||
| 398 | VirtualAmiibo* InputSubsystem::GetVirtualAmiibo() { | 422 | VirtualAmiibo* InputSubsystem::GetVirtualAmiibo() { |
| 399 | return impl->virtual_amiibo.get(); | 423 | return impl->virtual_amiibo.get(); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp index 44281e407..945cdb42b 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp | |||
| @@ -60,11 +60,10 @@ public: | |||
| 60 | Add(spv::ImageOperandsMask::ConstOffsets, offsets); | 60 | Add(spv::ImageOperandsMask::ConstOffsets, offsets); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | explicit ImageOperands(EmitContext& ctx, const IR::Value& offset, Id lod, Id ms) { | 63 | explicit ImageOperands(Id lod, Id ms) { |
| 64 | if (Sirit::ValidId(lod)) { | 64 | if (Sirit::ValidId(lod)) { |
| 65 | Add(spv::ImageOperandsMask::Lod, lod); | 65 | Add(spv::ImageOperandsMask::Lod, lod); |
| 66 | } | 66 | } |
| 67 | AddOffset(ctx, offset, ImageFetchOffsetAllowed); | ||
| 68 | if (Sirit::ValidId(ms)) { | 67 | if (Sirit::ValidId(ms)) { |
| 69 | Add(spv::ImageOperandsMask::Sample, ms); | 68 | Add(spv::ImageOperandsMask::Sample, ms); |
| 70 | } | 69 | } |
| @@ -312,6 +311,43 @@ Id ImageGatherSubpixelOffset(EmitContext& ctx, const IR::TextureInstInfo& info, | |||
| 312 | return coords; | 311 | return coords; |
| 313 | } | 312 | } |
| 314 | } | 313 | } |
| 314 | |||
| 315 | void AddOffsetToCoordinates(EmitContext& ctx, const IR::TextureInstInfo& info, Id& coords, | ||
| 316 | Id offset) { | ||
| 317 | if (!Sirit::ValidId(offset)) { | ||
| 318 | return; | ||
| 319 | } | ||
| 320 | |||
| 321 | Id result_type{}; | ||
| 322 | switch (info.type) { | ||
| 323 | case TextureType::Buffer: | ||
| 324 | case TextureType::Color1D: { | ||
| 325 | result_type = ctx.U32[1]; | ||
| 326 | break; | ||
| 327 | } | ||
| 328 | case TextureType::ColorArray1D: | ||
| 329 | offset = ctx.OpCompositeConstruct(ctx.U32[2], offset, ctx.u32_zero_value); | ||
| 330 | [[fallthrough]]; | ||
| 331 | case TextureType::Color2D: | ||
| 332 | case TextureType::Color2DRect: { | ||
| 333 | result_type = ctx.U32[2]; | ||
| 334 | break; | ||
| 335 | } | ||
| 336 | case TextureType::ColorArray2D: | ||
| 337 | offset = ctx.OpCompositeConstruct(ctx.U32[3], ctx.OpCompositeExtract(ctx.U32[1], coords, 0), | ||
| 338 | ctx.OpCompositeExtract(ctx.U32[1], coords, 1), | ||
| 339 | ctx.u32_zero_value); | ||
| 340 | [[fallthrough]]; | ||
| 341 | case TextureType::Color3D: { | ||
| 342 | result_type = ctx.U32[3]; | ||
| 343 | break; | ||
| 344 | } | ||
| 345 | case TextureType::ColorCube: | ||
| 346 | case TextureType::ColorArrayCube: | ||
| 347 | return; | ||
| 348 | } | ||
| 349 | coords = ctx.OpIAdd(result_type, coords, offset); | ||
| 350 | } | ||
| 315 | } // Anonymous namespace | 351 | } // Anonymous namespace |
| 316 | 352 | ||
| 317 | Id EmitBindlessImageSampleImplicitLod(EmitContext&) { | 353 | Id EmitBindlessImageSampleImplicitLod(EmitContext&) { |
| @@ -494,9 +530,10 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, | |||
| 494 | operands.Span()); | 530 | operands.Span()); |
| 495 | } | 531 | } |
| 496 | 532 | ||
| 497 | Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | 533 | Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, |
| 498 | const IR::Value& offset, Id lod, Id ms) { | 534 | Id lod, Id ms) { |
| 499 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | 535 | const auto info{inst->Flags<IR::TextureInstInfo>()}; |
| 536 | AddOffsetToCoordinates(ctx, info, coords, offset); | ||
| 500 | if (info.type == TextureType::Buffer) { | 537 | if (info.type == TextureType::Buffer) { |
| 501 | lod = Id{}; | 538 | lod = Id{}; |
| 502 | } | 539 | } |
| @@ -504,7 +541,7 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c | |||
| 504 | // This image is multisampled, lod must be implicit | 541 | // This image is multisampled, lod must be implicit |
| 505 | lod = Id{}; | 542 | lod = Id{}; |
| 506 | } | 543 | } |
| 507 | const ImageOperands operands(ctx, offset, lod, ms); | 544 | const ImageOperands operands(lod, ms); |
| 508 | return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4], | 545 | return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4], |
| 509 | TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span()); | 546 | TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span()); |
| 510 | } | 547 | } |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 08fcabd58..5c01b1012 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h | |||
| @@ -537,8 +537,8 @@ Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id | |||
| 537 | const IR::Value& offset, const IR::Value& offset2); | 537 | const IR::Value& offset, const IR::Value& offset2); |
| 538 | Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | 538 | Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, |
| 539 | const IR::Value& offset, const IR::Value& offset2, Id dref); | 539 | const IR::Value& offset, const IR::Value& offset2, Id dref); |
| 540 | Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | 540 | Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, |
| 541 | const IR::Value& offset, Id lod, Id ms); | 541 | Id lod, Id ms); |
| 542 | Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod, | 542 | Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod, |
| 543 | const IR::Value& skip_mips); | 543 | const IR::Value& skip_mips); |
| 544 | Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); | 544 | Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); |
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 6d3d933c5..296c90e85 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h | |||
| @@ -1130,7 +1130,7 @@ void BufferCache<P>::UpdateVertexBuffer(u32 index) { | |||
| 1130 | channel_state->vertex_buffers[index] = NULL_BINDING; | 1130 | channel_state->vertex_buffers[index] = NULL_BINDING; |
| 1131 | return; | 1131 | return; |
| 1132 | } | 1132 | } |
| 1133 | if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end)) { | 1133 | if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end) || size >= 64_MiB) { |
| 1134 | size = static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, size)); | 1134 | size = static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, size)); |
| 1135 | } | 1135 | } |
| 1136 | const BufferId buffer_id = FindBuffer(*device_addr, size); | 1136 | const BufferId buffer_id = FindBuffer(*device_addr, size); |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index a94e1f043..0d47b032c 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -291,7 +291,9 @@ u32 Maxwell3D::ProcessShadowRam(u32 method, u32 argument) { | |||
| 291 | } | 291 | } |
| 292 | 292 | ||
| 293 | void Maxwell3D::ConsumeSinkImpl() { | 293 | void Maxwell3D::ConsumeSinkImpl() { |
| 294 | SCOPE_EXIT({ method_sink.clear(); }); | 294 | SCOPE_EXIT { |
| 295 | method_sink.clear(); | ||
| 296 | }; | ||
| 295 | const auto control = shadow_state.shadow_ram_control; | 297 | const auto control = shadow_state.shadow_ram_control; |
| 296 | if (control == Regs::ShadowRamControl::Track || | 298 | if (control == Regs::ShadowRamControl::Track || |
| 297 | control == Regs::ShadowRamControl::TrackWithFilter) { | 299 | control == Regs::ShadowRamControl::TrackWithFilter) { |
diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h index c3eda6893..2135f1f2d 100644 --- a/src/video_core/fence_manager.h +++ b/src/video_core/fence_manager.h | |||
| @@ -197,7 +197,9 @@ private: | |||
| 197 | MicroProfileOnThreadCreate(name.c_str()); | 197 | MicroProfileOnThreadCreate(name.c_str()); |
| 198 | 198 | ||
| 199 | // Cleanup | 199 | // Cleanup |
| 200 | SCOPE_EXIT({ MicroProfileOnThreadExit(); }); | 200 | SCOPE_EXIT { |
| 201 | MicroProfileOnThreadExit(); | ||
| 202 | }; | ||
| 201 | 203 | ||
| 202 | Common::SetCurrentThreadName(name.c_str()); | 204 | Common::SetCurrentThreadName(name.c_str()); |
| 203 | Common::SetCurrentThreadPriority(Common::ThreadPriority::High); | 205 | Common::SetCurrentThreadPriority(Common::ThreadPriority::High); |
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index 58d8110b8..477e11457 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp | |||
| @@ -22,7 +22,9 @@ static void RunThread(std::stop_token stop_token, Core::System& system, | |||
| 22 | Tegra::Control::Scheduler& scheduler, SynchState& state) { | 22 | Tegra::Control::Scheduler& scheduler, SynchState& state) { |
| 23 | std::string name = "GPU"; | 23 | std::string name = "GPU"; |
| 24 | MicroProfileOnThreadCreate(name.c_str()); | 24 | MicroProfileOnThreadCreate(name.c_str()); |
| 25 | SCOPE_EXIT({ MicroProfileOnThreadExit(); }); | 25 | SCOPE_EXIT { |
| 26 | MicroProfileOnThreadExit(); | ||
| 27 | }; | ||
| 26 | 28 | ||
| 27 | Common::SetCurrentThreadName(name.c_str()); | 29 | Common::SetCurrentThreadName(name.c_str()); |
| 28 | Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical); | 30 | Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical); |
diff --git a/src/video_core/host1x/ffmpeg/ffmpeg.cpp b/src/video_core/host1x/ffmpeg/ffmpeg.cpp index 96686da59..1003cd38d 100644 --- a/src/video_core/host1x/ffmpeg/ffmpeg.cpp +++ b/src/video_core/host1x/ffmpeg/ffmpeg.cpp | |||
| @@ -273,10 +273,10 @@ DeinterlaceFilter::DeinterlaceFilter(const Frame& frame) { | |||
| 273 | const AVFilter* buffer_sink = avfilter_get_by_name("buffersink"); | 273 | const AVFilter* buffer_sink = avfilter_get_by_name("buffersink"); |
| 274 | AVFilterInOut* inputs = avfilter_inout_alloc(); | 274 | AVFilterInOut* inputs = avfilter_inout_alloc(); |
| 275 | AVFilterInOut* outputs = avfilter_inout_alloc(); | 275 | AVFilterInOut* outputs = avfilter_inout_alloc(); |
| 276 | SCOPE_EXIT({ | 276 | SCOPE_EXIT { |
| 277 | avfilter_inout_free(&inputs); | 277 | avfilter_inout_free(&inputs); |
| 278 | avfilter_inout_free(&outputs); | 278 | avfilter_inout_free(&outputs); |
| 279 | }); | 279 | }; |
| 280 | 280 | ||
| 281 | // Don't know how to get the accurate time_base but it doesn't matter for yadif filter | 281 | // Don't know how to get the accurate time_base but it doesn't matter for yadif filter |
| 282 | // so just use 1/1 to make buffer filter happy | 282 | // so just use 1/1 to make buffer filter happy |
diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp index 46e853e04..fb529f88b 100644 --- a/src/video_core/macro/macro_hle.cpp +++ b/src/video_core/macro/macro_hle.cpp | |||
| @@ -92,12 +92,12 @@ public: | |||
| 92 | 92 | ||
| 93 | private: | 93 | private: |
| 94 | void Fallback(const std::vector<u32>& parameters) { | 94 | void Fallback(const std::vector<u32>& parameters) { |
| 95 | SCOPE_EXIT({ | 95 | SCOPE_EXIT { |
| 96 | if (extended) { | 96 | if (extended) { |
| 97 | maxwell3d.engine_state = Maxwell3D::EngineHint::None; | 97 | maxwell3d.engine_state = Maxwell3D::EngineHint::None; |
| 98 | maxwell3d.replace_table.clear(); | 98 | maxwell3d.replace_table.clear(); |
| 99 | } | 99 | } |
| 100 | }); | 100 | }; |
| 101 | maxwell3d.RefreshParameters(); | 101 | maxwell3d.RefreshParameters(); |
| 102 | const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); | 102 | const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); |
| 103 | 103 | ||
| @@ -281,12 +281,12 @@ public: | |||
| 281 | 281 | ||
| 282 | private: | 282 | private: |
| 283 | void Fallback(const std::vector<u32>& parameters) { | 283 | void Fallback(const std::vector<u32>& parameters) { |
| 284 | SCOPE_EXIT({ | 284 | SCOPE_EXIT { |
| 285 | // Clean everything. | 285 | // Clean everything. |
| 286 | maxwell3d.regs.vertex_id_base = 0x0; | 286 | maxwell3d.regs.vertex_id_base = 0x0; |
| 287 | maxwell3d.engine_state = Maxwell3D::EngineHint::None; | 287 | maxwell3d.engine_state = Maxwell3D::EngineHint::None; |
| 288 | maxwell3d.replace_table.clear(); | 288 | maxwell3d.replace_table.clear(); |
| 289 | }); | 289 | }; |
| 290 | maxwell3d.RefreshParameters(); | 290 | maxwell3d.RefreshParameters(); |
| 291 | const u32 start_indirect = parameters[0]; | 291 | const u32 start_indirect = parameters[0]; |
| 292 | const u32 end_indirect = parameters[1]; | 292 | const u32 end_indirect = parameters[1]; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index b42fb110c..16af8e6bd 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -230,7 +230,9 @@ template <typename Func> | |||
| 230 | void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) { | 230 | void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) { |
| 231 | MICROPROFILE_SCOPE(OpenGL_Drawing); | 231 | MICROPROFILE_SCOPE(OpenGL_Drawing); |
| 232 | 232 | ||
| 233 | SCOPE_EXIT({ gpu.TickWork(); }); | 233 | SCOPE_EXIT { |
| 234 | gpu.TickWork(); | ||
| 235 | }; | ||
| 234 | gpu_memory->FlushCaching(); | 236 | gpu_memory->FlushCaching(); |
| 235 | 237 | ||
| 236 | GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()}; | 238 | GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()}; |
| @@ -355,7 +357,9 @@ void RasterizerOpenGL::DrawIndirect() { | |||
| 355 | void RasterizerOpenGL::DrawTexture() { | 357 | void RasterizerOpenGL::DrawTexture() { |
| 356 | MICROPROFILE_SCOPE(OpenGL_Drawing); | 358 | MICROPROFILE_SCOPE(OpenGL_Drawing); |
| 357 | 359 | ||
| 358 | SCOPE_EXIT({ gpu.TickWork(); }); | 360 | SCOPE_EXIT { |
| 361 | gpu.TickWork(); | ||
| 362 | }; | ||
| 359 | 363 | ||
| 360 | texture_cache.SynchronizeGraphicsDescriptors(); | 364 | texture_cache.SynchronizeGraphicsDescriptors(); |
| 361 | texture_cache.UpdateRenderTargets(false); | 365 | texture_cache.UpdateRenderTargets(false); |
diff --git a/src/video_core/renderer_vulkan/present/layer.cpp b/src/video_core/renderer_vulkan/present/layer.cpp index 3847a9a13..4e41afe5b 100644 --- a/src/video_core/renderer_vulkan/present/layer.cpp +++ b/src/video_core/renderer_vulkan/present/layer.cpp | |||
| @@ -82,7 +82,9 @@ void Layer::ConfigureDraw(PresentPushConstants* out_push_constants, | |||
| 82 | // Finish any pending renderpass | 82 | // Finish any pending renderpass |
| 83 | scheduler.RequestOutsideRenderPassOperationContext(); | 83 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 84 | scheduler.Wait(resource_ticks[image_index]); | 84 | scheduler.Wait(resource_ticks[image_index]); |
| 85 | SCOPE_EXIT({ resource_ticks[image_index] = scheduler.CurrentTick(); }); | 85 | SCOPE_EXIT { |
| 86 | resource_ticks[image_index] = scheduler.CurrentTick(); | ||
| 87 | }; | ||
| 86 | 88 | ||
| 87 | if (!use_accelerated) { | 89 | if (!use_accelerated) { |
| 88 | UpdateRawImage(framebuffer, image_index); | 90 | UpdateRawImage(framebuffer, image_index); |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index d50417116..c553f5b3d 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -144,7 +144,9 @@ void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebu | |||
| 144 | return; | 144 | return; |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | SCOPE_EXIT({ render_window.OnFrameDisplayed(); }); | 147 | SCOPE_EXIT { |
| 148 | render_window.OnFrameDisplayed(); | ||
| 149 | }; | ||
| 148 | 150 | ||
| 149 | RenderAppletCaptureLayer(framebuffers); | 151 | RenderAppletCaptureLayer(framebuffers); |
| 150 | 152 | ||
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index aa0a027bb..74f9f099e 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -196,7 +196,9 @@ template <typename Func> | |||
| 196 | void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) { | 196 | void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) { |
| 197 | MICROPROFILE_SCOPE(Vulkan_Drawing); | 197 | MICROPROFILE_SCOPE(Vulkan_Drawing); |
| 198 | 198 | ||
| 199 | SCOPE_EXIT({ gpu.TickWork(); }); | 199 | SCOPE_EXIT { |
| 200 | gpu.TickWork(); | ||
| 201 | }; | ||
| 200 | FlushWork(); | 202 | FlushWork(); |
| 201 | gpu_memory->FlushCaching(); | 203 | gpu_memory->FlushCaching(); |
| 202 | 204 | ||
| @@ -288,7 +290,9 @@ void RasterizerVulkan::DrawIndirect() { | |||
| 288 | void RasterizerVulkan::DrawTexture() { | 290 | void RasterizerVulkan::DrawTexture() { |
| 289 | MICROPROFILE_SCOPE(Vulkan_Drawing); | 291 | MICROPROFILE_SCOPE(Vulkan_Drawing); |
| 290 | 292 | ||
| 291 | SCOPE_EXIT({ gpu.TickWork(); }); | 293 | SCOPE_EXIT { |
| 294 | gpu.TickWork(); | ||
| 295 | }; | ||
| 292 | FlushWork(); | 296 | FlushWork(); |
| 293 | 297 | ||
| 294 | query_cache.NotifySegment(true); | 298 | query_cache.NotifySegment(true); |
diff --git a/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp index 5fa0d9620..f41c3e506 100644 --- a/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp +++ b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp | |||
| @@ -116,7 +116,9 @@ void NsightAftermathTracker::OnGpuCrashDumpCallback(const void* gpu_crash_dump, | |||
| 116 | LOG_ERROR(Render_Vulkan, "Failed to create decoder"); | 116 | LOG_ERROR(Render_Vulkan, "Failed to create decoder"); |
| 117 | return; | 117 | return; |
| 118 | } | 118 | } |
| 119 | SCOPE_EXIT({ GFSDK_Aftermath_GpuCrashDump_DestroyDecoder(decoder); }); | 119 | SCOPE_EXIT { |
| 120 | GFSDK_Aftermath_GpuCrashDump_DestroyDecoder(decoder); | ||
| 121 | }; | ||
| 120 | 122 | ||
| 121 | u32 json_size = 0; | 123 | u32 json_size = 0; |
| 122 | if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_GenerateJSON( | 124 | if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_GenerateJSON( |
diff --git a/src/yuzu/configuration/qt_config.cpp b/src/yuzu/configuration/qt_config.cpp index 1051031f2..37951b9c8 100644 --- a/src/yuzu/configuration/qt_config.cpp +++ b/src/yuzu/configuration/qt_config.cpp | |||
| @@ -90,6 +90,7 @@ void QtConfig::ReadQtPlayerValues(const std::size_t player_index) { | |||
| 90 | if (profile_name.empty()) { | 90 | if (profile_name.empty()) { |
| 91 | // Use the global input config | 91 | // Use the global input config |
| 92 | player = Settings::values.players.GetValue(true)[player_index]; | 92 | player = Settings::values.players.GetValue(true)[player_index]; |
| 93 | player.profile_name = ""; | ||
| 93 | return; | 94 | return; |
| 94 | } | 95 | } |
| 95 | } | 96 | } |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index dfa50006a..236642fb9 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -646,10 +646,10 @@ void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParamete | |||
| 646 | std::shared_ptr<Service::NFC::NfcDevice> nfp_device) { | 646 | std::shared_ptr<Service::NFC::NfcDevice> nfp_device) { |
| 647 | cabinet_applet = | 647 | cabinet_applet = |
| 648 | new QtAmiiboSettingsDialog(this, parameters, input_subsystem.get(), nfp_device); | 648 | new QtAmiiboSettingsDialog(this, parameters, input_subsystem.get(), nfp_device); |
| 649 | SCOPE_EXIT({ | 649 | SCOPE_EXIT { |
| 650 | cabinet_applet->deleteLater(); | 650 | cabinet_applet->deleteLater(); |
| 651 | cabinet_applet = nullptr; | 651 | cabinet_applet = nullptr; |
| 652 | }); | 652 | }; |
| 653 | 653 | ||
| 654 | cabinet_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | | 654 | cabinet_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | |
| 655 | Qt::WindowTitleHint | Qt::WindowSystemMenuHint); | 655 | Qt::WindowTitleHint | Qt::WindowSystemMenuHint); |
| @@ -673,10 +673,10 @@ void GMainWindow::ControllerSelectorReconfigureControllers( | |||
| 673 | const Core::Frontend::ControllerParameters& parameters) { | 673 | const Core::Frontend::ControllerParameters& parameters) { |
| 674 | controller_applet = | 674 | controller_applet = |
| 675 | new QtControllerSelectorDialog(this, parameters, input_subsystem.get(), *system); | 675 | new QtControllerSelectorDialog(this, parameters, input_subsystem.get(), *system); |
| 676 | SCOPE_EXIT({ | 676 | SCOPE_EXIT { |
| 677 | controller_applet->deleteLater(); | 677 | controller_applet->deleteLater(); |
| 678 | controller_applet = nullptr; | 678 | controller_applet = nullptr; |
| 679 | }); | 679 | }; |
| 680 | 680 | ||
| 681 | controller_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | | 681 | controller_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | |
| 682 | Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | | 682 | Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | |
| @@ -703,10 +703,10 @@ void GMainWindow::ControllerSelectorRequestExit() { | |||
| 703 | void GMainWindow::ProfileSelectorSelectProfile( | 703 | void GMainWindow::ProfileSelectorSelectProfile( |
| 704 | const Core::Frontend::ProfileSelectParameters& parameters) { | 704 | const Core::Frontend::ProfileSelectParameters& parameters) { |
| 705 | profile_select_applet = new QtProfileSelectionDialog(*system, this, parameters); | 705 | profile_select_applet = new QtProfileSelectionDialog(*system, this, parameters); |
| 706 | SCOPE_EXIT({ | 706 | SCOPE_EXIT { |
| 707 | profile_select_applet->deleteLater(); | 707 | profile_select_applet->deleteLater(); |
| 708 | profile_select_applet = nullptr; | 708 | profile_select_applet = nullptr; |
| 709 | }); | 709 | }; |
| 710 | 710 | ||
| 711 | profile_select_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | | 711 | profile_select_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | |
| 712 | Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | | 712 | Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | |
| @@ -1603,6 +1603,7 @@ void GMainWindow::ConnectMenuEvents() { | |||
| 1603 | // Help | 1603 | // Help |
| 1604 | connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder); | 1604 | connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder); |
| 1605 | connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents); | 1605 | connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents); |
| 1606 | connect_menu(ui->action_Install_Firmware, &GMainWindow::OnInstallFirmware); | ||
| 1606 | connect_menu(ui->action_About, &GMainWindow::OnAbout); | 1607 | connect_menu(ui->action_About, &GMainWindow::OnAbout); |
| 1607 | } | 1608 | } |
| 1608 | 1609 | ||
| @@ -1631,6 +1632,8 @@ void GMainWindow::UpdateMenuState() { | |||
| 1631 | action->setEnabled(emulation_running); | 1632 | action->setEnabled(emulation_running); |
| 1632 | } | 1633 | } |
| 1633 | 1634 | ||
| 1635 | ui->action_Install_Firmware->setEnabled(!emulation_running); | ||
| 1636 | |||
| 1634 | for (QAction* action : applet_actions) { | 1637 | for (QAction* action : applet_actions) { |
| 1635 | action->setEnabled(is_firmware_available && !emulation_running); | 1638 | action->setEnabled(is_firmware_available && !emulation_running); |
| 1636 | } | 1639 | } |
| @@ -2882,17 +2885,19 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, | |||
| 2882 | LOG_ERROR(Frontend, "CoInitialize failed"); | 2885 | LOG_ERROR(Frontend, "CoInitialize failed"); |
| 2883 | return false; | 2886 | return false; |
| 2884 | } | 2887 | } |
| 2885 | SCOPE_EXIT({ CoUninitialize(); }); | 2888 | SCOPE_EXIT { |
| 2889 | CoUninitialize(); | ||
| 2890 | }; | ||
| 2886 | IShellLinkW* ps1 = nullptr; | 2891 | IShellLinkW* ps1 = nullptr; |
| 2887 | IPersistFile* persist_file = nullptr; | 2892 | IPersistFile* persist_file = nullptr; |
| 2888 | SCOPE_EXIT({ | 2893 | SCOPE_EXIT { |
| 2889 | if (persist_file != nullptr) { | 2894 | if (persist_file != nullptr) { |
| 2890 | persist_file->Release(); | 2895 | persist_file->Release(); |
| 2891 | } | 2896 | } |
| 2892 | if (ps1 != nullptr) { | 2897 | if (ps1 != nullptr) { |
| 2893 | ps1->Release(); | 2898 | ps1->Release(); |
| 2894 | } | 2899 | } |
| 2895 | }); | 2900 | }; |
| 2896 | HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, | 2901 | HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, |
| 2897 | reinterpret_cast<void**>(&ps1)); | 2902 | reinterpret_cast<void**>(&ps1)); |
| 2898 | if (FAILED(hres)) { | 2903 | if (FAILED(hres)) { |
| @@ -3517,10 +3522,10 @@ void GMainWindow::OnSaveConfig() { | |||
| 3517 | void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { | 3522 | void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { |
| 3518 | error_applet = new OverlayDialog(render_window, *system, error_code, error_text, QString{}, | 3523 | error_applet = new OverlayDialog(render_window, *system, error_code, error_text, QString{}, |
| 3519 | tr("OK"), Qt::AlignLeft | Qt::AlignVCenter); | 3524 | tr("OK"), Qt::AlignLeft | Qt::AlignVCenter); |
| 3520 | SCOPE_EXIT({ | 3525 | SCOPE_EXIT { |
| 3521 | error_applet->deleteLater(); | 3526 | error_applet->deleteLater(); |
| 3522 | error_applet = nullptr; | 3527 | error_applet = nullptr; |
| 3523 | }); | 3528 | }; |
| 3524 | error_applet->exec(); | 3529 | error_applet->exec(); |
| 3525 | 3530 | ||
| 3526 | emit ErrorDisplayFinished(); | 3531 | emit ErrorDisplayFinished(); |
| @@ -4150,6 +4155,146 @@ void GMainWindow::OnVerifyInstalledContents() { | |||
| 4150 | } | 4155 | } |
| 4151 | } | 4156 | } |
| 4152 | 4157 | ||
| 4158 | void GMainWindow::OnInstallFirmware() { | ||
| 4159 | // Don't do this while emulation is running, that'd probably be a bad idea. | ||
| 4160 | if (emu_thread != nullptr && emu_thread->IsRunning()) { | ||
| 4161 | return; | ||
| 4162 | } | ||
| 4163 | |||
| 4164 | // Check for installed keys, error out, suggest restart? | ||
| 4165 | if (!ContentManager::AreKeysPresent()) { | ||
| 4166 | QMessageBox::information( | ||
| 4167 | this, tr("Keys not installed"), | ||
| 4168 | tr("Install decryption keys and restart yuzu before attempting to install firmware.")); | ||
| 4169 | return; | ||
| 4170 | } | ||
| 4171 | |||
| 4172 | QString firmware_source_location = | ||
| 4173 | QFileDialog::getExistingDirectory(this, tr("Select Dumped Firmware Source Location"), | ||
| 4174 | QString::fromStdString(""), QFileDialog::ShowDirsOnly); | ||
| 4175 | if (firmware_source_location.isEmpty()) { | ||
| 4176 | return; | ||
| 4177 | } | ||
| 4178 | |||
| 4179 | QProgressDialog progress(tr("Installing Firmware..."), tr("Cancel"), 0, 100, this); | ||
| 4180 | progress.setWindowModality(Qt::WindowModal); | ||
| 4181 | progress.setMinimumDuration(100); | ||
| 4182 | progress.setAutoClose(false); | ||
| 4183 | progress.setAutoReset(false); | ||
| 4184 | progress.show(); | ||
| 4185 | |||
| 4186 | // Declare progress callback. | ||
| 4187 | auto QtProgressCallback = [&](size_t total_size, size_t processed_size) { | ||
| 4188 | progress.setValue(static_cast<int>((processed_size * 100) / total_size)); | ||
| 4189 | return progress.wasCanceled(); | ||
| 4190 | }; | ||
| 4191 | |||
| 4192 | LOG_INFO(Frontend, "Installing firmware from {}", firmware_source_location.toStdString()); | ||
| 4193 | |||
| 4194 | // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in | ||
| 4195 | // there.) | ||
| 4196 | std::filesystem::path firmware_source_path = firmware_source_location.toStdString(); | ||
| 4197 | if (!Common::FS::IsDir(firmware_source_path)) { | ||
| 4198 | progress.close(); | ||
| 4199 | return; | ||
| 4200 | } | ||
| 4201 | |||
| 4202 | std::vector<std::filesystem::path> out; | ||
| 4203 | const Common::FS::DirEntryCallable callback = | ||
| 4204 | [&out](const std::filesystem::directory_entry& entry) { | ||
| 4205 | if (entry.path().has_extension() && entry.path().extension() == ".nca") | ||
| 4206 | out.emplace_back(entry.path()); | ||
| 4207 | |||
| 4208 | return true; | ||
| 4209 | }; | ||
| 4210 | |||
| 4211 | QtProgressCallback(100, 10); | ||
| 4212 | |||
| 4213 | Common::FS::IterateDirEntries(firmware_source_path, callback, Common::FS::DirEntryFilter::File); | ||
| 4214 | if (out.size() <= 0) { | ||
| 4215 | progress.close(); | ||
| 4216 | QMessageBox::warning(this, tr("Firmware install failed"), | ||
| 4217 | tr("Unable to locate potential firmware NCA files")); | ||
| 4218 | return; | ||
| 4219 | } | ||
| 4220 | |||
| 4221 | // Locate and erase the content of nand/system/Content/registered/*.nca, if any. | ||
| 4222 | auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); | ||
| 4223 | if (!sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { | ||
| 4224 | progress.close(); | ||
| 4225 | QMessageBox::critical(this, tr("Firmware install failed"), | ||
| 4226 | tr("Failed to delete one or more firmware file.")); | ||
| 4227 | return; | ||
| 4228 | } | ||
| 4229 | |||
| 4230 | LOG_INFO(Frontend, | ||
| 4231 | "Cleaned nand/system/Content/registered folder in preparation for new firmware."); | ||
| 4232 | |||
| 4233 | QtProgressCallback(100, 20); | ||
| 4234 | |||
| 4235 | auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); | ||
| 4236 | |||
| 4237 | bool success = true; | ||
| 4238 | bool cancelled = false; | ||
| 4239 | int i = 0; | ||
| 4240 | for (const auto& firmware_src_path : out) { | ||
| 4241 | i++; | ||
| 4242 | auto firmware_src_vfile = | ||
| 4243 | vfs->OpenFile(firmware_src_path.generic_string(), FileSys::OpenMode::Read); | ||
| 4244 | auto firmware_dst_vfile = | ||
| 4245 | firmware_vdir->CreateFileRelative(firmware_src_path.filename().string()); | ||
| 4246 | |||
| 4247 | if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { | ||
| 4248 | LOG_ERROR(Frontend, "Failed to copy firmware file {} to {} in registered folder!", | ||
| 4249 | firmware_src_path.generic_string(), firmware_src_path.filename().string()); | ||
| 4250 | success = false; | ||
| 4251 | } | ||
| 4252 | |||
| 4253 | if (QtProgressCallback(100, 20 + (int)(((float)(i) / (float)out.size()) * 70.0))) { | ||
| 4254 | success = false; | ||
| 4255 | cancelled = true; | ||
| 4256 | break; | ||
| 4257 | } | ||
| 4258 | } | ||
| 4259 | |||
| 4260 | if (!success && !cancelled) { | ||
| 4261 | progress.close(); | ||
| 4262 | QMessageBox::critical(this, tr("Firmware install failed"), | ||
| 4263 | tr("One or more firmware files failed to copy into NAND.")); | ||
| 4264 | return; | ||
| 4265 | } else if (cancelled) { | ||
| 4266 | progress.close(); | ||
| 4267 | QMessageBox::warning(this, tr("Firmware install failed"), | ||
| 4268 | tr("Firmware installation cancelled, firmware may be in bad state, " | ||
| 4269 | "restart yuzu or re-install firmware.")); | ||
| 4270 | return; | ||
| 4271 | } | ||
| 4272 | |||
| 4273 | // Re-scan VFS for the newly placed firmware files. | ||
| 4274 | system->GetFileSystemController().CreateFactories(*vfs); | ||
| 4275 | |||
| 4276 | auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { | ||
| 4277 | progress.setValue(90 + static_cast<int>((processed_size * 10) / total_size)); | ||
| 4278 | return progress.wasCanceled(); | ||
| 4279 | }; | ||
| 4280 | |||
| 4281 | auto result = | ||
| 4282 | ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true); | ||
| 4283 | |||
| 4284 | if (result.size() > 0) { | ||
| 4285 | const auto failed_names = | ||
| 4286 | QString::fromStdString(fmt::format("{}", fmt::join(result, "\n"))); | ||
| 4287 | progress.close(); | ||
| 4288 | QMessageBox::critical( | ||
| 4289 | this, tr("Firmware integrity verification failed!"), | ||
| 4290 | tr("Verification failed for the following files:\n\n%1").arg(failed_names)); | ||
| 4291 | return; | ||
| 4292 | } | ||
| 4293 | |||
| 4294 | progress.close(); | ||
| 4295 | OnCheckFirmwareDecryption(); | ||
| 4296 | } | ||
| 4297 | |||
| 4153 | void GMainWindow::OnAbout() { | 4298 | void GMainWindow::OnAbout() { |
| 4154 | AboutDialog aboutDialog(this); | 4299 | AboutDialog aboutDialog(this); |
| 4155 | aboutDialog.exec(); | 4300 | aboutDialog.exec(); |
| @@ -5049,7 +5194,9 @@ int main(int argc, char* argv[]) { | |||
| 5049 | 5194 | ||
| 5050 | Common::DetachedTasks detached_tasks; | 5195 | Common::DetachedTasks detached_tasks; |
| 5051 | MicroProfileOnThreadCreate("Frontend"); | 5196 | MicroProfileOnThreadCreate("Frontend"); |
| 5052 | SCOPE_EXIT({ MicroProfileShutdown(); }); | 5197 | SCOPE_EXIT { |
| 5198 | MicroProfileShutdown(); | ||
| 5199 | }; | ||
| 5053 | 5200 | ||
| 5054 | Common::ConfigureNvidiaEnvironmentFlags(); | 5201 | Common::ConfigureNvidiaEnvironmentFlags(); |
| 5055 | 5202 | ||
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index aba61e388..1f0e35c67 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -380,6 +380,7 @@ private slots: | |||
| 380 | void OnLoadAmiibo(); | 380 | void OnLoadAmiibo(); |
| 381 | void OnOpenYuzuFolder(); | 381 | void OnOpenYuzuFolder(); |
| 382 | void OnVerifyInstalledContents(); | 382 | void OnVerifyInstalledContents(); |
| 383 | void OnInstallFirmware(); | ||
| 383 | void OnAbout(); | 384 | void OnAbout(); |
| 384 | void OnToggleFilterBar(); | 385 | void OnToggleFilterBar(); |
| 385 | void OnToggleStatusBar(); | 386 | void OnToggleStatusBar(); |
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index 6a6b0821f..6ff444a22 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui | |||
| @@ -25,7 +25,16 @@ | |||
| 25 | </property> | 25 | </property> |
| 26 | <widget class="QWidget" name="centralwidget"> | 26 | <widget class="QWidget" name="centralwidget"> |
| 27 | <layout class="QHBoxLayout" name="horizontalLayout"> | 27 | <layout class="QHBoxLayout" name="horizontalLayout"> |
| 28 | <property name="margin" stdset="0"> | 28 | <property name="leftMargin"> |
| 29 | <number>0</number> | ||
| 30 | </property> | ||
| 31 | <property name="topMargin"> | ||
| 32 | <number>0</number> | ||
| 33 | </property> | ||
| 34 | <property name="rightMargin"> | ||
| 35 | <number>0</number> | ||
| 36 | </property> | ||
| 37 | <property name="bottomMargin"> | ||
| 29 | <number>0</number> | 38 | <number>0</number> |
| 30 | </property> | 39 | </property> |
| 31 | </layout> | 40 | </layout> |
| @@ -156,8 +165,8 @@ | |||
| 156 | <addaction name="separator"/> | 165 | <addaction name="separator"/> |
| 157 | <addaction name="action_Configure_Tas"/> | 166 | <addaction name="action_Configure_Tas"/> |
| 158 | </widget> | 167 | </widget> |
| 159 | <addaction name="action_Rederive"/> | ||
| 160 | <addaction name="action_Verify_installed_contents"/> | 168 | <addaction name="action_Verify_installed_contents"/> |
| 169 | <addaction name="action_Install_Firmware"/> | ||
| 161 | <addaction name="separator"/> | 170 | <addaction name="separator"/> |
| 162 | <addaction name="menu_cabinet_applet"/> | 171 | <addaction name="menu_cabinet_applet"/> |
| 163 | <addaction name="action_Load_Album"/> | 172 | <addaction name="action_Load_Album"/> |
| @@ -455,6 +464,11 @@ | |||
| 455 | <string>Open &Controller Menu</string> | 464 | <string>Open &Controller Menu</string> |
| 456 | </property> | 465 | </property> |
| 457 | </action> | 466 | </action> |
| 467 | <action name="action_Install_Firmware"> | ||
| 468 | <property name="text"> | ||
| 469 | <string>Install Firmware</string> | ||
| 470 | </property> | ||
| 471 | </action> | ||
| 458 | </widget> | 472 | </widget> |
| 459 | <resources> | 473 | <resources> |
| 460 | <include location="yuzu.qrc"/> | 474 | <include location="yuzu.qrc"/> |
diff --git a/src/yuzu_cmd/sdl_config.cpp b/src/yuzu_cmd/sdl_config.cpp index 995114510..6e0f254b6 100644 --- a/src/yuzu_cmd/sdl_config.cpp +++ b/src/yuzu_cmd/sdl_config.cpp | |||
| @@ -103,6 +103,7 @@ void SdlConfig::ReadSdlPlayerValues(const std::size_t player_index) { | |||
| 103 | if (profile_name.empty()) { | 103 | if (profile_name.empty()) { |
| 104 | // Use the global input config | 104 | // Use the global input config |
| 105 | player = Settings::values.players.GetValue(true)[player_index]; | 105 | player = Settings::values.players.GetValue(true)[player_index]; |
| 106 | player.profile_name = ""; | ||
| 106 | return; | 107 | return; |
| 107 | } | 108 | } |
| 108 | } | 109 | } |
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 3b321dad1..8a8cdbc44 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -327,7 +327,9 @@ int main(int argc, char** argv) { | |||
| 327 | #endif | 327 | #endif |
| 328 | 328 | ||
| 329 | MicroProfileOnThreadCreate("EmuThread"); | 329 | MicroProfileOnThreadCreate("EmuThread"); |
| 330 | SCOPE_EXIT({ MicroProfileShutdown(); }); | 330 | SCOPE_EXIT { |
| 331 | MicroProfileShutdown(); | ||
| 332 | }; | ||
| 331 | 333 | ||
| 332 | Common::ConfigureNvidiaEnvironmentFlags(); | 334 | Common::ConfigureNvidiaEnvironmentFlags(); |
| 333 | 335 | ||