diff options
Diffstat (limited to 'src')
266 files changed, 4819 insertions, 2810 deletions
diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index bab4f4d0f..9a47e2bd8 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts | |||
| @@ -26,7 +26,7 @@ val autoVersion = (((System.currentTimeMillis() / 1000) - 1451606400) / 10).toIn | |||
| 26 | android { | 26 | android { |
| 27 | namespace = "org.yuzu.yuzu_emu" | 27 | namespace = "org.yuzu.yuzu_emu" |
| 28 | 28 | ||
| 29 | compileSdkVersion = "android-33" | 29 | compileSdkVersion = "android-34" |
| 30 | ndkVersion = "25.2.9519653" | 30 | ndkVersion = "25.2.9519653" |
| 31 | 31 | ||
| 32 | buildFeatures { | 32 | buildFeatures { |
| @@ -51,7 +51,7 @@ android { | |||
| 51 | // TODO If this is ever modified, change application_id in strings.xml | 51 | // TODO If this is ever modified, change application_id in strings.xml |
| 52 | applicationId = "org.yuzu.yuzu_emu" | 52 | applicationId = "org.yuzu.yuzu_emu" |
| 53 | minSdk = 30 | 53 | minSdk = 30 |
| 54 | targetSdk = 33 | 54 | targetSdk = 34 |
| 55 | versionName = getGitVersion() | 55 | versionName = getGitVersion() |
| 56 | 56 | ||
| 57 | // If you want to use autoVersion for the versionCode, create a property in local.properties | 57 | // If you want to use autoVersion for the versionCode, create a property in local.properties |
diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml index e31ad69e2..51d949d65 100644 --- a/src/android/app/src/main/AndroidManifest.xml +++ b/src/android/app/src/main/AndroidManifest.xml | |||
| @@ -13,6 +13,7 @@ SPDX-License-Identifier: GPL-3.0-or-later | |||
| 13 | 13 | ||
| 14 | <uses-permission android:name="android.permission.INTERNET" /> | 14 | <uses-permission android:name="android.permission.INTERNET" /> |
| 15 | <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> | 15 | <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> |
| 16 | <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" /> | ||
| 16 | <uses-permission android:name="android.permission.NFC" /> | 17 | <uses-permission android:name="android.permission.NFC" /> |
| 17 | <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> | 18 | <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> |
| 18 | 19 | ||
| @@ -69,7 +70,9 @@ SPDX-License-Identifier: GPL-3.0-or-later | |||
| 69 | android:resource="@xml/nfc_tech_filter" /> | 70 | android:resource="@xml/nfc_tech_filter" /> |
| 70 | </activity> | 71 | </activity> |
| 71 | 72 | ||
| 72 | <service android:name="org.yuzu.yuzu_emu.utils.ForegroundService"/> | 73 | <service android:name="org.yuzu.yuzu_emu.utils.ForegroundService" android:foregroundServiceType="specialUse"> |
| 74 | <property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE" android:value="Keep emulation running in background"/> | ||
| 75 | </service> | ||
| 73 | 76 | ||
| 74 | <provider | 77 | <provider |
| 75 | android:name=".features.DocumentProvider" | 78 | android:name=".features.DocumentProvider" |
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 f860cdd4b..9c32e044c 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 | |||
| @@ -286,7 +286,7 @@ object NativeLibrary { | |||
| 286 | /** | 286 | /** |
| 287 | * Unpauses emulation from a paused state. | 287 | * Unpauses emulation from a paused state. |
| 288 | */ | 288 | */ |
| 289 | external fun unPauseEmulation() | 289 | external fun unpauseEmulation() |
| 290 | 290 | ||
| 291 | /** | 291 | /** |
| 292 | * Pauses emulation. | 292 | * Pauses emulation. |
| @@ -314,6 +314,21 @@ object NativeLibrary { | |||
| 314 | external fun isPaused(): Boolean | 314 | external fun isPaused(): Boolean |
| 315 | 315 | ||
| 316 | /** | 316 | /** |
| 317 | * Mutes emulation sound | ||
| 318 | */ | ||
| 319 | external fun muteAudio(): Boolean | ||
| 320 | |||
| 321 | /** | ||
| 322 | * Unmutes emulation sound | ||
| 323 | */ | ||
| 324 | external fun unmuteAudio(): Boolean | ||
| 325 | |||
| 326 | /** | ||
| 327 | * Returns true if emulation audio is muted. | ||
| 328 | */ | ||
| 329 | external fun isMuted(): Boolean | ||
| 330 | |||
| 331 | /** | ||
| 317 | * Returns the performance stats for the current game | 332 | * Returns the performance stats for the current game |
| 318 | */ | 333 | */ |
| 319 | external fun getPerfStats(): DoubleArray | 334 | external fun getPerfStats(): DoubleArray |
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 f0a6753a9..ae665ed2e 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 | |||
| @@ -27,13 +27,13 @@ import android.view.MotionEvent | |||
| 27 | import android.view.Surface | 27 | import android.view.Surface |
| 28 | import android.view.View | 28 | import android.view.View |
| 29 | import android.view.inputmethod.InputMethodManager | 29 | import android.view.inputmethod.InputMethodManager |
| 30 | import android.widget.Toast | ||
| 30 | import androidx.activity.viewModels | 31 | import androidx.activity.viewModels |
| 31 | import androidx.appcompat.app.AppCompatActivity | 32 | import androidx.appcompat.app.AppCompatActivity |
| 32 | import androidx.core.view.WindowCompat | 33 | import androidx.core.view.WindowCompat |
| 33 | import androidx.core.view.WindowInsetsCompat | 34 | import androidx.core.view.WindowInsetsCompat |
| 34 | import androidx.core.view.WindowInsetsControllerCompat | 35 | import androidx.core.view.WindowInsetsControllerCompat |
| 35 | import androidx.navigation.fragment.NavHostFragment | 36 | import androidx.navigation.fragment.NavHostFragment |
| 36 | import kotlin.math.roundToInt | ||
| 37 | import org.yuzu.yuzu_emu.NativeLibrary | 37 | import org.yuzu.yuzu_emu.NativeLibrary |
| 38 | import org.yuzu.yuzu_emu.R | 38 | import org.yuzu.yuzu_emu.R |
| 39 | import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding | 39 | import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding |
| @@ -44,8 +44,10 @@ import org.yuzu.yuzu_emu.model.Game | |||
| 44 | import org.yuzu.yuzu_emu.utils.ControllerMappingHelper | 44 | import org.yuzu.yuzu_emu.utils.ControllerMappingHelper |
| 45 | import org.yuzu.yuzu_emu.utils.ForegroundService | 45 | import org.yuzu.yuzu_emu.utils.ForegroundService |
| 46 | import org.yuzu.yuzu_emu.utils.InputHandler | 46 | import org.yuzu.yuzu_emu.utils.InputHandler |
| 47 | import org.yuzu.yuzu_emu.utils.MemoryUtil | ||
| 47 | import org.yuzu.yuzu_emu.utils.NfcReader | 48 | import org.yuzu.yuzu_emu.utils.NfcReader |
| 48 | import org.yuzu.yuzu_emu.utils.ThemeHelper | 49 | import org.yuzu.yuzu_emu.utils.ThemeHelper |
| 50 | import kotlin.math.roundToInt | ||
| 49 | 51 | ||
| 50 | class EmulationActivity : AppCompatActivity(), SensorEventListener { | 52 | class EmulationActivity : AppCompatActivity(), SensorEventListener { |
| 51 | private lateinit var binding: ActivityEmulationBinding | 53 | private lateinit var binding: ActivityEmulationBinding |
| @@ -63,6 +65,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 63 | 65 | ||
| 64 | private val actionPause = "ACTION_EMULATOR_PAUSE" | 66 | private val actionPause = "ACTION_EMULATOR_PAUSE" |
| 65 | private val actionPlay = "ACTION_EMULATOR_PLAY" | 67 | private val actionPlay = "ACTION_EMULATOR_PLAY" |
| 68 | private val actionMute = "ACTION_EMULATOR_MUTE" | ||
| 69 | private val actionUnmute = "ACTION_EMULATOR_UNMUTE" | ||
| 66 | 70 | ||
| 67 | private val settingsViewModel: SettingsViewModel by viewModels() | 71 | private val settingsViewModel: SettingsViewModel by viewModels() |
| 68 | 72 | ||
| @@ -102,6 +106,19 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 102 | inputHandler = InputHandler() | 106 | inputHandler = InputHandler() |
| 103 | inputHandler.initialize() | 107 | inputHandler.initialize() |
| 104 | 108 | ||
| 109 | val memoryUtil = MemoryUtil(this) | ||
| 110 | if (memoryUtil.isLessThan(8, MemoryUtil.Gb)) { | ||
| 111 | Toast.makeText( | ||
| 112 | this, | ||
| 113 | getString( | ||
| 114 | R.string.device_memory_inadequate, | ||
| 115 | memoryUtil.getDeviceRAM(), | ||
| 116 | "8 ${getString(R.string.memory_gigabyte)}" | ||
| 117 | ), | ||
| 118 | Toast.LENGTH_LONG | ||
| 119 | ).show() | ||
| 120 | } | ||
| 121 | |||
| 105 | // Start a foreground service to prevent the app from getting killed in the background | 122 | // Start a foreground service to prevent the app from getting killed in the background |
| 106 | val startIntent = Intent(this, ForegroundService::class.java) | 123 | val startIntent = Intent(this, ForegroundService::class.java) |
| 107 | startForegroundService(startIntent) | 124 | startForegroundService(startIntent) |
| @@ -305,6 +322,41 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 305 | pictureInPictureActions.add(pauseRemoteAction) | 322 | pictureInPictureActions.add(pauseRemoteAction) |
| 306 | } | 323 | } |
| 307 | 324 | ||
| 325 | if (NativeLibrary.isMuted()) { | ||
| 326 | val unmuteIcon = Icon.createWithResource( | ||
| 327 | this@EmulationActivity, | ||
| 328 | R.drawable.ic_pip_unmute | ||
| 329 | ) | ||
| 330 | val unmutePendingIntent = PendingIntent.getBroadcast( | ||
| 331 | this@EmulationActivity, | ||
| 332 | R.drawable.ic_pip_unmute, | ||
| 333 | Intent(actionUnmute), | ||
| 334 | pendingFlags | ||
| 335 | ) | ||
| 336 | val unmuteRemoteAction = RemoteAction( | ||
| 337 | unmuteIcon, | ||
| 338 | getString(R.string.unmute), | ||
| 339 | getString(R.string.unmute), | ||
| 340 | unmutePendingIntent | ||
| 341 | ) | ||
| 342 | pictureInPictureActions.add(unmuteRemoteAction) | ||
| 343 | } else { | ||
| 344 | val muteIcon = Icon.createWithResource(this@EmulationActivity, R.drawable.ic_pip_mute) | ||
| 345 | val mutePendingIntent = PendingIntent.getBroadcast( | ||
| 346 | this@EmulationActivity, | ||
| 347 | R.drawable.ic_pip_mute, | ||
| 348 | Intent(actionMute), | ||
| 349 | pendingFlags | ||
| 350 | ) | ||
| 351 | val muteRemoteAction = RemoteAction( | ||
| 352 | muteIcon, | ||
| 353 | getString(R.string.mute), | ||
| 354 | getString(R.string.mute), | ||
| 355 | mutePendingIntent | ||
| 356 | ) | ||
| 357 | pictureInPictureActions.add(muteRemoteAction) | ||
| 358 | } | ||
| 359 | |||
| 308 | return this.apply { setActions(pictureInPictureActions) } | 360 | return this.apply { setActions(pictureInPictureActions) } |
| 309 | } | 361 | } |
| 310 | 362 | ||
| @@ -322,10 +374,15 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 322 | private var pictureInPictureReceiver = object : BroadcastReceiver() { | 374 | private var pictureInPictureReceiver = object : BroadcastReceiver() { |
| 323 | override fun onReceive(context: Context?, intent: Intent) { | 375 | override fun onReceive(context: Context?, intent: Intent) { |
| 324 | if (intent.action == actionPlay) { | 376 | if (intent.action == actionPlay) { |
| 325 | if (NativeLibrary.isPaused()) NativeLibrary.unPauseEmulation() | 377 | if (NativeLibrary.isPaused()) NativeLibrary.unpauseEmulation() |
| 326 | } else if (intent.action == actionPause) { | 378 | } else if (intent.action == actionPause) { |
| 327 | if (!NativeLibrary.isPaused()) NativeLibrary.pauseEmulation() | 379 | if (!NativeLibrary.isPaused()) NativeLibrary.pauseEmulation() |
| 328 | } | 380 | } |
| 381 | if (intent.action == actionUnmute) { | ||
| 382 | if (NativeLibrary.isMuted()) NativeLibrary.unmuteAudio() | ||
| 383 | } else if (intent.action == actionMute) { | ||
| 384 | if (!NativeLibrary.isMuted()) NativeLibrary.muteAudio() | ||
| 385 | } | ||
| 329 | buildPictureInPictureParams() | 386 | buildPictureInPictureParams() |
| 330 | } | 387 | } |
| 331 | } | 388 | } |
| @@ -339,6 +396,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 339 | IntentFilter().apply { | 396 | IntentFilter().apply { |
| 340 | addAction(actionPause) | 397 | addAction(actionPause) |
| 341 | addAction(actionPlay) | 398 | addAction(actionPlay) |
| 399 | addAction(actionMute) | ||
| 400 | addAction(actionUnmute) | ||
| 342 | }.also { | 401 | }.also { |
| 343 | registerReceiver(pictureInPictureReceiver, it) | 402 | registerReceiver(pictureInPictureReceiver, it) |
| 344 | } | 403 | } |
| @@ -347,6 +406,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 347 | unregisterReceiver(pictureInPictureReceiver) | 406 | unregisterReceiver(pictureInPictureReceiver) |
| 348 | } catch (ignored: Exception) { | 407 | } catch (ignored: Exception) { |
| 349 | } | 408 | } |
| 409 | // Always resume audio, since there is no UI button | ||
| 410 | if (NativeLibrary.isMuted()) NativeLibrary.unmuteAudio() | ||
| 350 | } | 411 | } |
| 351 | } | 412 | } |
| 352 | 413 | ||
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 4643418c1..09976db62 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 | |||
| @@ -714,7 +714,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 714 | State.PAUSED -> { | 714 | State.PAUSED -> { |
| 715 | Log.debug("[EmulationFragment] Resuming emulation.") | 715 | Log.debug("[EmulationFragment] Resuming emulation.") |
| 716 | NativeLibrary.surfaceChanged(surface) | 716 | NativeLibrary.surfaceChanged(surface) |
| 717 | NativeLibrary.unPauseEmulation() | 717 | NativeLibrary.unpauseEmulation() |
| 718 | } | 718 | } |
| 719 | 719 | ||
| 720 | else -> Log.debug("[EmulationFragment] Bug, run called while already running.") | 720 | else -> Log.debug("[EmulationFragment] Bug, run called while already running.") |
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 6f8adbba5..5a36ffad4 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 | |||
| @@ -68,79 +68,109 @@ class HomeSettingsFragment : Fragment() { | |||
| 68 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | 68 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| 69 | mainActivity = requireActivity() as MainActivity | 69 | mainActivity = requireActivity() as MainActivity |
| 70 | 70 | ||
| 71 | val optionsList: MutableList<HomeSetting> = mutableListOf( | 71 | val optionsList: MutableList<HomeSetting> = mutableListOf<HomeSetting>().apply { |
| 72 | HomeSetting( | 72 | add( |
| 73 | R.string.advanced_settings, | 73 | HomeSetting( |
| 74 | R.string.settings_description, | 74 | R.string.advanced_settings, |
| 75 | R.drawable.ic_settings | 75 | R.string.settings_description, |
| 76 | ) { SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") }, | 76 | R.drawable.ic_settings |
| 77 | HomeSetting( | 77 | ) { SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") } |
| 78 | R.string.open_user_folder, | 78 | ) |
| 79 | R.string.open_user_folder_description, | 79 | add( |
| 80 | R.drawable.ic_folder_open | 80 | HomeSetting( |
| 81 | ) { openFileManager() }, | 81 | R.string.open_user_folder, |
| 82 | HomeSetting( | 82 | R.string.open_user_folder_description, |
| 83 | R.string.preferences_theme, | 83 | R.drawable.ic_folder_open |
| 84 | R.string.theme_and_color_description, | 84 | ) { openFileManager() } |
| 85 | R.drawable.ic_palette | 85 | ) |
| 86 | ) { SettingsActivity.launch(requireContext(), Settings.SECTION_THEME, "") }, | 86 | add( |
| 87 | HomeSetting( | 87 | HomeSetting( |
| 88 | R.string.install_gpu_driver, | 88 | R.string.preferences_theme, |
| 89 | R.string.install_gpu_driver_description, | 89 | R.string.theme_and_color_description, |
| 90 | R.drawable.ic_exit | 90 | R.drawable.ic_palette |
| 91 | ) { driverInstaller() }, | 91 | ) { SettingsActivity.launch(requireContext(), Settings.SECTION_THEME, "") } |
| 92 | HomeSetting( | 92 | ) |
| 93 | R.string.install_amiibo_keys, | 93 | |
| 94 | R.string.install_amiibo_keys_description, | 94 | if (GpuDriverHelper.supportsCustomDriverLoading()) { |
| 95 | R.drawable.ic_nfc | 95 | add( |
| 96 | ) { mainActivity.getAmiiboKey.launch(arrayOf("*/*")) }, | 96 | HomeSetting( |
| 97 | HomeSetting( | 97 | R.string.install_gpu_driver, |
| 98 | R.string.install_game_content, | 98 | R.string.install_gpu_driver_description, |
| 99 | R.string.install_game_content_description, | 99 | R.drawable.ic_exit |
| 100 | R.drawable.ic_system_update_alt | 100 | ) { driverInstaller() } |
| 101 | ) { mainActivity.installGameUpdate.launch(arrayOf("*/*")) }, | ||
| 102 | HomeSetting( | ||
| 103 | R.string.select_games_folder, | ||
| 104 | R.string.select_games_folder_description, | ||
| 105 | R.drawable.ic_add | ||
| 106 | ) { | ||
| 107 | mainActivity.getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data) | ||
| 108 | }, | ||
| 109 | HomeSetting( | ||
| 110 | R.string.manage_save_data, | ||
| 111 | R.string.import_export_saves_description, | ||
| 112 | R.drawable.ic_save | ||
| 113 | ) { | ||
| 114 | ImportExportSavesFragment().show( | ||
| 115 | parentFragmentManager, | ||
| 116 | ImportExportSavesFragment.TAG | ||
| 117 | ) | 101 | ) |
| 118 | }, | ||
| 119 | HomeSetting( | ||
| 120 | R.string.install_prod_keys, | ||
| 121 | R.string.install_prod_keys_description, | ||
| 122 | R.drawable.ic_unlock | ||
| 123 | ) { mainActivity.getProdKey.launch(arrayOf("*/*")) }, | ||
| 124 | HomeSetting( | ||
| 125 | R.string.install_firmware, | ||
| 126 | R.string.install_firmware_description, | ||
| 127 | R.drawable.ic_firmware | ||
| 128 | ) { mainActivity.getFirmware.launch(arrayOf("application/zip")) }, | ||
| 129 | HomeSetting( | ||
| 130 | R.string.share_log, | ||
| 131 | R.string.share_log_description, | ||
| 132 | R.drawable.ic_log | ||
| 133 | ) { shareLog() }, | ||
| 134 | HomeSetting( | ||
| 135 | R.string.about, | ||
| 136 | R.string.about_description, | ||
| 137 | R.drawable.ic_info_outline | ||
| 138 | ) { | ||
| 139 | exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) | ||
| 140 | parentFragmentManager.primaryNavigationFragment?.findNavController() | ||
| 141 | ?.navigate(R.id.action_homeSettingsFragment_to_aboutFragment) | ||
| 142 | } | 102 | } |
| 143 | ) | 103 | |
| 104 | add( | ||
| 105 | HomeSetting( | ||
| 106 | R.string.install_amiibo_keys, | ||
| 107 | R.string.install_amiibo_keys_description, | ||
| 108 | R.drawable.ic_nfc | ||
| 109 | ) { mainActivity.getAmiiboKey.launch(arrayOf("*/*")) } | ||
| 110 | ) | ||
| 111 | add( | ||
| 112 | HomeSetting( | ||
| 113 | R.string.install_game_content, | ||
| 114 | R.string.install_game_content_description, | ||
| 115 | R.drawable.ic_system_update_alt | ||
| 116 | ) { mainActivity.installGameUpdate.launch(arrayOf("*/*")) } | ||
| 117 | ) | ||
| 118 | add( | ||
| 119 | HomeSetting( | ||
| 120 | R.string.select_games_folder, | ||
| 121 | R.string.select_games_folder_description, | ||
| 122 | R.drawable.ic_add | ||
| 123 | ) { | ||
| 124 | mainActivity.getGamesDirectory.launch( | ||
| 125 | Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data | ||
| 126 | ) | ||
| 127 | } | ||
| 128 | ) | ||
| 129 | add( | ||
| 130 | HomeSetting( | ||
| 131 | R.string.manage_save_data, | ||
| 132 | R.string.import_export_saves_description, | ||
| 133 | R.drawable.ic_save | ||
| 134 | ) { | ||
| 135 | ImportExportSavesFragment().show( | ||
| 136 | parentFragmentManager, | ||
| 137 | ImportExportSavesFragment.TAG | ||
| 138 | ) | ||
| 139 | } | ||
| 140 | ) | ||
| 141 | add( | ||
| 142 | HomeSetting( | ||
| 143 | R.string.install_prod_keys, | ||
| 144 | R.string.install_prod_keys_description, | ||
| 145 | R.drawable.ic_unlock | ||
| 146 | ) { mainActivity.getProdKey.launch(arrayOf("*/*")) } | ||
| 147 | ) | ||
| 148 | add( | ||
| 149 | HomeSetting( | ||
| 150 | R.string.install_firmware, | ||
| 151 | R.string.install_firmware_description, | ||
| 152 | R.drawable.ic_firmware | ||
| 153 | ) { mainActivity.getFirmware.launch(arrayOf("application/zip")) } | ||
| 154 | ) | ||
| 155 | add( | ||
| 156 | HomeSetting( | ||
| 157 | R.string.share_log, | ||
| 158 | R.string.share_log_description, | ||
| 159 | R.drawable.ic_log | ||
| 160 | ) { shareLog() } | ||
| 161 | ) | ||
| 162 | add( | ||
| 163 | HomeSetting( | ||
| 164 | R.string.about, | ||
| 165 | R.string.about_description, | ||
| 166 | R.drawable.ic_info_outline | ||
| 167 | ) { | ||
| 168 | exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) | ||
| 169 | parentFragmentManager.primaryNavigationFragment?.findNavController() | ||
| 170 | ?.navigate(R.id.action_homeSettingsFragment_to_aboutFragment) | ||
| 171 | } | ||
| 172 | ) | ||
| 173 | } | ||
| 144 | 174 | ||
| 145 | if (!BuildConfig.PREMIUM) { | 175 | if (!BuildConfig.PREMIUM) { |
| 146 | optionsList.add( | 176 | optionsList.add( |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LongMessageDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LongMessageDialogFragment.kt new file mode 100644 index 000000000..b29b627e9 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LongMessageDialogFragment.kt | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 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.Intent | ||
| 8 | import android.net.Uri | ||
| 9 | import android.os.Bundle | ||
| 10 | import androidx.fragment.app.DialogFragment | ||
| 11 | import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||
| 12 | import org.yuzu.yuzu_emu.R | ||
| 13 | |||
| 14 | class LongMessageDialogFragment : DialogFragment() { | ||
| 15 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { | ||
| 16 | val titleId = requireArguments().getInt(TITLE) | ||
| 17 | val description = requireArguments().getString(DESCRIPTION) | ||
| 18 | val helpLinkId = requireArguments().getInt(HELP_LINK) | ||
| 19 | |||
| 20 | val dialog = MaterialAlertDialogBuilder(requireContext()) | ||
| 21 | .setPositiveButton(R.string.close, null) | ||
| 22 | .setTitle(titleId) | ||
| 23 | .setMessage(description) | ||
| 24 | |||
| 25 | if (helpLinkId != 0) { | ||
| 26 | dialog.setNeutralButton(R.string.learn_more) { _, _ -> | ||
| 27 | openLink(getString(helpLinkId)) | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | return dialog.show() | ||
| 32 | } | ||
| 33 | |||
| 34 | private fun openLink(link: String) { | ||
| 35 | val intent = Intent(Intent.ACTION_VIEW, Uri.parse(link)) | ||
| 36 | startActivity(intent) | ||
| 37 | } | ||
| 38 | |||
| 39 | companion object { | ||
| 40 | const val TAG = "LongMessageDialogFragment" | ||
| 41 | |||
| 42 | private const val TITLE = "Title" | ||
| 43 | private const val DESCRIPTION = "Description" | ||
| 44 | private const val HELP_LINK = "Link" | ||
| 45 | |||
| 46 | fun newInstance( | ||
| 47 | titleId: Int, | ||
| 48 | description: String, | ||
| 49 | helpLinkId: Int = 0 | ||
| 50 | ): LongMessageDialogFragment { | ||
| 51 | val dialog = LongMessageDialogFragment() | ||
| 52 | val bundle = Bundle() | ||
| 53 | bundle.apply { | ||
| 54 | putInt(TITLE, titleId) | ||
| 55 | putString(DESCRIPTION, description) | ||
| 56 | putInt(HELP_LINK, helpLinkId) | ||
| 57 | } | ||
| 58 | dialog.arguments = bundle | ||
| 59 | return dialog | ||
| 60 | } | ||
| 61 | } | ||
| 62 | } | ||
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 dd6c895fd..f54dccc69 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 | |||
| @@ -29,7 +29,6 @@ import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager | |||
| 29 | import org.yuzu.yuzu_emu.model.Game | 29 | import org.yuzu.yuzu_emu.model.Game |
| 30 | import org.yuzu.yuzu_emu.model.GamesViewModel | 30 | import org.yuzu.yuzu_emu.model.GamesViewModel |
| 31 | import org.yuzu.yuzu_emu.model.HomeViewModel | 31 | import org.yuzu.yuzu_emu.model.HomeViewModel |
| 32 | import org.yuzu.yuzu_emu.utils.FileUtil | ||
| 33 | 32 | ||
| 34 | class SearchFragment : Fragment() { | 33 | class SearchFragment : Fragment() { |
| 35 | private var _binding: FragmentSearchBinding? = null | 34 | private var _binding: FragmentSearchBinding? = null |
| @@ -128,10 +127,7 @@ class SearchFragment : Fragment() { | |||
| 128 | 127 | ||
| 129 | R.id.chip_homebrew -> baseList.filter { it.isHomebrew } | 128 | R.id.chip_homebrew -> baseList.filter { it.isHomebrew } |
| 130 | 129 | ||
| 131 | R.id.chip_retail -> baseList.filter { | 130 | R.id.chip_retail -> baseList.filter { !it.isHomebrew } |
| 132 | FileUtil.hasExtension(it.path, "xci") || | ||
| 133 | FileUtil.hasExtension(it.path, "nsp") | ||
| 134 | } | ||
| 135 | 131 | ||
| 136 | else -> baseList | 132 | else -> baseList |
| 137 | } | 133 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt index 6a048e39f..6527c64ab 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt | |||
| @@ -43,7 +43,7 @@ class Game( | |||
| 43 | 43 | ||
| 44 | companion object { | 44 | companion object { |
| 45 | val extensions: Set<String> = HashSet( | 45 | val extensions: Set<String> = HashSet( |
| 46 | listOf(".xci", ".nsp", ".nca", ".nro") | 46 | listOf("xci", "nsp", "nca", "nro") |
| 47 | ) | 47 | ) |
| 48 | } | 48 | } |
| 49 | } | 49 | } |
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 cc1d87f1b..f7d7aed1e 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 | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | package org.yuzu.yuzu_emu.ui.main | 4 | package org.yuzu.yuzu_emu.ui.main |
| 5 | 5 | ||
| 6 | import android.content.Intent | 6 | import android.content.Intent |
| 7 | import android.net.Uri | ||
| 7 | import android.os.Bundle | 8 | import android.os.Bundle |
| 8 | import android.view.View | 9 | import android.view.View |
| 9 | import android.view.ViewGroup.MarginLayoutParams | 10 | import android.view.ViewGroup.MarginLayoutParams |
| @@ -42,6 +43,7 @@ import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel | |||
| 42 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity | 43 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity |
| 43 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile | 44 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile |
| 44 | import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment | 45 | import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment |
| 46 | import org.yuzu.yuzu_emu.fragments.LongMessageDialogFragment | ||
| 45 | import org.yuzu.yuzu_emu.fragments.MessageDialogFragment | 47 | import org.yuzu.yuzu_emu.fragments.MessageDialogFragment |
| 46 | import org.yuzu.yuzu_emu.model.GamesViewModel | 48 | import org.yuzu.yuzu_emu.model.GamesViewModel |
| 47 | import org.yuzu.yuzu_emu.model.HomeViewModel | 49 | import org.yuzu.yuzu_emu.model.HomeViewModel |
| @@ -294,7 +296,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 294 | return@registerForActivityResult | 296 | return@registerForActivityResult |
| 295 | } | 297 | } |
| 296 | 298 | ||
| 297 | if (!FileUtil.hasExtension(result, "keys")) { | 299 | if (FileUtil.getExtension(result) != "keys") { |
| 298 | MessageDialogFragment.newInstance( | 300 | MessageDialogFragment.newInstance( |
| 299 | R.string.reading_keys_failure, | 301 | R.string.reading_keys_failure, |
| 300 | R.string.install_prod_keys_failure_extension_description | 302 | R.string.install_prod_keys_failure_extension_description |
| @@ -391,7 +393,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 391 | return@registerForActivityResult | 393 | return@registerForActivityResult |
| 392 | } | 394 | } |
| 393 | 395 | ||
| 394 | if (!FileUtil.hasExtension(result, "bin")) { | 396 | if (FileUtil.getExtension(result) != "bin") { |
| 395 | MessageDialogFragment.newInstance( | 397 | MessageDialogFragment.newInstance( |
| 396 | R.string.reading_keys_failure, | 398 | R.string.reading_keys_failure, |
| 397 | R.string.install_amiibo_keys_failure_extension_description | 399 | R.string.install_amiibo_keys_failure_extension_description |
| @@ -481,62 +483,110 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 481 | } | 483 | } |
| 482 | } | 484 | } |
| 483 | 485 | ||
| 484 | val installGameUpdate = | 486 | val installGameUpdate = registerForActivityResult( |
| 485 | registerForActivityResult(ActivityResultContracts.OpenDocument()) { | 487 | ActivityResultContracts.OpenMultipleDocuments() |
| 486 | if (it == null) { | 488 | ) { documents: List<Uri> -> |
| 487 | return@registerForActivityResult | 489 | if (documents.isNotEmpty()) { |
| 488 | } | ||
| 489 | |||
| 490 | IndeterminateProgressDialogFragment.newInstance( | 490 | IndeterminateProgressDialogFragment.newInstance( |
| 491 | this@MainActivity, | 491 | this@MainActivity, |
| 492 | R.string.install_game_content | 492 | R.string.install_game_content |
| 493 | ) { | 493 | ) { |
| 494 | val result = NativeLibrary.installFileToNand(it.toString()) | 494 | var installSuccess = 0 |
| 495 | var installOverwrite = 0 | ||
| 496 | var errorBaseGame = 0 | ||
| 497 | var errorExtension = 0 | ||
| 498 | var errorOther = 0 | ||
| 499 | var errorTotal = 0 | ||
| 495 | lifecycleScope.launch { | 500 | lifecycleScope.launch { |
| 496 | withContext(Dispatchers.Main) { | 501 | documents.forEach { |
| 497 | when (result) { | 502 | when (NativeLibrary.installFileToNand(it.toString())) { |
| 498 | NativeLibrary.InstallFileToNandResult.Success -> { | 503 | NativeLibrary.InstallFileToNandResult.Success -> { |
| 499 | Toast.makeText( | 504 | installSuccess += 1 |
| 500 | applicationContext, | ||
| 501 | R.string.install_game_content_success, | ||
| 502 | Toast.LENGTH_SHORT | ||
| 503 | ).show() | ||
| 504 | } | 505 | } |
| 505 | 506 | ||
| 506 | NativeLibrary.InstallFileToNandResult.SuccessFileOverwritten -> { | 507 | NativeLibrary.InstallFileToNandResult.SuccessFileOverwritten -> { |
| 507 | Toast.makeText( | 508 | installOverwrite += 1 |
| 508 | applicationContext, | ||
| 509 | R.string.install_game_content_success_overwrite, | ||
| 510 | Toast.LENGTH_SHORT | ||
| 511 | ).show() | ||
| 512 | } | 509 | } |
| 513 | 510 | ||
| 514 | NativeLibrary.InstallFileToNandResult.ErrorBaseGame -> { | 511 | NativeLibrary.InstallFileToNandResult.ErrorBaseGame -> { |
| 515 | MessageDialogFragment.newInstance( | 512 | errorBaseGame += 1 |
| 516 | R.string.install_game_content_failure, | ||
| 517 | R.string.install_game_content_failure_base | ||
| 518 | ).show(supportFragmentManager, MessageDialogFragment.TAG) | ||
| 519 | } | 513 | } |
| 520 | 514 | ||
| 521 | NativeLibrary.InstallFileToNandResult.ErrorFilenameExtension -> { | 515 | NativeLibrary.InstallFileToNandResult.ErrorFilenameExtension -> { |
| 522 | MessageDialogFragment.newInstance( | 516 | errorExtension += 1 |
| 523 | R.string.install_game_content_failure, | ||
| 524 | R.string.install_game_content_failure_file_extension, | ||
| 525 | R.string.install_game_content_help_link | ||
| 526 | ).show(supportFragmentManager, MessageDialogFragment.TAG) | ||
| 527 | } | 517 | } |
| 528 | 518 | ||
| 529 | else -> { | 519 | else -> { |
| 530 | MessageDialogFragment.newInstance( | 520 | errorOther += 1 |
| 531 | R.string.install_game_content_failure, | ||
| 532 | R.string.install_game_content_failure_description, | ||
| 533 | R.string.install_game_content_help_link | ||
| 534 | ).show(supportFragmentManager, MessageDialogFragment.TAG) | ||
| 535 | } | 521 | } |
| 536 | } | 522 | } |
| 537 | } | 523 | } |
| 524 | withContext(Dispatchers.Main) { | ||
| 525 | val separator = System.getProperty("line.separator") ?: "\n" | ||
| 526 | val installResult = StringBuilder() | ||
| 527 | if (installSuccess > 0) { | ||
| 528 | installResult.append( | ||
| 529 | getString( | ||
| 530 | R.string.install_game_content_success_install, | ||
| 531 | installSuccess | ||
| 532 | ) | ||
| 533 | ) | ||
| 534 | installResult.append(separator) | ||
| 535 | } | ||
| 536 | if (installOverwrite > 0) { | ||
| 537 | installResult.append( | ||
| 538 | getString( | ||
| 539 | R.string.install_game_content_success_overwrite, | ||
| 540 | installOverwrite | ||
| 541 | ) | ||
| 542 | ) | ||
| 543 | installResult.append(separator) | ||
| 544 | } | ||
| 545 | errorTotal = errorBaseGame + errorExtension + errorOther | ||
| 546 | if (errorTotal > 0) { | ||
| 547 | installResult.append(separator) | ||
| 548 | installResult.append( | ||
| 549 | getString( | ||
| 550 | R.string.install_game_content_failed_count, | ||
| 551 | errorTotal | ||
| 552 | ) | ||
| 553 | ) | ||
| 554 | installResult.append(separator) | ||
| 555 | if (errorBaseGame > 0) { | ||
| 556 | installResult.append(separator) | ||
| 557 | installResult.append( | ||
| 558 | getString(R.string.install_game_content_failure_base) | ||
| 559 | ) | ||
| 560 | installResult.append(separator) | ||
| 561 | } | ||
| 562 | if (errorExtension > 0) { | ||
| 563 | installResult.append(separator) | ||
| 564 | installResult.append( | ||
| 565 | getString(R.string.install_game_content_failure_file_extension) | ||
| 566 | ) | ||
| 567 | installResult.append(separator) | ||
| 568 | } | ||
| 569 | if (errorOther > 0) { | ||
| 570 | installResult.append( | ||
| 571 | getString(R.string.install_game_content_failure_description) | ||
| 572 | ) | ||
| 573 | installResult.append(separator) | ||
| 574 | } | ||
| 575 | LongMessageDialogFragment.newInstance( | ||
| 576 | R.string.install_game_content_failure, | ||
| 577 | installResult.toString().trim(), | ||
| 578 | R.string.install_game_content_help_link | ||
| 579 | ).show(supportFragmentManager, LongMessageDialogFragment.TAG) | ||
| 580 | } else { | ||
| 581 | LongMessageDialogFragment.newInstance( | ||
| 582 | R.string.install_game_content_success, | ||
| 583 | installResult.toString().trim() | ||
| 584 | ).show(supportFragmentManager, LongMessageDialogFragment.TAG) | ||
| 585 | } | ||
| 586 | } | ||
| 538 | } | 587 | } |
| 539 | return@newInstance result | 588 | return@newInstance installSuccess + installOverwrite + errorTotal |
| 540 | }.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG) | 589 | }.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG) |
| 541 | } | 590 | } |
| 591 | } | ||
| 542 | } | 592 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt index 9f3bbe56f..142af5f26 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt | |||
| @@ -7,7 +7,6 @@ import android.content.Context | |||
| 7 | import android.database.Cursor | 7 | import android.database.Cursor |
| 8 | import android.net.Uri | 8 | import android.net.Uri |
| 9 | import android.provider.DocumentsContract | 9 | import android.provider.DocumentsContract |
| 10 | import android.provider.OpenableColumns | ||
| 11 | import androidx.documentfile.provider.DocumentFile | 10 | import androidx.documentfile.provider.DocumentFile |
| 12 | import java.io.BufferedInputStream | 11 | import java.io.BufferedInputStream |
| 13 | import java.io.File | 12 | import java.io.File |
| @@ -185,19 +184,18 @@ object FileUtil { | |||
| 185 | 184 | ||
| 186 | /** | 185 | /** |
| 187 | * Get file display name from given path | 186 | * Get file display name from given path |
| 188 | * @param path content uri path | 187 | * @param uri content uri |
| 189 | * @return String display name | 188 | * @return String display name |
| 190 | */ | 189 | */ |
| 191 | fun getFilename(context: Context, path: String): String { | 190 | fun getFilename(uri: Uri): String { |
| 192 | val resolver = context.contentResolver | 191 | val resolver = YuzuApplication.appContext.contentResolver |
| 193 | val columns = arrayOf( | 192 | val columns = arrayOf( |
| 194 | DocumentsContract.Document.COLUMN_DISPLAY_NAME | 193 | DocumentsContract.Document.COLUMN_DISPLAY_NAME |
| 195 | ) | 194 | ) |
| 196 | var filename = "" | 195 | var filename = "" |
| 197 | var c: Cursor? = null | 196 | var c: Cursor? = null |
| 198 | try { | 197 | try { |
| 199 | val mUri = Uri.parse(path) | 198 | c = resolver.query(uri, columns, null, null, null) |
| 200 | c = resolver.query(mUri, columns, null, null, null) | ||
| 201 | c!!.moveToNext() | 199 | c!!.moveToNext() |
| 202 | filename = c.getString(0) | 200 | filename = c.getString(0) |
| 203 | } catch (e: Exception) { | 201 | } catch (e: Exception) { |
| @@ -326,25 +324,9 @@ object FileUtil { | |||
| 326 | } | 324 | } |
| 327 | } | 325 | } |
| 328 | 326 | ||
| 329 | fun hasExtension(path: String, extension: String): Boolean = | 327 | fun getExtension(uri: Uri): String { |
| 330 | path.substring(path.lastIndexOf(".") + 1).contains(extension) | 328 | val fileName = getFilename(uri) |
| 331 | 329 | return fileName.substring(fileName.lastIndexOf(".") + 1) | |
| 332 | fun hasExtension(uri: Uri, extension: String): Boolean { | 330 | .lowercase() |
| 333 | val fileName: String? | ||
| 334 | val cursor = YuzuApplication.appContext.contentResolver.query(uri, null, null, null, null) | ||
| 335 | val nameIndex = cursor?.getColumnIndex(OpenableColumns.DISPLAY_NAME) | ||
| 336 | cursor?.moveToFirst() | ||
| 337 | |||
| 338 | if (nameIndex == null) { | ||
| 339 | return false | ||
| 340 | } | ||
| 341 | |||
| 342 | fileName = cursor.getString(nameIndex) | ||
| 343 | cursor.close() | ||
| 344 | |||
| 345 | if (fileName == null) { | ||
| 346 | return false | ||
| 347 | } | ||
| 348 | return fileName.substring(fileName.lastIndexOf(".") + 1).contains(extension) | ||
| 349 | } | 331 | } |
| 350 | } | 332 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt index ee9f3e570..f8e7eeca7 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt | |||
| @@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.utils | |||
| 6 | import android.content.SharedPreferences | 6 | import android.content.SharedPreferences |
| 7 | import android.net.Uri | 7 | import android.net.Uri |
| 8 | import androidx.preference.PreferenceManager | 8 | import androidx.preference.PreferenceManager |
| 9 | import java.util.* | ||
| 10 | import kotlinx.serialization.encodeToString | 9 | import kotlinx.serialization.encodeToString |
| 11 | import kotlinx.serialization.json.Json | 10 | import kotlinx.serialization.json.Json |
| 12 | import org.yuzu.yuzu_emu.NativeLibrary | 11 | import org.yuzu.yuzu_emu.NativeLibrary |
| @@ -33,15 +32,9 @@ object GameHelper { | |||
| 33 | val children = FileUtil.listFiles(context, gamesUri) | 32 | val children = FileUtil.listFiles(context, gamesUri) |
| 34 | for (file in children) { | 33 | for (file in children) { |
| 35 | if (!file.isDirectory) { | 34 | if (!file.isDirectory) { |
| 36 | val filename = file.uri.toString() | 35 | // Check that the file has an extension we care about before trying to read out of it. |
| 37 | val extensionStart = filename.lastIndexOf('.') | 36 | if (Game.extensions.contains(FileUtil.getExtension(file.uri))) { |
| 38 | if (extensionStart > 0) { | 37 | games.add(getGame(file.uri)) |
| 39 | val fileExtension = filename.substring(extensionStart) | ||
| 40 | |||
| 41 | // Check that the file has an extension we care about before trying to read out of it. | ||
| 42 | if (Game.extensions.contains(fileExtension.lowercase(Locale.getDefault()))) { | ||
| 43 | games.add(getGame(filename)) | ||
| 44 | } | ||
| 45 | } | 38 | } |
| 46 | } | 39 | } |
| 47 | } | 40 | } |
| @@ -59,21 +52,19 @@ object GameHelper { | |||
| 59 | return games.toList() | 52 | return games.toList() |
| 60 | } | 53 | } |
| 61 | 54 | ||
| 62 | private fun getGame(filePath: String): Game { | 55 | private fun getGame(uri: Uri): Game { |
| 56 | val filePath = uri.toString() | ||
| 63 | var name = NativeLibrary.getTitle(filePath) | 57 | var name = NativeLibrary.getTitle(filePath) |
| 64 | 58 | ||
| 65 | // If the game's title field is empty, use the filename. | 59 | // If the game's title field is empty, use the filename. |
| 66 | if (name.isEmpty()) { | 60 | if (name.isEmpty()) { |
| 67 | name = filePath.substring(filePath.lastIndexOf("/") + 1) | 61 | name = FileUtil.getFilename(uri) |
| 68 | } | 62 | } |
| 69 | var gameId = NativeLibrary.getGameId(filePath) | 63 | var gameId = NativeLibrary.getGameId(filePath) |
| 70 | 64 | ||
| 71 | // If the game's ID field is empty, use the filename without extension. | 65 | // If the game's ID field is empty, use the filename without extension. |
| 72 | if (gameId.isEmpty()) { | 66 | if (gameId.isEmpty()) { |
| 73 | gameId = filePath.substring( | 67 | gameId = name.substring(0, name.lastIndexOf(".")) |
| 74 | filePath.lastIndexOf("/") + 1, | ||
| 75 | filePath.lastIndexOf(".") | ||
| 76 | ) | ||
| 77 | } | 68 | } |
| 78 | 69 | ||
| 79 | val newGame = Game( | 70 | val newGame = Game( |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt index dad159481..1d4695a2a 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt | |||
| @@ -113,6 +113,8 @@ object GpuDriverHelper { | |||
| 113 | initializeDriverParameters(context) | 113 | initializeDriverParameters(context) |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | external fun supportsCustomDriverLoading(): Boolean | ||
| 117 | |||
| 116 | // Parse the custom driver metadata to retrieve the name. | 118 | // Parse the custom driver metadata to retrieve the name. |
| 117 | val customDriverName: String? | 119 | val customDriverName: String? |
| 118 | get() { | 120 | get() { |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt new file mode 100644 index 000000000..18e5fa0b0 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.utils | ||
| 5 | |||
| 6 | import android.app.ActivityManager | ||
| 7 | import android.content.Context | ||
| 8 | import org.yuzu.yuzu_emu.R | ||
| 9 | import java.util.Locale | ||
| 10 | |||
| 11 | class MemoryUtil(val context: Context) { | ||
| 12 | |||
| 13 | private val Long.floatForm: String | ||
| 14 | get() = String.format(Locale.ROOT, "%.2f", this.toDouble()) | ||
| 15 | |||
| 16 | private fun bytesToSizeUnit(size: Long): String { | ||
| 17 | return when { | ||
| 18 | size < Kb -> "${size.floatForm} ${context.getString(R.string.memory_byte)}" | ||
| 19 | size < Mb -> "${(size / Kb).floatForm} ${context.getString(R.string.memory_kilobyte)}" | ||
| 20 | size < Gb -> "${(size / Mb).floatForm} ${context.getString(R.string.memory_megabyte)}" | ||
| 21 | size < Tb -> "${(size / Gb).floatForm} ${context.getString(R.string.memory_gigabyte)}" | ||
| 22 | size < Pb -> "${(size / Tb).floatForm} ${context.getString(R.string.memory_terabyte)}" | ||
| 23 | size < Eb -> "${(size / Pb).floatForm} ${context.getString(R.string.memory_petabyte)}" | ||
| 24 | else -> "${(size / Eb).floatForm} ${context.getString(R.string.memory_exabyte)}" | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | private val totalMemory = | ||
| 29 | with(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager) { | ||
| 30 | val memInfo = ActivityManager.MemoryInfo() | ||
| 31 | getMemoryInfo(memInfo) | ||
| 32 | memInfo.totalMem | ||
| 33 | } | ||
| 34 | |||
| 35 | fun isLessThan(minimum: Int, size: Long): Boolean { | ||
| 36 | return when (size) { | ||
| 37 | Kb -> totalMemory < Mb && totalMemory < minimum | ||
| 38 | Mb -> totalMemory < Gb && (totalMemory / Mb) < minimum | ||
| 39 | Gb -> totalMemory < Tb && (totalMemory / Gb) < minimum | ||
| 40 | Tb -> totalMemory < Pb && (totalMemory / Tb) < minimum | ||
| 41 | Pb -> totalMemory < Eb && (totalMemory / Pb) < minimum | ||
| 42 | Eb -> totalMemory / Eb < minimum | ||
| 43 | else -> totalMemory < Kb && totalMemory < minimum | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | fun getDeviceRAM(): String { | ||
| 48 | return bytesToSizeUnit(totalMemory) | ||
| 49 | } | ||
| 50 | |||
| 51 | companion object { | ||
| 52 | const val Kb: Long = 1024 | ||
| 53 | const val Mb = Kb * 1024 | ||
| 54 | const val Gb = Mb * 1024 | ||
| 55 | const val Tb = Gb * 1024 | ||
| 56 | const val Pb = Tb * 1024 | ||
| 57 | const val Eb = Pb * 1024 | ||
| 58 | } | ||
| 59 | } | ||
diff --git a/src/android/app/src/main/jni/CMakeLists.txt b/src/android/app/src/main/jni/CMakeLists.txt index 041781577..e2ed08e9f 100644 --- a/src/android/app/src/main/jni/CMakeLists.txt +++ b/src/android/app/src/main/jni/CMakeLists.txt | |||
| @@ -14,7 +14,6 @@ add_library(yuzu-android SHARED | |||
| 14 | id_cache.cpp | 14 | id_cache.cpp |
| 15 | id_cache.h | 15 | id_cache.h |
| 16 | native.cpp | 16 | native.cpp |
| 17 | native.h | ||
| 18 | ) | 17 | ) |
| 19 | 18 | ||
| 20 | set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR}) | 19 | set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR}) |
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index f9617202b..8bc6a4a04 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <android/api-level.h> | 14 | #include <android/api-level.h> |
| 15 | #include <android/native_window_jni.h> | 15 | #include <android/native_window_jni.h> |
| 16 | #include <core/loader/nro.h> | 16 | #include <core/loader/nro.h> |
| 17 | #include <jni.h> | ||
| 17 | 18 | ||
| 18 | #include "common/detached_tasks.h" | 19 | #include "common/detached_tasks.h" |
| 19 | #include "common/dynamic_library.h" | 20 | #include "common/dynamic_library.h" |
| @@ -59,6 +60,9 @@ | |||
| 59 | #include "video_core/rasterizer_interface.h" | 60 | #include "video_core/rasterizer_interface.h" |
| 60 | #include "video_core/renderer_base.h" | 61 | #include "video_core/renderer_base.h" |
| 61 | 62 | ||
| 63 | #define jconst [[maybe_unused]] const auto | ||
| 64 | #define jauto [[maybe_unused]] auto | ||
| 65 | |||
| 62 | namespace { | 66 | namespace { |
| 63 | 67 | ||
| 64 | class EmulationSession final { | 68 | class EmulationSession final { |
| @@ -98,8 +102,8 @@ public: | |||
| 98 | } | 102 | } |
| 99 | 103 | ||
| 100 | int InstallFileToNand(std::string filename) { | 104 | int InstallFileToNand(std::string filename) { |
| 101 | const auto copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, | 105 | jconst copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, |
| 102 | std::size_t block_size) { | 106 | std::size_t block_size) { |
| 103 | if (src == nullptr || dest == nullptr) { | 107 | if (src == nullptr || dest == nullptr) { |
| 104 | return false; | 108 | return false; |
| 105 | } | 109 | } |
| @@ -108,10 +112,10 @@ public: | |||
| 108 | } | 112 | } |
| 109 | 113 | ||
| 110 | using namespace Common::Literals; | 114 | using namespace Common::Literals; |
| 111 | std::vector<u8> buffer(1_MiB); | 115 | [[maybe_unused]] std::vector<u8> buffer(1_MiB); |
| 112 | 116 | ||
| 113 | for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { | 117 | for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { |
| 114 | const auto read = src->Read(buffer.data(), buffer.size(), i); | 118 | jconst read = src->Read(buffer.data(), buffer.size(), i); |
| 115 | dest->Write(buffer.data(), read, i); | 119 | dest->Write(buffer.data(), read, i); |
| 116 | } | 120 | } |
| 117 | return true; | 121 | return true; |
| @@ -128,14 +132,14 @@ public: | |||
| 128 | m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>()); | 132 | m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>()); |
| 129 | m_system.GetFileSystemController().CreateFactories(*m_vfs); | 133 | m_system.GetFileSystemController().CreateFactories(*m_vfs); |
| 130 | 134 | ||
| 131 | std::shared_ptr<FileSys::NSP> nsp; | 135 | [[maybe_unused]] std::shared_ptr<FileSys::NSP> nsp; |
| 132 | if (filename.ends_with("nsp")) { | 136 | if (filename.ends_with("nsp")) { |
| 133 | nsp = std::make_shared<FileSys::NSP>(m_vfs->OpenFile(filename, FileSys::Mode::Read)); | 137 | nsp = std::make_shared<FileSys::NSP>(m_vfs->OpenFile(filename, FileSys::Mode::Read)); |
| 134 | if (nsp->IsExtractedType()) { | 138 | if (nsp->IsExtractedType()) { |
| 135 | return InstallError; | 139 | return InstallError; |
| 136 | } | 140 | } |
| 137 | } else if (filename.ends_with("xci")) { | 141 | } else if (filename.ends_with("xci")) { |
| 138 | const auto xci = | 142 | jconst xci = |
| 139 | std::make_shared<FileSys::XCI>(m_vfs->OpenFile(filename, FileSys::Mode::Read)); | 143 | std::make_shared<FileSys::XCI>(m_vfs->OpenFile(filename, FileSys::Mode::Read)); |
| 140 | nsp = xci->GetSecurePartitionNSP(); | 144 | nsp = xci->GetSecurePartitionNSP(); |
| 141 | } else { | 145 | } else { |
| @@ -150,7 +154,7 @@ public: | |||
| 150 | return InstallError; | 154 | return InstallError; |
| 151 | } | 155 | } |
| 152 | 156 | ||
| 153 | const auto res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry( | 157 | jconst res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry( |
| 154 | *nsp, true, copy_func); | 158 | *nsp, true, copy_func); |
| 155 | 159 | ||
| 156 | switch (res) { | 160 | switch (res) { |
| @@ -233,10 +237,11 @@ public: | |||
| 233 | m_system.SetFilesystem(m_vfs); | 237 | m_system.SetFilesystem(m_vfs); |
| 234 | 238 | ||
| 235 | // Initialize system. | 239 | // Initialize system. |
| 236 | auto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>(); | 240 | jauto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>(); |
| 237 | m_software_keyboard = android_keyboard.get(); | 241 | m_software_keyboard = android_keyboard.get(); |
| 238 | m_system.SetShuttingDown(false); | 242 | m_system.SetShuttingDown(false); |
| 239 | m_system.ApplySettings(); | 243 | m_system.ApplySettings(); |
| 244 | Settings::LogSettings(); | ||
| 240 | m_system.HIDCore().ReloadInputDevices(); | 245 | m_system.HIDCore().ReloadInputDevices(); |
| 241 | m_system.SetAppletFrontendSet({ | 246 | m_system.SetAppletFrontendSet({ |
| 242 | nullptr, // Amiibo Settings | 247 | nullptr, // Amiibo Settings |
| @@ -330,7 +335,7 @@ public: | |||
| 330 | 335 | ||
| 331 | while (true) { | 336 | while (true) { |
| 332 | { | 337 | { |
| 333 | std::unique_lock lock(m_mutex); | 338 | [[maybe_unused]] std::unique_lock lock(m_mutex); |
| 334 | if (m_cv.wait_for(lock, std::chrono::milliseconds(800), | 339 | if (m_cv.wait_for(lock, std::chrono::milliseconds(800), |
| 335 | [&]() { return !m_is_running; })) { | 340 | [&]() { return !m_is_running; })) { |
| 336 | // Emulation halted. | 341 | // Emulation halted. |
| @@ -362,7 +367,7 @@ public: | |||
| 362 | } | 367 | } |
| 363 | 368 | ||
| 364 | bool IsHandheldOnly() { | 369 | bool IsHandheldOnly() { |
| 365 | const auto npad_style_set = m_system.HIDCore().GetSupportedStyleTag(); | 370 | jconst npad_style_set = m_system.HIDCore().GetSupportedStyleTag(); |
| 366 | 371 | ||
| 367 | if (npad_style_set.fullkey == 1) { | 372 | if (npad_style_set.fullkey == 1) { |
| 368 | return false; | 373 | return false; |
| @@ -375,17 +380,17 @@ public: | |||
| 375 | return !Settings::values.use_docked_mode.GetValue(); | 380 | return !Settings::values.use_docked_mode.GetValue(); |
| 376 | } | 381 | } |
| 377 | 382 | ||
| 378 | void SetDeviceType(int index, int type) { | 383 | void SetDeviceType([[maybe_unused]] int index, int type) { |
| 379 | auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); | 384 | jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); |
| 380 | controller->SetNpadStyleIndex(static_cast<Core::HID::NpadStyleIndex>(type)); | 385 | controller->SetNpadStyleIndex(static_cast<Core::HID::NpadStyleIndex>(type)); |
| 381 | } | 386 | } |
| 382 | 387 | ||
| 383 | void OnGamepadConnectEvent(int index) { | 388 | void OnGamepadConnectEvent([[maybe_unused]] int index) { |
| 384 | auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); | 389 | jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); |
| 385 | 390 | ||
| 386 | // Ensure that player1 is configured correctly and handheld disconnected | 391 | // Ensure that player1 is configured correctly and handheld disconnected |
| 387 | if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) { | 392 | if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) { |
| 388 | auto handheld = | 393 | jauto handheld = |
| 389 | m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); | 394 | m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); |
| 390 | 395 | ||
| 391 | if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) { | 396 | if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) { |
| @@ -397,7 +402,8 @@ public: | |||
| 397 | 402 | ||
| 398 | // Ensure that handheld is configured correctly and player 1 disconnected | 403 | // Ensure that handheld is configured correctly and player 1 disconnected |
| 399 | if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) { | 404 | if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) { |
| 400 | auto player1 = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); | 405 | jauto player1 = |
| 406 | m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); | ||
| 401 | 407 | ||
| 402 | if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) { | 408 | if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) { |
| 403 | player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); | 409 | player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); |
| @@ -411,8 +417,8 @@ public: | |||
| 411 | } | 417 | } |
| 412 | } | 418 | } |
| 413 | 419 | ||
| 414 | void OnGamepadDisconnectEvent(int index) { | 420 | void OnGamepadDisconnectEvent([[maybe_unused]] int index) { |
| 415 | auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); | 421 | jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); |
| 416 | controller->Disconnect(); | 422 | controller->Disconnect(); |
| 417 | } | 423 | } |
| 418 | 424 | ||
| @@ -428,7 +434,7 @@ private: | |||
| 428 | }; | 434 | }; |
| 429 | 435 | ||
| 430 | RomMetadata GetRomMetadata(const std::string& path) { | 436 | RomMetadata GetRomMetadata(const std::string& path) { |
| 431 | if (auto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) { | 437 | if (jauto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) { |
| 432 | return search->second; | 438 | return search->second; |
| 433 | } | 439 | } |
| 434 | 440 | ||
| @@ -436,14 +442,14 @@ private: | |||
| 436 | } | 442 | } |
| 437 | 443 | ||
| 438 | RomMetadata CacheRomMetadata(const std::string& path) { | 444 | RomMetadata CacheRomMetadata(const std::string& path) { |
| 439 | const auto file = Core::GetGameFileFromPath(m_vfs, path); | 445 | jconst file = Core::GetGameFileFromPath(m_vfs, path); |
| 440 | auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0); | 446 | jauto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0); |
| 441 | 447 | ||
| 442 | RomMetadata entry; | 448 | RomMetadata entry; |
| 443 | loader->ReadTitle(entry.title); | 449 | loader->ReadTitle(entry.title); |
| 444 | loader->ReadIcon(entry.icon); | 450 | loader->ReadIcon(entry.icon); |
| 445 | if (loader->GetFileType() == Loader::FileType::NRO) { | 451 | if (loader->GetFileType() == Loader::FileType::NRO) { |
| 446 | auto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get()); | 452 | jauto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get()); |
| 447 | entry.isHomebrew = loader_nro->IsHomebrew(); | 453 | entry.isHomebrew = loader_nro->IsHomebrew(); |
| 448 | } else { | 454 | } else { |
| 449 | entry.isHomebrew = false; | 455 | entry.isHomebrew = false; |
| @@ -514,7 +520,7 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) { | |||
| 514 | 520 | ||
| 515 | SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); }); | 521 | SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); }); |
| 516 | 522 | ||
| 517 | const auto result = EmulationSession::GetInstance().InitializeEmulation(filepath); | 523 | jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath); |
| 518 | if (result != Core::SystemResultStatus::Success) { | 524 | if (result != Core::SystemResultStatus::Success) { |
| 519 | return result; | 525 | return result; |
| 520 | } | 526 | } |
| @@ -526,83 +532,104 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) { | |||
| 526 | 532 | ||
| 527 | extern "C" { | 533 | extern "C" { |
| 528 | 534 | ||
| 529 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, | 535 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, jobject instance, |
| 530 | [[maybe_unused]] jclass clazz, | 536 | [[maybe_unused]] jobject surf) { |
| 531 | jobject surf) { | ||
| 532 | EmulationSession::GetInstance().SetNativeWindow(ANativeWindow_fromSurface(env, surf)); | 537 | EmulationSession::GetInstance().SetNativeWindow(ANativeWindow_fromSurface(env, surf)); |
| 533 | EmulationSession::GetInstance().SurfaceChanged(); | 538 | EmulationSession::GetInstance().SurfaceChanged(); |
| 534 | } | 539 | } |
| 535 | 540 | ||
| 536 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, | 541 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, jobject instance) { |
| 537 | [[maybe_unused]] jclass clazz) { | ||
| 538 | ANativeWindow_release(EmulationSession::GetInstance().NativeWindow()); | 542 | ANativeWindow_release(EmulationSession::GetInstance().NativeWindow()); |
| 539 | EmulationSession::GetInstance().SetNativeWindow(nullptr); | 543 | EmulationSession::GetInstance().SetNativeWindow(nullptr); |
| 540 | EmulationSession::GetInstance().SurfaceChanged(); | 544 | EmulationSession::GetInstance().SurfaceChanged(); |
| 541 | } | 545 | } |
| 542 | 546 | ||
| 543 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, | 547 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jobject instance, |
| 544 | [[maybe_unused]] jclass clazz, | 548 | [[maybe_unused]] jstring j_directory) { |
| 545 | jstring j_directory) { | ||
| 546 | Common::FS::SetAppDirectory(GetJString(env, j_directory)); | 549 | Common::FS::SetAppDirectory(GetJString(env, j_directory)); |
| 547 | } | 550 | } |
| 548 | 551 | ||
| 549 | int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, | 552 | int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject instance, |
| 550 | [[maybe_unused]] jclass clazz, | 553 | [[maybe_unused]] jstring j_file) { |
| 551 | jstring j_file) { | ||
| 552 | return EmulationSession::GetInstance().InstallFileToNand(GetJString(env, j_file)); | 554 | return EmulationSession::GetInstance().InstallFileToNand(GetJString(env, j_file)); |
| 553 | } | 555 | } |
| 554 | 556 | ||
| 555 | void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver( | 557 | void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(JNIEnv* env, jclass clazz, |
| 556 | JNIEnv* env, [[maybe_unused]] jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir, | 558 | jstring hook_lib_dir, |
| 557 | jstring custom_driver_name, jstring file_redirect_dir) { | 559 | jstring custom_driver_dir, |
| 560 | jstring custom_driver_name, | ||
| 561 | jstring file_redirect_dir) { | ||
| 558 | EmulationSession::GetInstance().InitializeGpuDriver( | 562 | EmulationSession::GetInstance().InitializeGpuDriver( |
| 559 | GetJString(env, hook_lib_dir), GetJString(env, custom_driver_dir), | 563 | GetJString(env, hook_lib_dir), GetJString(env, custom_driver_dir), |
| 560 | GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir)); | 564 | GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir)); |
| 561 | } | 565 | } |
| 562 | 566 | ||
| 563 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env, | 567 | [[maybe_unused]] static bool CheckKgslPresent() { |
| 564 | [[maybe_unused]] jclass clazz) { | 568 | constexpr auto KgslPath{"/dev/kgsl-3d0"}; |
| 569 | |||
| 570 | return access(KgslPath, F_OK) == 0; | ||
| 571 | } | ||
| 572 | |||
| 573 | [[maybe_unused]] bool SupportsCustomDriver() { | ||
| 574 | return android_get_device_api_level() >= 28 && CheckKgslPresent(); | ||
| 575 | } | ||
| 576 | |||
| 577 | jboolean JNICALL Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_supportsCustomDriverLoading( | ||
| 578 | JNIEnv* env, jobject instance) { | ||
| 579 | #ifdef ARCHITECTURE_arm64 | ||
| 580 | // If the KGSL device exists custom drivers can be loaded using adrenotools | ||
| 581 | return SupportsCustomDriver(); | ||
| 582 | #else | ||
| 583 | return false; | ||
| 584 | #endif | ||
| 585 | } | ||
| 586 | |||
| 587 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env, jclass clazz) { | ||
| 565 | Core::Crypto::KeyManager::Instance().ReloadKeys(); | 588 | Core::Crypto::KeyManager::Instance().ReloadKeys(); |
| 566 | return static_cast<jboolean>(Core::Crypto::KeyManager::Instance().AreKeysLoaded()); | 589 | return static_cast<jboolean>(Core::Crypto::KeyManager::Instance().AreKeysLoaded()); |
| 567 | } | 590 | } |
| 568 | 591 | ||
| 569 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_unPauseEmulation([[maybe_unused]] JNIEnv* env, | 592 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_unpauseEmulation(JNIEnv* env, jclass clazz) { |
| 570 | [[maybe_unused]] jclass clazz) { | ||
| 571 | EmulationSession::GetInstance().UnPauseEmulation(); | 593 | EmulationSession::GetInstance().UnPauseEmulation(); |
| 572 | } | 594 | } |
| 573 | 595 | ||
| 574 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_pauseEmulation([[maybe_unused]] JNIEnv* env, | 596 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_pauseEmulation(JNIEnv* env, jclass clazz) { |
| 575 | [[maybe_unused]] jclass clazz) { | ||
| 576 | EmulationSession::GetInstance().PauseEmulation(); | 597 | EmulationSession::GetInstance().PauseEmulation(); |
| 577 | } | 598 | } |
| 578 | 599 | ||
| 579 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_stopEmulation([[maybe_unused]] JNIEnv* env, | 600 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_stopEmulation(JNIEnv* env, jclass clazz) { |
| 580 | [[maybe_unused]] jclass clazz) { | ||
| 581 | EmulationSession::GetInstance().HaltEmulation(); | 601 | EmulationSession::GetInstance().HaltEmulation(); |
| 582 | } | 602 | } |
| 583 | 603 | ||
| 584 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_resetRomMetadata([[maybe_unused]] JNIEnv* env, | 604 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_resetRomMetadata(JNIEnv* env, jclass clazz) { |
| 585 | [[maybe_unused]] jclass clazz) { | ||
| 586 | EmulationSession::GetInstance().ResetRomMetadata(); | 605 | EmulationSession::GetInstance().ResetRomMetadata(); |
| 587 | } | 606 | } |
| 588 | 607 | ||
| 589 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isRunning([[maybe_unused]] JNIEnv* env, | 608 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isRunning(JNIEnv* env, jclass clazz) { |
| 590 | [[maybe_unused]] jclass clazz) { | ||
| 591 | return static_cast<jboolean>(EmulationSession::GetInstance().IsRunning()); | 609 | return static_cast<jboolean>(EmulationSession::GetInstance().IsRunning()); |
| 592 | } | 610 | } |
| 593 | 611 | ||
| 594 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isPaused([[maybe_unused]] JNIEnv* env, | 612 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isPaused(JNIEnv* env, jclass clazz) { |
| 595 | [[maybe_unused]] jclass clazz) { | ||
| 596 | return static_cast<jboolean>(EmulationSession::GetInstance().IsPaused()); | 613 | return static_cast<jboolean>(EmulationSession::GetInstance().IsPaused()); |
| 597 | } | 614 | } |
| 598 | 615 | ||
| 599 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHandheldOnly([[maybe_unused]] JNIEnv* env, | 616 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_muteAduio(JNIEnv* env, jclass clazz) { |
| 600 | [[maybe_unused]] jclass clazz) { | 617 | Settings::values.audio_muted = true; |
| 618 | } | ||
| 619 | |||
| 620 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_unmuteAudio(JNIEnv* env, jclass clazz) { | ||
| 621 | Settings::values.audio_muted = false; | ||
| 622 | } | ||
| 623 | |||
| 624 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isMuted(JNIEnv* env, jclass clazz) { | ||
| 625 | return static_cast<jboolean>(Settings::values.audio_muted.GetValue()); | ||
| 626 | } | ||
| 627 | |||
| 628 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHandheldOnly(JNIEnv* env, jclass clazz) { | ||
| 601 | return EmulationSession::GetInstance().IsHandheldOnly(); | 629 | return EmulationSession::GetInstance().IsHandheldOnly(); |
| 602 | } | 630 | } |
| 603 | 631 | ||
| 604 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_setDeviceType([[maybe_unused]] JNIEnv* env, | 632 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_setDeviceType(JNIEnv* env, jclass clazz, |
| 605 | [[maybe_unused]] jclass clazz, | ||
| 606 | jint j_device, jint j_type) { | 633 | jint j_device, jint j_type) { |
| 607 | if (EmulationSession::GetInstance().IsRunning()) { | 634 | if (EmulationSession::GetInstance().IsRunning()) { |
| 608 | EmulationSession::GetInstance().SetDeviceType(j_device, j_type); | 635 | EmulationSession::GetInstance().SetDeviceType(j_device, j_type); |
| @@ -610,8 +637,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_setDeviceType([[maybe_unused]] JN | |||
| 610 | return static_cast<jboolean>(true); | 637 | return static_cast<jboolean>(true); |
| 611 | } | 638 | } |
| 612 | 639 | ||
| 613 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadConnectEvent([[maybe_unused]] JNIEnv* env, | 640 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadConnectEvent(JNIEnv* env, jclass clazz, |
| 614 | [[maybe_unused]] jclass clazz, | ||
| 615 | jint j_device) { | 641 | jint j_device) { |
| 616 | if (EmulationSession::GetInstance().IsRunning()) { | 642 | if (EmulationSession::GetInstance().IsRunning()) { |
| 617 | EmulationSession::GetInstance().OnGamepadConnectEvent(j_device); | 643 | EmulationSession::GetInstance().OnGamepadConnectEvent(j_device); |
| @@ -619,17 +645,16 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadConnectEvent([[maybe_unu | |||
| 619 | return static_cast<jboolean>(true); | 645 | return static_cast<jboolean>(true); |
| 620 | } | 646 | } |
| 621 | 647 | ||
| 622 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent( | 648 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent(JNIEnv* env, jclass clazz, |
| 623 | [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device) { | 649 | jint j_device) { |
| 624 | if (EmulationSession::GetInstance().IsRunning()) { | 650 | if (EmulationSession::GetInstance().IsRunning()) { |
| 625 | EmulationSession::GetInstance().OnGamepadDisconnectEvent(j_device); | 651 | EmulationSession::GetInstance().OnGamepadDisconnectEvent(j_device); |
| 626 | } | 652 | } |
| 627 | return static_cast<jboolean>(true); | 653 | return static_cast<jboolean>(true); |
| 628 | } | 654 | } |
| 629 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent([[maybe_unused]] JNIEnv* env, | 655 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent(JNIEnv* env, jclass clazz, |
| 630 | [[maybe_unused]] jclass clazz, | 656 | jint j_device, jint j_button, |
| 631 | [[maybe_unused]] jint j_device, | 657 | jint action) { |
| 632 | jint j_button, jint action) { | ||
| 633 | if (EmulationSession::GetInstance().IsRunning()) { | 658 | if (EmulationSession::GetInstance().IsRunning()) { |
| 634 | // Ensure gamepad is connected | 659 | // Ensure gamepad is connected |
| 635 | EmulationSession::GetInstance().OnGamepadConnectEvent(j_device); | 660 | EmulationSession::GetInstance().OnGamepadConnectEvent(j_device); |
| @@ -639,8 +664,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent([[maybe_unus | |||
| 639 | return static_cast<jboolean>(true); | 664 | return static_cast<jboolean>(true); |
| 640 | } | 665 | } |
| 641 | 666 | ||
| 642 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadJoystickEvent([[maybe_unused]] JNIEnv* env, | 667 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadJoystickEvent(JNIEnv* env, jclass clazz, |
| 643 | [[maybe_unused]] jclass clazz, | ||
| 644 | jint j_device, jint stick_id, | 668 | jint j_device, jint stick_id, |
| 645 | jfloat x, jfloat y) { | 669 | jfloat x, jfloat y) { |
| 646 | if (EmulationSession::GetInstance().IsRunning()) { | 670 | if (EmulationSession::GetInstance().IsRunning()) { |
| @@ -650,9 +674,8 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadJoystickEvent([[maybe_un | |||
| 650 | } | 674 | } |
| 651 | 675 | ||
| 652 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent( | 676 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent( |
| 653 | [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device, | 677 | JNIEnv* env, jclass clazz, jint j_device, jlong delta_timestamp, jfloat gyro_x, jfloat gyro_y, |
| 654 | jlong delta_timestamp, jfloat gyro_x, jfloat gyro_y, jfloat gyro_z, jfloat accel_x, | 678 | jfloat gyro_z, jfloat accel_x, jfloat accel_y, jfloat accel_z) { |
| 655 | jfloat accel_y, jfloat accel_z) { | ||
| 656 | if (EmulationSession::GetInstance().IsRunning()) { | 679 | if (EmulationSession::GetInstance().IsRunning()) { |
| 657 | EmulationSession::GetInstance().Window().OnGamepadMotionEvent( | 680 | EmulationSession::GetInstance().Window().OnGamepadMotionEvent( |
| 658 | j_device, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z); | 681 | j_device, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z); |
| @@ -660,8 +683,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent( | |||
| 660 | return static_cast<jboolean>(true); | 683 | return static_cast<jboolean>(true); |
| 661 | } | 684 | } |
| 662 | 685 | ||
| 663 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag([[maybe_unused]] JNIEnv* env, | 686 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag(JNIEnv* env, jclass clazz, |
| 664 | [[maybe_unused]] jclass clazz, | ||
| 665 | jbyteArray j_data) { | 687 | jbyteArray j_data) { |
| 666 | jboolean isCopy{false}; | 688 | jboolean isCopy{false}; |
| 667 | std::span<u8> data(reinterpret_cast<u8*>(env->GetByteArrayElements(j_data, &isCopy)), | 689 | std::span<u8> data(reinterpret_cast<u8*>(env->GetByteArrayElements(j_data, &isCopy)), |
| @@ -673,108 +695,92 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag([[maybe_unused]] JNI | |||
| 673 | return static_cast<jboolean>(true); | 695 | return static_cast<jboolean>(true); |
| 674 | } | 696 | } |
| 675 | 697 | ||
| 676 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onRemoveNfcTag([[maybe_unused]] JNIEnv* env, | 698 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onRemoveNfcTag(JNIEnv* env, jclass clazz) { |
| 677 | [[maybe_unused]] jclass clazz) { | ||
| 678 | if (EmulationSession::GetInstance().IsRunning()) { | 699 | if (EmulationSession::GetInstance().IsRunning()) { |
| 679 | EmulationSession::GetInstance().Window().OnRemoveNfcTag(); | 700 | EmulationSession::GetInstance().Window().OnRemoveNfcTag(); |
| 680 | } | 701 | } |
| 681 | return static_cast<jboolean>(true); | 702 | return static_cast<jboolean>(true); |
| 682 | } | 703 | } |
| 683 | 704 | ||
| 684 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchPressed([[maybe_unused]] JNIEnv* env, | 705 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchPressed(JNIEnv* env, jclass clazz, jint id, |
| 685 | [[maybe_unused]] jclass clazz, jint id, | ||
| 686 | jfloat x, jfloat y) { | 706 | jfloat x, jfloat y) { |
| 687 | if (EmulationSession::GetInstance().IsRunning()) { | 707 | if (EmulationSession::GetInstance().IsRunning()) { |
| 688 | EmulationSession::GetInstance().Window().OnTouchPressed(id, x, y); | 708 | EmulationSession::GetInstance().Window().OnTouchPressed(id, x, y); |
| 689 | } | 709 | } |
| 690 | } | 710 | } |
| 691 | 711 | ||
| 692 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved([[maybe_unused]] JNIEnv* env, | 712 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved(JNIEnv* env, jclass clazz, jint id, |
| 693 | [[maybe_unused]] jclass clazz, jint id, | ||
| 694 | jfloat x, jfloat y) { | 713 | jfloat x, jfloat y) { |
| 695 | if (EmulationSession::GetInstance().IsRunning()) { | 714 | if (EmulationSession::GetInstance().IsRunning()) { |
| 696 | EmulationSession::GetInstance().Window().OnTouchMoved(id, x, y); | 715 | EmulationSession::GetInstance().Window().OnTouchMoved(id, x, y); |
| 697 | } | 716 | } |
| 698 | } | 717 | } |
| 699 | 718 | ||
| 700 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased([[maybe_unused]] JNIEnv* env, | 719 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased(JNIEnv* env, jclass clazz, jint id) { |
| 701 | [[maybe_unused]] jclass clazz, jint id) { | ||
| 702 | if (EmulationSession::GetInstance().IsRunning()) { | 720 | if (EmulationSession::GetInstance().IsRunning()) { |
| 703 | EmulationSession::GetInstance().Window().OnTouchReleased(id); | 721 | EmulationSession::GetInstance().Window().OnTouchReleased(id); |
| 704 | } | 722 | } |
| 705 | } | 723 | } |
| 706 | 724 | ||
| 707 | jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon([[maybe_unused]] JNIEnv* env, | 725 | jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon(JNIEnv* env, jclass clazz, |
| 708 | [[maybe_unused]] jclass clazz, | 726 | jstring j_filename) { |
| 709 | [[maybe_unused]] jstring j_filename) { | 727 | jauto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename)); |
| 710 | auto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename)); | ||
| 711 | jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size())); | 728 | jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size())); |
| 712 | env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon), | 729 | env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon), |
| 713 | reinterpret_cast<jbyte*>(icon_data.data())); | 730 | reinterpret_cast<jbyte*>(icon_data.data())); |
| 714 | return icon; | 731 | return icon; |
| 715 | } | 732 | } |
| 716 | 733 | ||
| 717 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getTitle([[maybe_unused]] JNIEnv* env, | 734 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getTitle(JNIEnv* env, jclass clazz, |
| 718 | [[maybe_unused]] jclass clazz, | 735 | jstring j_filename) { |
| 719 | [[maybe_unused]] jstring j_filename) { | 736 | jauto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename)); |
| 720 | auto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename)); | ||
| 721 | return env->NewStringUTF(title.c_str()); | 737 | return env->NewStringUTF(title.c_str()); |
| 722 | } | 738 | } |
| 723 | 739 | ||
| 724 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDescription([[maybe_unused]] JNIEnv* env, | 740 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDescription(JNIEnv* env, jclass clazz, |
| 725 | [[maybe_unused]] jclass clazz, | ||
| 726 | jstring j_filename) { | 741 | jstring j_filename) { |
| 727 | return j_filename; | 742 | return j_filename; |
| 728 | } | 743 | } |
| 729 | 744 | ||
| 730 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGameId([[maybe_unused]] JNIEnv* env, | 745 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGameId(JNIEnv* env, jclass clazz, |
| 731 | [[maybe_unused]] jclass clazz, | ||
| 732 | jstring j_filename) { | 746 | jstring j_filename) { |
| 733 | return j_filename; | 747 | return j_filename; |
| 734 | } | 748 | } |
| 735 | 749 | ||
| 736 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getRegions([[maybe_unused]] JNIEnv* env, | 750 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getRegions(JNIEnv* env, jclass clazz, |
| 737 | [[maybe_unused]] jclass clazz, | 751 | jstring j_filename) { |
| 738 | [[maybe_unused]] jstring j_filename) { | ||
| 739 | return env->NewStringUTF(""); | 752 | return env->NewStringUTF(""); |
| 740 | } | 753 | } |
| 741 | 754 | ||
| 742 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany([[maybe_unused]] JNIEnv* env, | 755 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany(JNIEnv* env, jclass clazz, |
| 743 | [[maybe_unused]] jclass clazz, | 756 | jstring j_filename) { |
| 744 | [[maybe_unused]] jstring j_filename) { | ||
| 745 | return env->NewStringUTF(""); | 757 | return env->NewStringUTF(""); |
| 746 | } | 758 | } |
| 747 | 759 | ||
| 748 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew([[maybe_unused]] JNIEnv* env, | 760 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew(JNIEnv* env, jclass clazz, |
| 749 | [[maybe_unused]] jclass clazz, | 761 | jstring j_filename) { |
| 750 | [[maybe_unused]] jstring j_filename) { | ||
| 751 | return EmulationSession::GetInstance().GetIsHomebrew(GetJString(env, j_filename)); | 762 | return EmulationSession::GetInstance().GetIsHomebrew(GetJString(env, j_filename)); |
| 752 | } | 763 | } |
| 753 | 764 | ||
| 754 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation | 765 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation(JNIEnv* env, jclass clazz) { |
| 755 | [[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) { | ||
| 756 | // Create the default config.ini. | 766 | // Create the default config.ini. |
| 757 | Config{}; | 767 | Config{}; |
| 758 | // Initialize the emulated system. | 768 | // Initialize the emulated system. |
| 759 | EmulationSession::GetInstance().System().Initialize(); | 769 | EmulationSession::GetInstance().System().Initialize(); |
| 760 | } | 770 | } |
| 761 | 771 | ||
| 762 | jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore([[maybe_unused]] JNIEnv* env, | 772 | jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass clazz) { |
| 763 | [[maybe_unused]] jclass clazz) { | ||
| 764 | return {}; | 773 | return {}; |
| 765 | } | 774 | } |
| 766 | 775 | ||
| 767 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z( | 776 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z( |
| 768 | [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, [[maybe_unused]] jstring j_file, | 777 | JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate) {} |
| 769 | [[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {} | ||
| 770 | 778 | ||
| 771 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings([[maybe_unused]] JNIEnv* env, | 779 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings(JNIEnv* env, jclass clazz) { |
| 772 | [[maybe_unused]] jclass clazz) { | ||
| 773 | Config{}; | 780 | Config{}; |
| 774 | } | 781 | } |
| 775 | 782 | ||
| 776 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getUserSetting([[maybe_unused]] JNIEnv* env, | 783 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getUserSetting(JNIEnv* env, jclass clazz, |
| 777 | [[maybe_unused]] jclass clazz, | ||
| 778 | jstring j_game_id, jstring j_section, | 784 | jstring j_game_id, jstring j_section, |
| 779 | jstring j_key) { | 785 | jstring j_key) { |
| 780 | std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); | 786 | std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); |
| @@ -788,8 +794,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getUserSetting([[maybe_unused]] JN | |||
| 788 | return env->NewStringUTF(""); | 794 | return env->NewStringUTF(""); |
| 789 | } | 795 | } |
| 790 | 796 | ||
| 791 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_setUserSetting([[maybe_unused]] JNIEnv* env, | 797 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_setUserSetting(JNIEnv* env, jclass clazz, |
| 792 | [[maybe_unused]] jclass clazz, | ||
| 793 | jstring j_game_id, jstring j_section, | 798 | jstring j_game_id, jstring j_section, |
| 794 | jstring j_key, jstring j_value) { | 799 | jstring j_key, jstring j_value) { |
| 795 | std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); | 800 | std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); |
| @@ -803,20 +808,18 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_setUserSetting([[maybe_unused]] JNIEn | |||
| 803 | env->ReleaseStringUTFChars(j_value, value.data()); | 808 | env->ReleaseStringUTFChars(j_value, value.data()); |
| 804 | } | 809 | } |
| 805 | 810 | ||
| 806 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_initGameIni([[maybe_unused]] JNIEnv* env, | 811 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_initGameIni(JNIEnv* env, jclass clazz, |
| 807 | [[maybe_unused]] jclass clazz, | ||
| 808 | jstring j_game_id) { | 812 | jstring j_game_id) { |
| 809 | std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); | 813 | std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); |
| 810 | 814 | ||
| 811 | env->ReleaseStringUTFChars(j_game_id, game_id.data()); | 815 | env->ReleaseStringUTFChars(j_game_id, game_id.data()); |
| 812 | } | 816 | } |
| 813 | 817 | ||
| 814 | jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats([[maybe_unused]] JNIEnv* env, | 818 | jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jclass clazz) { |
| 815 | [[maybe_unused]] jclass clazz) { | ||
| 816 | jdoubleArray j_stats = env->NewDoubleArray(4); | 819 | jdoubleArray j_stats = env->NewDoubleArray(4); |
| 817 | 820 | ||
| 818 | if (EmulationSession::GetInstance().IsRunning()) { | 821 | if (EmulationSession::GetInstance().IsRunning()) { |
| 819 | const auto results = EmulationSession::GetInstance().PerfStats(); | 822 | jconst results = EmulationSession::GetInstance().PerfStats(); |
| 820 | 823 | ||
| 821 | // Converting the structure into an array makes it easier to pass it to the frontend | 824 | // Converting the structure into an array makes it easier to pass it to the frontend |
| 822 | double stats[4] = {results.system_fps, results.average_game_fps, results.frametime, | 825 | double stats[4] = {results.system_fps, results.average_game_fps, results.frametime, |
| @@ -828,11 +831,11 @@ jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats([[maybe_unused]] | |||
| 828 | return j_stats; | 831 | return j_stats; |
| 829 | } | 832 | } |
| 830 | 833 | ||
| 831 | void Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_setSysDirectory( | 834 | void Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_setSysDirectory(JNIEnv* env, |
| 832 | [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jstring j_path) {} | 835 | jclass clazz, |
| 836 | jstring j_path) {} | ||
| 833 | 837 | ||
| 834 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2([[maybe_unused]] JNIEnv* env, | 838 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2(JNIEnv* env, jclass clazz, |
| 835 | [[maybe_unused]] jclass clazz, | ||
| 836 | jstring j_path) { | 839 | jstring j_path) { |
| 837 | const std::string path = GetJString(env, j_path); | 840 | const std::string path = GetJString(env, j_path); |
| 838 | 841 | ||
| @@ -843,8 +846,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2([[maybe_unus | |||
| 843 | } | 846 | } |
| 844 | } | 847 | } |
| 845 | 848 | ||
| 846 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_logDeviceInfo([[maybe_unused]] JNIEnv* env, | 849 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_logDeviceInfo(JNIEnv* env, jclass clazz) { |
| 847 | [[maybe_unused]] jclass clazz) { | ||
| 848 | LOG_INFO(Frontend, "yuzu Version: {}-{}", Common::g_scm_branch, Common::g_scm_desc); | 850 | LOG_INFO(Frontend, "yuzu Version: {}-{}", Common::g_scm_branch, Common::g_scm_desc); |
| 849 | LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level()); | 851 | LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level()); |
| 850 | } | 852 | } |
diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h deleted file mode 100644 index 24dcbbcb8..000000000 --- a/src/android/app/src/main/jni/native.h +++ /dev/null | |||
| @@ -1,165 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <jni.h> | ||
| 7 | |||
| 8 | // Function calls from the Java side | ||
| 9 | #ifdef __cplusplus | ||
| 10 | extern "C" { | ||
| 11 | #endif | ||
| 12 | |||
| 13 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_UnPauseEmulation(JNIEnv* env, | ||
| 14 | jclass clazz); | ||
| 15 | |||
| 16 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_PauseEmulation(JNIEnv* env, | ||
| 17 | jclass clazz); | ||
| 18 | |||
| 19 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_StopEmulation(JNIEnv* env, | ||
| 20 | jclass clazz); | ||
| 21 | |||
| 22 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_ResetRomMetadata(JNIEnv* env, | ||
| 23 | jclass clazz); | ||
| 24 | |||
| 25 | JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_IsRunning(JNIEnv* env, | ||
| 26 | jclass clazz); | ||
| 27 | |||
| 28 | JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_isHandheldOnly(JNIEnv* env, | ||
| 29 | jclass clazz); | ||
| 30 | |||
| 31 | JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_setDeviceType(JNIEnv* env, | ||
| 32 | jclass clazz, | ||
| 33 | jstring j_device, | ||
| 34 | jstring j_type); | ||
| 35 | |||
| 36 | JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadConnectEvent( | ||
| 37 | JNIEnv* env, jclass clazz, jstring j_device); | ||
| 38 | |||
| 39 | JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent( | ||
| 40 | JNIEnv* env, jclass clazz, jstring j_device); | ||
| 41 | |||
| 42 | JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadEvent( | ||
| 43 | JNIEnv* env, jclass clazz, jstring j_device, jint j_button, jint action); | ||
| 44 | |||
| 45 | JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMoveEvent( | ||
| 46 | JNIEnv* env, jclass clazz, jstring j_device, jint axis, jfloat x, jfloat y); | ||
| 47 | |||
| 48 | JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadAxisEvent( | ||
| 49 | JNIEnv* env, jclass clazz, jstring j_device, jint axis_id, jfloat axis_val); | ||
| 50 | |||
| 51 | JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag(JNIEnv* env, | ||
| 52 | jclass clazz, | ||
| 53 | jbyteArray j_data); | ||
| 54 | |||
| 55 | JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onRemoveNfcTag(JNIEnv* env, | ||
| 56 | jclass clazz); | ||
| 57 | |||
| 58 | JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchEvent(JNIEnv* env, | ||
| 59 | jclass clazz, | ||
| 60 | jfloat x, jfloat y, | ||
| 61 | jboolean pressed); | ||
| 62 | |||
| 63 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved(JNIEnv* env, jclass clazz, | ||
| 64 | jfloat x, jfloat y); | ||
| 65 | |||
| 66 | JNIEXPORT jbyteArray JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetIcon(JNIEnv* env, | ||
| 67 | jclass clazz, | ||
| 68 | jstring j_file); | ||
| 69 | |||
| 70 | JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetTitle(JNIEnv* env, jclass clazz, | ||
| 71 | jstring j_filename); | ||
| 72 | |||
| 73 | JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetDescription(JNIEnv* env, | ||
| 74 | jclass clazz, | ||
| 75 | jstring j_filename); | ||
| 76 | |||
| 77 | JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetGameId(JNIEnv* env, jclass clazz, | ||
| 78 | jstring j_filename); | ||
| 79 | |||
| 80 | JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetRegions(JNIEnv* env, | ||
| 81 | jclass clazz, | ||
| 82 | jstring j_filename); | ||
| 83 | |||
| 84 | JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetCompany(JNIEnv* env, | ||
| 85 | jclass clazz, | ||
| 86 | jstring j_filename); | ||
| 87 | |||
| 88 | JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetGitRevision(JNIEnv* env, | ||
| 89 | jclass clazz); | ||
| 90 | |||
| 91 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SetAppDirectory(JNIEnv* env, | ||
| 92 | jclass clazz, | ||
| 93 | jstring j_directory); | ||
| 94 | |||
| 95 | JNIEXPORT void JNICALL | ||
| 96 | Java_org_yuzu_yuzu_1emu_NativeLibrary_Java_org_yuzu_yuzu_1emu_NativeLibrary_InitializeGpuDriver( | ||
| 97 | JNIEnv* env, jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir, | ||
| 98 | jstring custom_driver_name, jstring file_redirect_dir); | ||
| 99 | |||
| 100 | JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_ReloadKeys(JNIEnv* env, | ||
| 101 | jclass clazz); | ||
| 102 | |||
| 103 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_SetSysDirectory( | ||
| 104 | JNIEnv* env, jclass clazz, jstring path_); | ||
| 105 | |||
| 106 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SetSysDirectory(JNIEnv* env, | ||
| 107 | jclass clazz, | ||
| 108 | jstring path); | ||
| 109 | |||
| 110 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_InitializeEmulation(JNIEnv* env, | ||
| 111 | jclass clazz); | ||
| 112 | |||
| 113 | JNIEXPORT jint JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_DefaultCPUCore(JNIEnv* env, | ||
| 114 | jclass clazz); | ||
| 115 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SetProfiling(JNIEnv* env, jclass clazz, | ||
| 116 | jboolean enable); | ||
| 117 | |||
| 118 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_WriteProfileResults(JNIEnv* env, | ||
| 119 | jclass clazz); | ||
| 120 | |||
| 121 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_NotifyOrientationChange( | ||
| 122 | JNIEnv* env, jclass clazz, jint layout_option, jint rotation); | ||
| 123 | |||
| 124 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_Run__Ljava_lang_String_2( | ||
| 125 | JNIEnv* env, jclass clazz, jstring j_path); | ||
| 126 | |||
| 127 | JNIEXPORT void JNICALL | ||
| 128 | Java_org_yuzu_yuzu_1emu_NativeLibrary_Run__Ljava_lang_String_2Ljava_lang_String_2Z( | ||
| 129 | JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate); | ||
| 130 | |||
| 131 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env, | ||
| 132 | jclass clazz, | ||
| 133 | jobject surf); | ||
| 134 | |||
| 135 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SurfaceDestroyed(JNIEnv* env, | ||
| 136 | jclass clazz); | ||
| 137 | |||
| 138 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_InitGameIni(JNIEnv* env, jclass clazz, | ||
| 139 | jstring j_game_id); | ||
| 140 | |||
| 141 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_ReloadSettings(JNIEnv* env, | ||
| 142 | jclass clazz); | ||
| 143 | |||
| 144 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SetUserSetting( | ||
| 145 | JNIEnv* env, jclass clazz, jstring j_game_id, jstring j_section, jstring j_key, | ||
| 146 | jstring j_value); | ||
| 147 | |||
| 148 | JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetUserSetting( | ||
| 149 | JNIEnv* env, jclass clazz, jstring game_id, jstring section, jstring key); | ||
| 150 | |||
| 151 | JNIEXPORT jdoubleArray JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetPerfStats(JNIEnv* env, | ||
| 152 | jclass clazz); | ||
| 153 | |||
| 154 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_LogDeviceInfo(JNIEnv* env, | ||
| 155 | jclass clazz); | ||
| 156 | |||
| 157 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SubmitInlineKeyboardText( | ||
| 158 | JNIEnv* env, jclass clazz, jstring j_text); | ||
| 159 | |||
| 160 | JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SubmitInlineKeyboardInput( | ||
| 161 | JNIEnv* env, jclass clazz, jint j_key_code); | ||
| 162 | |||
| 163 | #ifdef __cplusplus | ||
| 164 | } | ||
| 165 | #endif | ||
diff --git a/src/android/app/src/main/res/drawable/ic_pip_mute.xml b/src/android/app/src/main/res/drawable/ic_pip_mute.xml new file mode 100644 index 000000000..a271c5fe8 --- /dev/null +++ b/src/android/app/src/main/res/drawable/ic_pip_mute.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:viewportHeight="24" | ||
| 5 | android:viewportWidth="24"> | ||
| 6 | <path | ||
| 7 | android:fillColor="@android:color/white" | ||
| 8 | android:pathData="M7,9v6h4l5,5V4l-5,5H7z" /> | ||
| 9 | </vector> | ||
diff --git a/src/android/app/src/main/res/drawable/ic_pip_unmute.xml b/src/android/app/src/main/res/drawable/ic_pip_unmute.xml new file mode 100644 index 000000000..f7ed0862e --- /dev/null +++ b/src/android/app/src/main/res/drawable/ic_pip_unmute.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:viewportHeight="24" | ||
| 5 | android:viewportWidth="24"> | ||
| 6 | <path | ||
| 7 | android:fillColor="@android:color/white" | ||
| 8 | android:pathData="M3,9v6h4l5,5L12,4L7,9L3,9zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77s-2.99,-7.86 -7,-8.77z" /> | ||
| 9 | </vector> | ||
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index cc1d8c39d..af7450619 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml | |||
| @@ -104,12 +104,14 @@ | |||
| 104 | <string name="share_log_missing">No log file found</string> | 104 | <string name="share_log_missing">No log file found</string> |
| 105 | <string name="install_game_content">Install game content</string> | 105 | <string name="install_game_content">Install game content</string> |
| 106 | <string name="install_game_content_description">Install game updates or DLC</string> | 106 | <string name="install_game_content_description">Install game updates or DLC</string> |
| 107 | <string name="install_game_content_failure">Error installing file to NAND</string> | 107 | <string name="install_game_content_failure">Error installing file(s) to NAND</string> |
| 108 | <string name="install_game_content_failure_description">Game content installation failed. Please ensure content is valid and that the prod.keys file is installed.</string> | 108 | <string name="install_game_content_failure_description">Please ensure content(s) are valid and that the prod.keys file is installed.</string> |
| 109 | <string name="install_game_content_failure_base">Installation of base games isn\'t permitted in order to avoid possible conflicts. Please select an update or DLC instead.</string> | 109 | <string name="install_game_content_failure_base">Installation of base games isn\'t permitted in order to avoid possible conflicts.</string> |
| 110 | <string name="install_game_content_failure_file_extension">The selected file type is not supported. Only NSP and XCI content is supported for this action. Please verify the game content is valid.</string> | 110 | <string name="install_game_content_failure_file_extension">Only NSP and XCI content is supported. Please verify the game content(s) are valid.</string> |
| 111 | <string name="install_game_content_success">Game content installed successfully</string> | 111 | <string name="install_game_content_failed_count">%1$d installation error(s)</string> |
| 112 | <string name="install_game_content_success_overwrite">Game content was overwritten successfully</string> | 112 | <string name="install_game_content_success">Game content(s) installed successfully</string> |
| 113 | <string name="install_game_content_success_install">%1$d installed successfully</string> | ||
| 114 | <string name="install_game_content_success_overwrite">%1$d overwritten successfully</string> | ||
| 113 | <string name="install_game_content_help_link">https://yuzu-emu.org/help/quickstart/#dumping-installed-updates</string> | 115 | <string name="install_game_content_help_link">https://yuzu-emu.org/help/quickstart/#dumping-installed-updates</string> |
| 114 | 116 | ||
| 115 | <!-- About screen strings --> | 117 | <!-- About screen strings --> |
| @@ -270,6 +272,7 @@ | |||
| 270 | <string name="fatal_error">Fatal Error</string> | 272 | <string name="fatal_error">Fatal Error</string> |
| 271 | <string name="fatal_error_message">A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes and bugs.</string> | 273 | <string name="fatal_error_message">A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes and bugs.</string> |
| 272 | <string name="performance_warning">Turning off this setting will significantly reduce emulation performance! For the best experience, it is recommended that you leave this setting enabled.</string> | 274 | <string name="performance_warning">Turning off this setting will significantly reduce emulation performance! For the best experience, it is recommended that you leave this setting enabled.</string> |
| 275 | <string name="device_memory_inadequate">Device RAM: %1$s\nRecommended: %2$s</string> | ||
| 273 | 276 | ||
| 274 | <!-- Region Names --> | 277 | <!-- Region Names --> |
| 275 | <string name="region_japan">Japan</string> | 278 | <string name="region_japan">Japan</string> |
| @@ -300,6 +303,15 @@ | |||
| 300 | <string name="language_traditional_chinese">Traditional Chinese (æ£é«”䏿–‡)</string> | 303 | <string name="language_traditional_chinese">Traditional Chinese (æ£é«”䏿–‡)</string> |
| 301 | <string name="language_brazilian_portuguese">Brazilian Portuguese (Português do Brasil)</string> | 304 | <string name="language_brazilian_portuguese">Brazilian Portuguese (Português do Brasil)</string> |
| 302 | 305 | ||
| 306 | <!-- Memory Sizes --> | ||
| 307 | <string name="memory_byte">Byte</string> | ||
| 308 | <string name="memory_kilobyte">KB</string> | ||
| 309 | <string name="memory_megabyte">MB</string> | ||
| 310 | <string name="memory_gigabyte">GB</string> | ||
| 311 | <string name="memory_terabyte">TB</string> | ||
| 312 | <string name="memory_petabyte">PB</string> | ||
| 313 | <string name="memory_exabyte">EB</string> | ||
| 314 | |||
| 303 | <!-- Renderer APIs --> | 315 | <!-- Renderer APIs --> |
| 304 | <string name="renderer_vulkan">Vulkan</string> | 316 | <string name="renderer_vulkan">Vulkan</string> |
| 305 | <string name="renderer_none">None</string> | 317 | <string name="renderer_none">None</string> |
| @@ -387,6 +399,8 @@ | |||
| 387 | <string name="picture_in_picture_description">Minimize window when placed in the background</string> | 399 | <string name="picture_in_picture_description">Minimize window when placed in the background</string> |
| 388 | <string name="pause">Pause</string> | 400 | <string name="pause">Pause</string> |
| 389 | <string name="play">Play</string> | 401 | <string name="play">Play</string> |
| 402 | <string name="mute">Mute</string> | ||
| 403 | <string name="unmute">Unmute</string> | ||
| 390 | 404 | ||
| 391 | <!-- Licenses screen strings --> | 405 | <!-- Licenses screen strings --> |
| 392 | <string name="licenses">Licenses</string> | 406 | <string name="licenses">Licenses</string> |
diff --git a/src/android/gradle.properties b/src/android/gradle.properties index e2f278f33..4fca1b576 100644 --- a/src/android/gradle.properties +++ b/src/android/gradle.properties | |||
| @@ -15,3 +15,6 @@ android.useAndroidX=true | |||
| 15 | kotlin.code.style=official | 15 | kotlin.code.style=official |
| 16 | kotlin.parallel.tasks.in.project=true | 16 | kotlin.parallel.tasks.in.project=true |
| 17 | android.defaults.buildfeatures.buildconfig=true | 17 | android.defaults.buildfeatures.buildconfig=true |
| 18 | |||
| 19 | # Android Gradle plugin 8.0.2 | ||
| 20 | android.suppressUnsupportedCompileSdk=34 | ||
diff --git a/src/audio_core/device/audio_buffers.h b/src/audio_core/device/audio_buffers.h index 15082f6c6..5d8ed0ef7 100644 --- a/src/audio_core/device/audio_buffers.h +++ b/src/audio_core/device/audio_buffers.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <mutex> | 7 | #include <mutex> |
| 8 | #include <span> | 8 | #include <span> |
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | #include <boost/container/static_vector.hpp> | ||
| 10 | 11 | ||
| 11 | #include "audio_buffer.h" | 12 | #include "audio_buffer.h" |
| 12 | #include "audio_core/device/device_session.h" | 13 | #include "audio_core/device/device_session.h" |
| @@ -48,7 +49,7 @@ public: | |||
| 48 | * | 49 | * |
| 49 | * @param out_buffers - The buffers which were registered. | 50 | * @param out_buffers - The buffers which were registered. |
| 50 | */ | 51 | */ |
| 51 | void RegisterBuffers(std::vector<AudioBuffer>& out_buffers) { | 52 | void RegisterBuffers(boost::container::static_vector<AudioBuffer, N>& out_buffers) { |
| 52 | std::scoped_lock l{lock}; | 53 | std::scoped_lock l{lock}; |
| 53 | const s32 to_register{std::min(std::min(appended_count, BufferAppendLimit), | 54 | const s32 to_register{std::min(std::min(appended_count, BufferAppendLimit), |
| 54 | BufferAppendLimit - registered_count)}; | 55 | BufferAppendLimit - registered_count)}; |
| @@ -162,7 +163,8 @@ public: | |||
| 162 | * @param max_buffers - Maximum number of buffers to released. | 163 | * @param max_buffers - Maximum number of buffers to released. |
| 163 | * @return The number of buffers released. | 164 | * @return The number of buffers released. |
| 164 | */ | 165 | */ |
| 165 | u32 GetRegisteredAppendedBuffers(std::vector<AudioBuffer>& buffers_flushed, u32 max_buffers) { | 166 | u32 GetRegisteredAppendedBuffers( |
| 167 | boost::container::static_vector<AudioBuffer, N>& buffers_flushed, u32 max_buffers) { | ||
| 166 | std::scoped_lock l{lock}; | 168 | std::scoped_lock l{lock}; |
| 167 | if (registered_count + appended_count == 0) { | 169 | if (registered_count + appended_count == 0) { |
| 168 | return 0; | 170 | return 0; |
| @@ -270,7 +272,7 @@ public: | |||
| 270 | */ | 272 | */ |
| 271 | bool FlushBuffers(u32& buffers_released) { | 273 | bool FlushBuffers(u32& buffers_released) { |
| 272 | std::scoped_lock l{lock}; | 274 | std::scoped_lock l{lock}; |
| 273 | std::vector<AudioBuffer> buffers_flushed{}; | 275 | boost::container::static_vector<AudioBuffer, N> buffers_flushed{}; |
| 274 | 276 | ||
| 275 | buffers_released = GetRegisteredAppendedBuffers(buffers_flushed, append_limit); | 277 | buffers_released = GetRegisteredAppendedBuffers(buffers_flushed, append_limit); |
| 276 | 278 | ||
diff --git a/src/audio_core/device/device_session.cpp b/src/audio_core/device/device_session.cpp index b5c0ef0e6..86811fcb8 100644 --- a/src/audio_core/device/device_session.cpp +++ b/src/audio_core/device/device_session.cpp | |||
| @@ -79,7 +79,7 @@ void DeviceSession::ClearBuffers() { | |||
| 79 | } | 79 | } |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) const { | 82 | void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) { |
| 83 | for (const auto& buffer : buffers) { | 83 | for (const auto& buffer : buffers) { |
| 84 | Sink::SinkBuffer new_buffer{ | 84 | Sink::SinkBuffer new_buffer{ |
| 85 | .frames = buffer.size / (channel_count * sizeof(s16)), | 85 | .frames = buffer.size / (channel_count * sizeof(s16)), |
| @@ -88,13 +88,13 @@ void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) const { | |||
| 88 | .consumed = false, | 88 | .consumed = false, |
| 89 | }; | 89 | }; |
| 90 | 90 | ||
| 91 | tmp_samples.resize_destructive(buffer.size / sizeof(s16)); | ||
| 91 | if (type == Sink::StreamType::In) { | 92 | if (type == Sink::StreamType::In) { |
| 92 | std::vector<s16> samples{}; | 93 | stream->AppendBuffer(new_buffer, tmp_samples); |
| 93 | stream->AppendBuffer(new_buffer, samples); | ||
| 94 | } else { | 94 | } else { |
| 95 | std::vector<s16> samples(buffer.size / sizeof(s16)); | 95 | system.ApplicationMemory().ReadBlockUnsafe(buffer.samples, tmp_samples.data(), |
| 96 | system.ApplicationMemory().ReadBlockUnsafe(buffer.samples, samples.data(), buffer.size); | 96 | buffer.size); |
| 97 | stream->AppendBuffer(new_buffer, samples); | 97 | stream->AppendBuffer(new_buffer, tmp_samples); |
| 98 | } | 98 | } |
| 99 | } | 99 | } |
| 100 | } | 100 | } |
diff --git a/src/audio_core/device/device_session.h b/src/audio_core/device/device_session.h index 75f766c68..7d52f362d 100644 --- a/src/audio_core/device/device_session.h +++ b/src/audio_core/device/device_session.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | 10 | ||
| 11 | #include "audio_core/common/common.h" | 11 | #include "audio_core/common/common.h" |
| 12 | #include "audio_core/sink/sink.h" | 12 | #include "audio_core/sink/sink.h" |
| 13 | #include "common/scratch_buffer.h" | ||
| 13 | #include "core/hle/service/audio/errors.h" | 14 | #include "core/hle/service/audio/errors.h" |
| 14 | 15 | ||
| 15 | namespace Core { | 16 | namespace Core { |
| @@ -62,7 +63,7 @@ public: | |||
| 62 | * | 63 | * |
| 63 | * @param buffers - The buffers to play. | 64 | * @param buffers - The buffers to play. |
| 64 | */ | 65 | */ |
| 65 | void AppendBuffers(std::span<const AudioBuffer> buffers) const; | 66 | void AppendBuffers(std::span<const AudioBuffer> buffers); |
| 66 | 67 | ||
| 67 | /** | 68 | /** |
| 68 | * (Audio In only) Pop samples from the backend, and write them back to this buffer's address. | 69 | * (Audio In only) Pop samples from the backend, and write them back to this buffer's address. |
| @@ -146,8 +147,8 @@ private: | |||
| 146 | std::shared_ptr<Core::Timing::EventType> thread_event; | 147 | std::shared_ptr<Core::Timing::EventType> thread_event; |
| 147 | /// Is this session initialised? | 148 | /// Is this session initialised? |
| 148 | bool initialized{}; | 149 | bool initialized{}; |
| 149 | /// Buffer queue | 150 | /// Temporary sample buffer |
| 150 | std::vector<AudioBuffer> buffer_queue{}; | 151 | Common::ScratchBuffer<s16> tmp_samples{}; |
| 151 | }; | 152 | }; |
| 152 | 153 | ||
| 153 | } // namespace AudioCore | 154 | } // namespace AudioCore |
diff --git a/src/audio_core/in/audio_in_system.cpp b/src/audio_core/in/audio_in_system.cpp index e23e51758..579129121 100644 --- a/src/audio_core/in/audio_in_system.cpp +++ b/src/audio_core/in/audio_in_system.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <mutex> | 4 | #include <mutex> |
| 5 | |||
| 5 | #include "audio_core/audio_event.h" | 6 | #include "audio_core/audio_event.h" |
| 6 | #include "audio_core/audio_manager.h" | 7 | #include "audio_core/audio_manager.h" |
| 7 | #include "audio_core/in/audio_in_system.h" | 8 | #include "audio_core/in/audio_in_system.h" |
| @@ -89,7 +90,7 @@ Result System::Start() { | |||
| 89 | session->Start(); | 90 | session->Start(); |
| 90 | state = State::Started; | 91 | state = State::Started; |
| 91 | 92 | ||
| 92 | std::vector<AudioBuffer> buffers_to_flush{}; | 93 | boost::container::static_vector<AudioBuffer, BufferCount> buffers_to_flush{}; |
| 93 | buffers.RegisterBuffers(buffers_to_flush); | 94 | buffers.RegisterBuffers(buffers_to_flush); |
| 94 | session->AppendBuffers(buffers_to_flush); | 95 | session->AppendBuffers(buffers_to_flush); |
| 95 | session->SetRingSize(static_cast<u32>(buffers_to_flush.size())); | 96 | session->SetRingSize(static_cast<u32>(buffers_to_flush.size())); |
| @@ -134,7 +135,7 @@ bool System::AppendBuffer(const AudioInBuffer& buffer, const u64 tag) { | |||
| 134 | 135 | ||
| 135 | void System::RegisterBuffers() { | 136 | void System::RegisterBuffers() { |
| 136 | if (state == State::Started) { | 137 | if (state == State::Started) { |
| 137 | std::vector<AudioBuffer> registered_buffers{}; | 138 | boost::container::static_vector<AudioBuffer, BufferCount> registered_buffers{}; |
| 138 | buffers.RegisterBuffers(registered_buffers); | 139 | buffers.RegisterBuffers(registered_buffers); |
| 139 | session->AppendBuffers(registered_buffers); | 140 | session->AppendBuffers(registered_buffers); |
| 140 | } | 141 | } |
diff --git a/src/audio_core/out/audio_out_system.cpp b/src/audio_core/out/audio_out_system.cpp index bd13f7219..0adf64bd3 100644 --- a/src/audio_core/out/audio_out_system.cpp +++ b/src/audio_core/out/audio_out_system.cpp | |||
| @@ -89,7 +89,7 @@ Result System::Start() { | |||
| 89 | session->Start(); | 89 | session->Start(); |
| 90 | state = State::Started; | 90 | state = State::Started; |
| 91 | 91 | ||
| 92 | std::vector<AudioBuffer> buffers_to_flush{}; | 92 | boost::container::static_vector<AudioBuffer, BufferCount> buffers_to_flush{}; |
| 93 | buffers.RegisterBuffers(buffers_to_flush); | 93 | buffers.RegisterBuffers(buffers_to_flush); |
| 94 | session->AppendBuffers(buffers_to_flush); | 94 | session->AppendBuffers(buffers_to_flush); |
| 95 | session->SetRingSize(static_cast<u32>(buffers_to_flush.size())); | 95 | session->SetRingSize(static_cast<u32>(buffers_to_flush.size())); |
| @@ -134,7 +134,7 @@ bool System::AppendBuffer(const AudioOutBuffer& buffer, u64 tag) { | |||
| 134 | 134 | ||
| 135 | void System::RegisterBuffers() { | 135 | void System::RegisterBuffers() { |
| 136 | if (state == State::Started) { | 136 | if (state == State::Started) { |
| 137 | std::vector<AudioBuffer> registered_buffers{}; | 137 | boost::container::static_vector<AudioBuffer, BufferCount> registered_buffers{}; |
| 138 | buffers.RegisterBuffers(registered_buffers); | 138 | buffers.RegisterBuffers(registered_buffers); |
| 139 | session->AppendBuffers(registered_buffers); | 139 | session->AppendBuffers(registered_buffers); |
| 140 | } | 140 | } |
diff --git a/src/audio_core/renderer/adsp/adsp.cpp b/src/audio_core/renderer/adsp/adsp.cpp index 74772fc50..b1db31e93 100644 --- a/src/audio_core/renderer/adsp/adsp.cpp +++ b/src/audio_core/renderer/adsp/adsp.cpp | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/core_timing.h" | 9 | #include "core/core_timing.h" |
| 10 | #include "core/core_timing_util.h" | ||
| 11 | #include "core/memory.h" | 10 | #include "core/memory.h" |
| 12 | 11 | ||
| 13 | namespace AudioCore::AudioRenderer::ADSP { | 12 | namespace AudioCore::AudioRenderer::ADSP { |
diff --git a/src/audio_core/renderer/adsp/audio_renderer.cpp b/src/audio_core/renderer/adsp/audio_renderer.cpp index 8bc39f9f9..9ca716b60 100644 --- a/src/audio_core/renderer/adsp/audio_renderer.cpp +++ b/src/audio_core/renderer/adsp/audio_renderer.cpp | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | #include "common/thread.h" | 13 | #include "common/thread.h" |
| 14 | #include "core/core.h" | 14 | #include "core/core.h" |
| 15 | #include "core/core_timing.h" | 15 | #include "core/core_timing.h" |
| 16 | #include "core/core_timing_util.h" | ||
| 17 | 16 | ||
| 18 | MICROPROFILE_DEFINE(Audio_Renderer, "Audio", "DSP", MP_RGB(60, 19, 97)); | 17 | MICROPROFILE_DEFINE(Audio_Renderer, "Audio", "DSP", MP_RGB(60, 19, 97)); |
| 19 | 18 | ||
| @@ -144,6 +143,7 @@ void AudioRenderer::ThreadFunc(std::stop_token stop_token) { | |||
| 144 | 143 | ||
| 145 | mailbox->ADSPSendMessage(RenderMessage::AudioRenderer_InitializeOK); | 144 | mailbox->ADSPSendMessage(RenderMessage::AudioRenderer_InitializeOK); |
| 146 | 145 | ||
| 146 | // 0.12 seconds (2304000 / 19200000) | ||
| 147 | constexpr u64 max_process_time{2'304'000ULL}; | 147 | constexpr u64 max_process_time{2'304'000ULL}; |
| 148 | 148 | ||
| 149 | while (!stop_token.stop_requested()) { | 149 | while (!stop_token.stop_requested()) { |
| @@ -184,8 +184,7 @@ void AudioRenderer::ThreadFunc(std::stop_token stop_token) { | |||
| 184 | u64 max_time{max_process_time}; | 184 | u64 max_time{max_process_time}; |
| 185 | if (index == 1 && command_buffer.applet_resource_user_id == | 185 | if (index == 1 && command_buffer.applet_resource_user_id == |
| 186 | mailbox->GetCommandBuffer(0).applet_resource_user_id) { | 186 | mailbox->GetCommandBuffer(0).applet_resource_user_id) { |
| 187 | max_time = max_process_time - | 187 | max_time = max_process_time - render_times_taken[0]; |
| 188 | Core::Timing::CyclesToNs(render_times_taken[0]).count(); | ||
| 189 | if (render_times_taken[0] > max_process_time) { | 188 | if (render_times_taken[0] > max_process_time) { |
| 190 | max_time = 0; | 189 | max_time = 0; |
| 191 | } | 190 | } |
diff --git a/src/audio_core/renderer/adsp/command_list_processor.cpp b/src/audio_core/renderer/adsp/command_list_processor.cpp index 7a300d216..3a0f1ae38 100644 --- a/src/audio_core/renderer/adsp/command_list_processor.cpp +++ b/src/audio_core/renderer/adsp/command_list_processor.cpp | |||
| @@ -9,7 +9,6 @@ | |||
| 9 | #include "common/settings.h" | 9 | #include "common/settings.h" |
| 10 | #include "core/core.h" | 10 | #include "core/core.h" |
| 11 | #include "core/core_timing.h" | 11 | #include "core/core_timing.h" |
| 12 | #include "core/core_timing_util.h" | ||
| 13 | #include "core/memory.h" | 12 | #include "core/memory.h" |
| 14 | 13 | ||
| 15 | namespace AudioCore::AudioRenderer::ADSP { | 14 | namespace AudioCore::AudioRenderer::ADSP { |
diff --git a/src/audio_core/renderer/command/data_source/decode.cpp b/src/audio_core/renderer/command/data_source/decode.cpp index ff5d31bd6..f45933203 100644 --- a/src/audio_core/renderer/command/data_source/decode.cpp +++ b/src/audio_core/renderer/command/data_source/decode.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "audio_core/renderer/command/resample/resample.h" | 8 | #include "audio_core/renderer/command/resample/resample.h" |
| 9 | #include "common/fixed_point.h" | 9 | #include "common/fixed_point.h" |
| 10 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 11 | #include "common/scratch_buffer.h" | ||
| 11 | #include "core/memory.h" | 12 | #include "core/memory.h" |
| 12 | 13 | ||
| 13 | namespace AudioCore::AudioRenderer { | 14 | namespace AudioCore::AudioRenderer { |
| @@ -27,6 +28,7 @@ constexpr std::array<u8, 3> PitchBySrcQuality = {4, 8, 4}; | |||
| 27 | template <typename T> | 28 | template <typename T> |
| 28 | static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer, | 29 | static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer, |
| 29 | const DecodeArg& req) { | 30 | const DecodeArg& req) { |
| 31 | std::array<T, TempBufferSize> tmp_samples{}; | ||
| 30 | constexpr s32 min{std::numeric_limits<s16>::min()}; | 32 | constexpr s32 min{std::numeric_limits<s16>::min()}; |
| 31 | constexpr s32 max{std::numeric_limits<s16>::max()}; | 33 | constexpr s32 max{std::numeric_limits<s16>::max()}; |
| 32 | 34 | ||
| @@ -49,18 +51,17 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer, | |||
| 49 | const u64 size{channel_count * samples_to_decode}; | 51 | const u64 size{channel_count * samples_to_decode}; |
| 50 | const u64 size_bytes{size * sizeof(T)}; | 52 | const u64 size_bytes{size * sizeof(T)}; |
| 51 | 53 | ||
| 52 | std::vector<T> samples(size); | 54 | memory.ReadBlockUnsafe(source, tmp_samples.data(), size_bytes); |
| 53 | memory.ReadBlockUnsafe(source, samples.data(), size_bytes); | ||
| 54 | 55 | ||
| 55 | if constexpr (std::is_floating_point_v<T>) { | 56 | if constexpr (std::is_floating_point_v<T>) { |
| 56 | for (u32 i = 0; i < samples_to_decode; i++) { | 57 | for (u32 i = 0; i < samples_to_decode; i++) { |
| 57 | auto sample{static_cast<s32>(samples[i * channel_count + req.target_channel] * | 58 | auto sample{static_cast<s32>(tmp_samples[i * channel_count + req.target_channel] * |
| 58 | std::numeric_limits<s16>::max())}; | 59 | std::numeric_limits<s16>::max())}; |
| 59 | out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max)); | 60 | out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max)); |
| 60 | } | 61 | } |
| 61 | } else { | 62 | } else { |
| 62 | for (u32 i = 0; i < samples_to_decode; i++) { | 63 | for (u32 i = 0; i < samples_to_decode; i++) { |
| 63 | out_buffer[i] = samples[i * channel_count + req.target_channel]; | 64 | out_buffer[i] = tmp_samples[i * channel_count + req.target_channel]; |
| 64 | } | 65 | } |
| 65 | } | 66 | } |
| 66 | } break; | 67 | } break; |
| @@ -73,17 +74,16 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer, | |||
| 73 | } | 74 | } |
| 74 | 75 | ||
| 75 | const VAddr source{req.buffer + ((req.start_offset + req.offset) * sizeof(T))}; | 76 | const VAddr source{req.buffer + ((req.start_offset + req.offset) * sizeof(T))}; |
| 76 | std::vector<T> samples(samples_to_decode); | 77 | memory.ReadBlockUnsafe(source, tmp_samples.data(), samples_to_decode * sizeof(T)); |
| 77 | memory.ReadBlockUnsafe(source, samples.data(), samples_to_decode * sizeof(T)); | ||
| 78 | 78 | ||
| 79 | if constexpr (std::is_floating_point_v<T>) { | 79 | if constexpr (std::is_floating_point_v<T>) { |
| 80 | for (u32 i = 0; i < samples_to_decode; i++) { | 80 | for (u32 i = 0; i < samples_to_decode; i++) { |
| 81 | auto sample{static_cast<s32>(samples[i * channel_count + req.target_channel] * | 81 | auto sample{static_cast<s32>(tmp_samples[i * channel_count + req.target_channel] * |
| 82 | std::numeric_limits<s16>::max())}; | 82 | std::numeric_limits<s16>::max())}; |
| 83 | out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max)); | 83 | out_buffer[i] = static_cast<s16>(std::clamp(sample, min, max)); |
| 84 | } | 84 | } |
| 85 | } else { | 85 | } else { |
| 86 | std::memcpy(out_buffer.data(), samples.data(), samples_to_decode * sizeof(s16)); | 86 | std::memcpy(out_buffer.data(), tmp_samples.data(), samples_to_decode * sizeof(s16)); |
| 87 | } | 87 | } |
| 88 | break; | 88 | break; |
| 89 | } | 89 | } |
| @@ -101,6 +101,7 @@ static u32 DecodePcm(Core::Memory::Memory& memory, std::span<s16> out_buffer, | |||
| 101 | */ | 101 | */ |
| 102 | static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer, | 102 | static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer, |
| 103 | const DecodeArg& req) { | 103 | const DecodeArg& req) { |
| 104 | std::array<u8, TempBufferSize> wavebuffer{}; | ||
| 104 | constexpr u32 SamplesPerFrame{14}; | 105 | constexpr u32 SamplesPerFrame{14}; |
| 105 | constexpr u32 NibblesPerFrame{16}; | 106 | constexpr u32 NibblesPerFrame{16}; |
| 106 | 107 | ||
| @@ -138,9 +139,7 @@ static u32 DecodeAdpcm(Core::Memory::Memory& memory, std::span<s16> out_buffer, | |||
| 138 | } | 139 | } |
| 139 | 140 | ||
| 140 | const auto size{std::max((samples_to_process / 8U) * SamplesPerFrame, 8U)}; | 141 | const auto size{std::max((samples_to_process / 8U) * SamplesPerFrame, 8U)}; |
| 141 | std::vector<u8> wavebuffer(size); | 142 | memory.ReadBlockUnsafe(req.buffer + position_in_frame / 2, wavebuffer.data(), size); |
| 142 | memory.ReadBlockUnsafe(req.buffer + position_in_frame / 2, wavebuffer.data(), | ||
| 143 | wavebuffer.size()); | ||
| 144 | 143 | ||
| 145 | auto context{req.adpcm_context}; | 144 | auto context{req.adpcm_context}; |
| 146 | auto header{context->header}; | 145 | auto header{context->header}; |
| @@ -258,7 +257,7 @@ void DecodeFromWaveBuffers(Core::Memory::Memory& memory, const DecodeFromWaveBuf | |||
| 258 | u32 offset{voice_state.offset}; | 257 | u32 offset{voice_state.offset}; |
| 259 | 258 | ||
| 260 | auto output_buffer{args.output}; | 259 | auto output_buffer{args.output}; |
| 261 | std::vector<s16> temp_buffer(TempBufferSize, 0); | 260 | std::array<s16, TempBufferSize> temp_buffer{}; |
| 262 | 261 | ||
| 263 | while (remaining_sample_count > 0) { | 262 | while (remaining_sample_count > 0) { |
| 264 | const auto samples_to_write{std::min(remaining_sample_count, max_remaining_sample_count)}; | 263 | const auto samples_to_write{std::min(remaining_sample_count, max_remaining_sample_count)}; |
diff --git a/src/audio_core/renderer/command/effect/compressor.cpp b/src/audio_core/renderer/command/effect/compressor.cpp index 7229618e8..ee9b68d5b 100644 --- a/src/audio_core/renderer/command/effect/compressor.cpp +++ b/src/audio_core/renderer/command/effect/compressor.cpp | |||
| @@ -44,8 +44,8 @@ static void InitializeCompressorEffect(const CompressorInfo::ParameterVersion2& | |||
| 44 | 44 | ||
| 45 | static void ApplyCompressorEffect(const CompressorInfo::ParameterVersion2& params, | 45 | static void ApplyCompressorEffect(const CompressorInfo::ParameterVersion2& params, |
| 46 | CompressorInfo::State& state, bool enabled, | 46 | CompressorInfo::State& state, bool enabled, |
| 47 | std::vector<std::span<const s32>> input_buffers, | 47 | std::span<std::span<const s32>> input_buffers, |
| 48 | std::vector<std::span<s32>> output_buffers, u32 sample_count) { | 48 | std::span<std::span<s32>> output_buffers, u32 sample_count) { |
| 49 | if (enabled) { | 49 | if (enabled) { |
| 50 | auto state_00{state.unk_00}; | 50 | auto state_00{state.unk_00}; |
| 51 | auto state_04{state.unk_04}; | 51 | auto state_04{state.unk_04}; |
| @@ -124,8 +124,8 @@ void CompressorCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& | |||
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | void CompressorCommand::Process(const ADSP::CommandListProcessor& processor) { | 126 | void CompressorCommand::Process(const ADSP::CommandListProcessor& processor) { |
| 127 | std::vector<std::span<const s32>> input_buffers(parameter.channel_count); | 127 | std::array<std::span<const s32>, MaxChannels> input_buffers{}; |
| 128 | std::vector<std::span<s32>> output_buffers(parameter.channel_count); | 128 | std::array<std::span<s32>, MaxChannels> output_buffers{}; |
| 129 | 129 | ||
| 130 | for (s16 i = 0; i < parameter.channel_count; i++) { | 130 | for (s16 i = 0; i < parameter.channel_count; i++) { |
| 131 | input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, | 131 | input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, |
diff --git a/src/audio_core/renderer/command/effect/delay.cpp b/src/audio_core/renderer/command/effect/delay.cpp index a4e408d40..e536cbb1e 100644 --- a/src/audio_core/renderer/command/effect/delay.cpp +++ b/src/audio_core/renderer/command/effect/delay.cpp | |||
| @@ -51,7 +51,7 @@ static void InitializeDelayEffect(const DelayInfo::ParameterVersion1& params, | |||
| 51 | state.delay_lines[channel].sample_count_max = sample_count_max.to_int_floor(); | 51 | state.delay_lines[channel].sample_count_max = sample_count_max.to_int_floor(); |
| 52 | state.delay_lines[channel].sample_count = sample_count.to_int_floor(); | 52 | state.delay_lines[channel].sample_count = sample_count.to_int_floor(); |
| 53 | state.delay_lines[channel].buffer.resize(state.delay_lines[channel].sample_count, 0); | 53 | state.delay_lines[channel].buffer.resize(state.delay_lines[channel].sample_count, 0); |
| 54 | if (state.delay_lines[channel].buffer.size() == 0) { | 54 | if (state.delay_lines[channel].sample_count == 0) { |
| 55 | state.delay_lines[channel].buffer.push_back(0); | 55 | state.delay_lines[channel].buffer.push_back(0); |
| 56 | } | 56 | } |
| 57 | state.delay_lines[channel].buffer_pos = 0; | 57 | state.delay_lines[channel].buffer_pos = 0; |
| @@ -74,8 +74,8 @@ static void InitializeDelayEffect(const DelayInfo::ParameterVersion1& params, | |||
| 74 | */ | 74 | */ |
| 75 | template <size_t NumChannels> | 75 | template <size_t NumChannels> |
| 76 | static void ApplyDelay(const DelayInfo::ParameterVersion1& params, DelayInfo::State& state, | 76 | static void ApplyDelay(const DelayInfo::ParameterVersion1& params, DelayInfo::State& state, |
| 77 | std::vector<std::span<const s32>>& inputs, | 77 | std::span<std::span<const s32>> inputs, std::span<std::span<s32>> outputs, |
| 78 | std::vector<std::span<s32>>& outputs, const u32 sample_count) { | 78 | const u32 sample_count) { |
| 79 | for (u32 sample_index = 0; sample_index < sample_count; sample_index++) { | 79 | for (u32 sample_index = 0; sample_index < sample_count; sample_index++) { |
| 80 | std::array<Common::FixedPoint<50, 14>, NumChannels> input_samples{}; | 80 | std::array<Common::FixedPoint<50, 14>, NumChannels> input_samples{}; |
| 81 | for (u32 channel = 0; channel < NumChannels; channel++) { | 81 | for (u32 channel = 0; channel < NumChannels; channel++) { |
| @@ -153,8 +153,8 @@ static void ApplyDelay(const DelayInfo::ParameterVersion1& params, DelayInfo::St | |||
| 153 | * @param sample_count - Number of samples to process. | 153 | * @param sample_count - Number of samples to process. |
| 154 | */ | 154 | */ |
| 155 | static void ApplyDelayEffect(const DelayInfo::ParameterVersion1& params, DelayInfo::State& state, | 155 | static void ApplyDelayEffect(const DelayInfo::ParameterVersion1& params, DelayInfo::State& state, |
| 156 | const bool enabled, std::vector<std::span<const s32>>& inputs, | 156 | const bool enabled, std::span<std::span<const s32>> inputs, |
| 157 | std::vector<std::span<s32>>& outputs, const u32 sample_count) { | 157 | std::span<std::span<s32>> outputs, const u32 sample_count) { |
| 158 | 158 | ||
| 159 | if (!IsChannelCountValid(params.channel_count)) { | 159 | if (!IsChannelCountValid(params.channel_count)) { |
| 160 | LOG_ERROR(Service_Audio, "Invalid delay channels {}", params.channel_count); | 160 | LOG_ERROR(Service_Audio, "Invalid delay channels {}", params.channel_count); |
| @@ -208,8 +208,8 @@ void DelayCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& proce | |||
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | void DelayCommand::Process(const ADSP::CommandListProcessor& processor) { | 210 | void DelayCommand::Process(const ADSP::CommandListProcessor& processor) { |
| 211 | std::vector<std::span<const s32>> input_buffers(parameter.channel_count); | 211 | std::array<std::span<const s32>, MaxChannels> input_buffers{}; |
| 212 | std::vector<std::span<s32>> output_buffers(parameter.channel_count); | 212 | std::array<std::span<s32>, MaxChannels> output_buffers{}; |
| 213 | 213 | ||
| 214 | for (s16 i = 0; i < parameter.channel_count; i++) { | 214 | for (s16 i = 0; i < parameter.channel_count; i++) { |
| 215 | input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, | 215 | input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, |
diff --git a/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp b/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp index 27d8b9844..d2bfb67cc 100644 --- a/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp +++ b/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp | |||
| @@ -408,8 +408,8 @@ void I3dl2ReverbCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& | |||
| 408 | } | 408 | } |
| 409 | 409 | ||
| 410 | void I3dl2ReverbCommand::Process(const ADSP::CommandListProcessor& processor) { | 410 | void I3dl2ReverbCommand::Process(const ADSP::CommandListProcessor& processor) { |
| 411 | std::vector<std::span<const s32>> input_buffers(parameter.channel_count); | 411 | std::array<std::span<const s32>, MaxChannels> input_buffers{}; |
| 412 | std::vector<std::span<s32>> output_buffers(parameter.channel_count); | 412 | std::array<std::span<s32>, MaxChannels> output_buffers{}; |
| 413 | 413 | ||
| 414 | for (u32 i = 0; i < parameter.channel_count; i++) { | 414 | for (u32 i = 0; i < parameter.channel_count; i++) { |
| 415 | input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, | 415 | input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, |
diff --git a/src/audio_core/renderer/command/effect/light_limiter.cpp b/src/audio_core/renderer/command/effect/light_limiter.cpp index e8fb0e2fc..4161a9821 100644 --- a/src/audio_core/renderer/command/effect/light_limiter.cpp +++ b/src/audio_core/renderer/command/effect/light_limiter.cpp | |||
| @@ -47,8 +47,8 @@ static void InitializeLightLimiterEffect(const LightLimiterInfo::ParameterVersio | |||
| 47 | */ | 47 | */ |
| 48 | static void ApplyLightLimiterEffect(const LightLimiterInfo::ParameterVersion2& params, | 48 | static void ApplyLightLimiterEffect(const LightLimiterInfo::ParameterVersion2& params, |
| 49 | LightLimiterInfo::State& state, const bool enabled, | 49 | LightLimiterInfo::State& state, const bool enabled, |
| 50 | std::vector<std::span<const s32>>& inputs, | 50 | std::span<std::span<const s32>> inputs, |
| 51 | std::vector<std::span<s32>>& outputs, const u32 sample_count, | 51 | std::span<std::span<s32>> outputs, const u32 sample_count, |
| 52 | LightLimiterInfo::StatisticsInternal* statistics) { | 52 | LightLimiterInfo::StatisticsInternal* statistics) { |
| 53 | constexpr s64 min{std::numeric_limits<s32>::min()}; | 53 | constexpr s64 min{std::numeric_limits<s32>::min()}; |
| 54 | constexpr s64 max{std::numeric_limits<s32>::max()}; | 54 | constexpr s64 max{std::numeric_limits<s32>::max()}; |
| @@ -147,8 +147,8 @@ void LightLimiterVersion1Command::Dump([[maybe_unused]] const ADSP::CommandListP | |||
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | void LightLimiterVersion1Command::Process(const ADSP::CommandListProcessor& processor) { | 149 | void LightLimiterVersion1Command::Process(const ADSP::CommandListProcessor& processor) { |
| 150 | std::vector<std::span<const s32>> input_buffers(parameter.channel_count); | 150 | std::array<std::span<const s32>, MaxChannels> input_buffers{}; |
| 151 | std::vector<std::span<s32>> output_buffers(parameter.channel_count); | 151 | std::array<std::span<s32>, MaxChannels> output_buffers{}; |
| 152 | 152 | ||
| 153 | for (u32 i = 0; i < parameter.channel_count; i++) { | 153 | for (u32 i = 0; i < parameter.channel_count; i++) { |
| 154 | input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, | 154 | input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, |
| @@ -190,8 +190,8 @@ void LightLimiterVersion2Command::Dump([[maybe_unused]] const ADSP::CommandListP | |||
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | void LightLimiterVersion2Command::Process(const ADSP::CommandListProcessor& processor) { | 192 | void LightLimiterVersion2Command::Process(const ADSP::CommandListProcessor& processor) { |
| 193 | std::vector<std::span<const s32>> input_buffers(parameter.channel_count); | 193 | std::array<std::span<const s32>, MaxChannels> input_buffers{}; |
| 194 | std::vector<std::span<s32>> output_buffers(parameter.channel_count); | 194 | std::array<std::span<s32>, MaxChannels> output_buffers{}; |
| 195 | 195 | ||
| 196 | for (u32 i = 0; i < parameter.channel_count; i++) { | 196 | for (u32 i = 0; i < parameter.channel_count; i++) { |
| 197 | input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, | 197 | input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, |
diff --git a/src/audio_core/renderer/command/effect/reverb.cpp b/src/audio_core/renderer/command/effect/reverb.cpp index 8b9b65214..fc2f15a5e 100644 --- a/src/audio_core/renderer/command/effect/reverb.cpp +++ b/src/audio_core/renderer/command/effect/reverb.cpp | |||
| @@ -250,8 +250,8 @@ static Common::FixedPoint<50, 14> Axfx2AllPassTick(ReverbInfo::ReverbDelayLine& | |||
| 250 | */ | 250 | */ |
| 251 | template <size_t NumChannels> | 251 | template <size_t NumChannels> |
| 252 | static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, ReverbInfo::State& state, | 252 | static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, ReverbInfo::State& state, |
| 253 | std::vector<std::span<const s32>>& inputs, | 253 | std::span<std::span<const s32>> inputs, |
| 254 | std::vector<std::span<s32>>& outputs, const u32 sample_count) { | 254 | std::span<std::span<s32>> outputs, const u32 sample_count) { |
| 255 | static constexpr std::array<u8, ReverbInfo::MaxDelayTaps> OutTapIndexes1Ch{ | 255 | static constexpr std::array<u8, ReverbInfo::MaxDelayTaps> OutTapIndexes1Ch{ |
| 256 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 256 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 257 | }; | 257 | }; |
| @@ -369,8 +369,8 @@ static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, Rever | |||
| 369 | * @param sample_count - Number of samples to process. | 369 | * @param sample_count - Number of samples to process. |
| 370 | */ | 370 | */ |
| 371 | static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, ReverbInfo::State& state, | 371 | static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, ReverbInfo::State& state, |
| 372 | const bool enabled, std::vector<std::span<const s32>>& inputs, | 372 | const bool enabled, std::span<std::span<const s32>> inputs, |
| 373 | std::vector<std::span<s32>>& outputs, const u32 sample_count) { | 373 | std::span<std::span<s32>> outputs, const u32 sample_count) { |
| 374 | if (enabled) { | 374 | if (enabled) { |
| 375 | switch (params.channel_count) { | 375 | switch (params.channel_count) { |
| 376 | case 0: | 376 | case 0: |
| @@ -412,8 +412,8 @@ void ReverbCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& proc | |||
| 412 | } | 412 | } |
| 413 | 413 | ||
| 414 | void ReverbCommand::Process(const ADSP::CommandListProcessor& processor) { | 414 | void ReverbCommand::Process(const ADSP::CommandListProcessor& processor) { |
| 415 | std::vector<std::span<const s32>> input_buffers(parameter.channel_count); | 415 | std::array<std::span<const s32>, MaxChannels> input_buffers{}; |
| 416 | std::vector<std::span<s32>> output_buffers(parameter.channel_count); | 416 | std::array<std::span<s32>, MaxChannels> output_buffers{}; |
| 417 | 417 | ||
| 418 | for (u32 i = 0; i < parameter.channel_count; i++) { | 418 | for (u32 i = 0; i < parameter.channel_count; i++) { |
| 419 | input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, | 419 | input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count, |
diff --git a/src/audio_core/renderer/command/performance/performance.cpp b/src/audio_core/renderer/command/performance/performance.cpp index 985958b03..4a881547f 100644 --- a/src/audio_core/renderer/command/performance/performance.cpp +++ b/src/audio_core/renderer/command/performance/performance.cpp | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #include "audio_core/renderer/command/performance/performance.h" | 5 | #include "audio_core/renderer/command/performance/performance.h" |
| 6 | #include "core/core.h" | 6 | #include "core/core.h" |
| 7 | #include "core/core_timing.h" | 7 | #include "core/core_timing.h" |
| 8 | #include "core/core_timing_util.h" | ||
| 9 | 8 | ||
| 10 | namespace AudioCore::AudioRenderer { | 9 | namespace AudioCore::AudioRenderer { |
| 11 | 10 | ||
| @@ -18,20 +17,18 @@ void PerformanceCommand::Process(const ADSP::CommandListProcessor& processor) { | |||
| 18 | auto base{entry_address.translated_address}; | 17 | auto base{entry_address.translated_address}; |
| 19 | if (state == PerformanceState::Start) { | 18 | if (state == PerformanceState::Start) { |
| 20 | auto start_time_ptr{reinterpret_cast<u32*>(base + entry_address.entry_start_time_offset)}; | 19 | auto start_time_ptr{reinterpret_cast<u32*>(base + entry_address.entry_start_time_offset)}; |
| 21 | *start_time_ptr = static_cast<u32>( | 20 | *start_time_ptr = |
| 22 | Core::Timing::CyclesToUs(processor.system->CoreTiming().GetClockTicks() - | 21 | static_cast<u32>(processor.system->CoreTiming().GetClockTicks() - processor.start_time - |
| 23 | processor.start_time - processor.current_processing_time) | 22 | processor.current_processing_time); |
| 24 | .count()); | ||
| 25 | } else if (state == PerformanceState::Stop) { | 23 | } else if (state == PerformanceState::Stop) { |
| 26 | auto processed_time_ptr{ | 24 | auto processed_time_ptr{ |
| 27 | reinterpret_cast<u32*>(base + entry_address.entry_processed_time_offset)}; | 25 | reinterpret_cast<u32*>(base + entry_address.entry_processed_time_offset)}; |
| 28 | auto entry_count_ptr{ | 26 | auto entry_count_ptr{ |
| 29 | reinterpret_cast<u32*>(base + entry_address.header_entry_count_offset)}; | 27 | reinterpret_cast<u32*>(base + entry_address.header_entry_count_offset)}; |
| 30 | 28 | ||
| 31 | *processed_time_ptr = static_cast<u32>( | 29 | *processed_time_ptr = |
| 32 | Core::Timing::CyclesToUs(processor.system->CoreTiming().GetClockTicks() - | 30 | static_cast<u32>(processor.system->CoreTiming().GetClockTicks() - processor.start_time - |
| 33 | processor.start_time - processor.current_processing_time) | 31 | processor.current_processing_time); |
| 34 | .count()); | ||
| 35 | (*entry_count_ptr)++; | 32 | (*entry_count_ptr)++; |
| 36 | } | 33 | } |
| 37 | } | 34 | } |
diff --git a/src/audio_core/renderer/command/sink/circular_buffer.cpp b/src/audio_core/renderer/command/sink/circular_buffer.cpp index ded5afc94..e2ce59792 100644 --- a/src/audio_core/renderer/command/sink/circular_buffer.cpp +++ b/src/audio_core/renderer/command/sink/circular_buffer.cpp | |||
| @@ -24,7 +24,7 @@ void CircularBufferSinkCommand::Process(const ADSP::CommandListProcessor& proces | |||
| 24 | constexpr s32 min{std::numeric_limits<s16>::min()}; | 24 | constexpr s32 min{std::numeric_limits<s16>::min()}; |
| 25 | constexpr s32 max{std::numeric_limits<s16>::max()}; | 25 | constexpr s32 max{std::numeric_limits<s16>::max()}; |
| 26 | 26 | ||
| 27 | std::vector<s16> output(processor.sample_count); | 27 | std::array<s16, TargetSampleCount * MaxChannels> output{}; |
| 28 | for (u32 channel = 0; channel < input_count; channel++) { | 28 | for (u32 channel = 0; channel < input_count; channel++) { |
| 29 | auto input{processor.mix_buffers.subspan(inputs[channel] * processor.sample_count, | 29 | auto input{processor.mix_buffers.subspan(inputs[channel] * processor.sample_count, |
| 30 | processor.sample_count)}; | 30 | processor.sample_count)}; |
| @@ -33,7 +33,7 @@ void CircularBufferSinkCommand::Process(const ADSP::CommandListProcessor& proces | |||
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | processor.memory->WriteBlockUnsafe(address + pos, output.data(), | 35 | processor.memory->WriteBlockUnsafe(address + pos, output.data(), |
| 36 | output.size() * sizeof(s16)); | 36 | processor.sample_count * sizeof(s16)); |
| 37 | pos += static_cast<u32>(processor.sample_count * sizeof(s16)); | 37 | pos += static_cast<u32>(processor.sample_count * sizeof(s16)); |
| 38 | if (pos >= size) { | 38 | if (pos >= size) { |
| 39 | pos = 0; | 39 | pos = 0; |
diff --git a/src/audio_core/renderer/command/sink/device.cpp b/src/audio_core/renderer/command/sink/device.cpp index e88372a75..5f74dd7ad 100644 --- a/src/audio_core/renderer/command/sink/device.cpp +++ b/src/audio_core/renderer/command/sink/device.cpp | |||
| @@ -33,8 +33,7 @@ void DeviceSinkCommand::Process(const ADSP::CommandListProcessor& processor) { | |||
| 33 | .consumed{false}, | 33 | .consumed{false}, |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | std::vector<s16> samples(out_buffer.frames * input_count); | 36 | std::array<s16, TargetSampleCount * MaxChannels> samples{}; |
| 37 | |||
| 38 | for (u32 channel = 0; channel < input_count; channel++) { | 37 | for (u32 channel = 0; channel < input_count; channel++) { |
| 39 | const auto offset{inputs[channel] * out_buffer.frames}; | 38 | const auto offset{inputs[channel] * out_buffer.frames}; |
| 40 | 39 | ||
| @@ -45,7 +44,7 @@ void DeviceSinkCommand::Process(const ADSP::CommandListProcessor& processor) { | |||
| 45 | } | 44 | } |
| 46 | 45 | ||
| 47 | out_buffer.tag = reinterpret_cast<u64>(samples.data()); | 46 | out_buffer.tag = reinterpret_cast<u64>(samples.data()); |
| 48 | stream->AppendBuffer(out_buffer, samples); | 47 | stream->AppendBuffer(out_buffer, {samples.data(), out_buffer.frames * input_count}); |
| 49 | 48 | ||
| 50 | if (stream->IsPaused()) { | 49 | if (stream->IsPaused()) { |
| 51 | stream->Start(); | 50 | stream->Start(); |
diff --git a/src/audio_core/renderer/mix/mix_context.cpp b/src/audio_core/renderer/mix/mix_context.cpp index 35b748ede..3a18ae7c2 100644 --- a/src/audio_core/renderer/mix/mix_context.cpp +++ b/src/audio_core/renderer/mix/mix_context.cpp | |||
| @@ -125,10 +125,10 @@ bool MixContext::TSortInfo(const SplitterContext& splitter_context) { | |||
| 125 | return false; | 125 | return false; |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | std::vector<s32> sorted_results{node_states.GetSortedResuls()}; | 128 | auto sorted_results{node_states.GetSortedResuls()}; |
| 129 | const auto result_size{std::min(count, static_cast<s32>(sorted_results.size()))}; | 129 | const auto result_size{std::min(count, static_cast<s32>(sorted_results.second))}; |
| 130 | for (s32 i = 0; i < result_size; i++) { | 130 | for (s32 i = 0; i < result_size; i++) { |
| 131 | sorted_mix_infos[i] = &mix_infos[sorted_results[i]]; | 131 | sorted_mix_infos[i] = &mix_infos[sorted_results.first[i]]; |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | CalcMixBufferOffset(); | 134 | CalcMixBufferOffset(); |
diff --git a/src/audio_core/renderer/nodes/node_states.cpp b/src/audio_core/renderer/nodes/node_states.cpp index 1821a51e6..b7a44a54c 100644 --- a/src/audio_core/renderer/nodes/node_states.cpp +++ b/src/audio_core/renderer/nodes/node_states.cpp | |||
| @@ -134,8 +134,8 @@ u32 NodeStates::GetNodeCount() const { | |||
| 134 | return node_count; | 134 | return node_count; |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | std::vector<s32> NodeStates::GetSortedResuls() const { | 137 | std::pair<std::span<u32>::reverse_iterator, size_t> NodeStates::GetSortedResuls() const { |
| 138 | return {results.rbegin(), results.rbegin() + result_pos}; | 138 | return {results.rbegin(), result_pos}; |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | } // namespace AudioCore::AudioRenderer | 141 | } // namespace AudioCore::AudioRenderer |
diff --git a/src/audio_core/renderer/nodes/node_states.h b/src/audio_core/renderer/nodes/node_states.h index 94b1d1254..e768cd4b5 100644 --- a/src/audio_core/renderer/nodes/node_states.h +++ b/src/audio_core/renderer/nodes/node_states.h | |||
| @@ -175,7 +175,7 @@ public: | |||
| 175 | * | 175 | * |
| 176 | * @return Vector of nodes in reverse order. | 176 | * @return Vector of nodes in reverse order. |
| 177 | */ | 177 | */ |
| 178 | std::vector<s32> GetSortedResuls() const; | 178 | std::pair<std::span<u32>::reverse_iterator, size_t> GetSortedResuls() const; |
| 179 | 179 | ||
| 180 | private: | 180 | private: |
| 181 | /// Number of nodes in the graph | 181 | /// Number of nodes in the graph |
diff --git a/src/audio_core/renderer/system.cpp b/src/audio_core/renderer/system.cpp index 53b258c4f..a23627472 100644 --- a/src/audio_core/renderer/system.cpp +++ b/src/audio_core/renderer/system.cpp | |||
| @@ -444,6 +444,7 @@ Result System::Update(std::span<const u8> input, std::span<u8> performance, std: | |||
| 444 | std::scoped_lock l{lock}; | 444 | std::scoped_lock l{lock}; |
| 445 | 445 | ||
| 446 | const auto start_time{core.CoreTiming().GetClockTicks()}; | 446 | const auto start_time{core.CoreTiming().GetClockTicks()}; |
| 447 | std::memset(output.data(), 0, output.size()); | ||
| 447 | 448 | ||
| 448 | InfoUpdater info_updater(input, output, process_handle, behavior); | 449 | InfoUpdater info_updater(input, output, process_handle, behavior); |
| 449 | 450 | ||
diff --git a/src/audio_core/sink/null_sink.h b/src/audio_core/sink/null_sink.h index 1215d3cd2..b6b43c93e 100644 --- a/src/audio_core/sink/null_sink.h +++ b/src/audio_core/sink/null_sink.h | |||
| @@ -20,7 +20,7 @@ public: | |||
| 20 | explicit NullSinkStreamImpl(Core::System& system_, StreamType type_) | 20 | explicit NullSinkStreamImpl(Core::System& system_, StreamType type_) |
| 21 | : SinkStream{system_, type_} {} | 21 | : SinkStream{system_, type_} {} |
| 22 | ~NullSinkStreamImpl() override {} | 22 | ~NullSinkStreamImpl() override {} |
| 23 | void AppendBuffer(SinkBuffer&, std::vector<s16>&) override {} | 23 | void AppendBuffer(SinkBuffer&, std::span<s16>) override {} |
| 24 | std::vector<s16> ReleaseBuffer(u64) override { | 24 | std::vector<s16> ReleaseBuffer(u64) override { |
| 25 | return {}; | 25 | return {}; |
| 26 | } | 26 | } |
diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp index f44fedfd5..404dcd0e9 100644 --- a/src/audio_core/sink/sink_stream.cpp +++ b/src/audio_core/sink/sink_stream.cpp | |||
| @@ -15,11 +15,10 @@ | |||
| 15 | #include "common/settings.h" | 15 | #include "common/settings.h" |
| 16 | #include "core/core.h" | 16 | #include "core/core.h" |
| 17 | #include "core/core_timing.h" | 17 | #include "core/core_timing.h" |
| 18 | #include "core/core_timing_util.h" | ||
| 19 | 18 | ||
| 20 | namespace AudioCore::Sink { | 19 | namespace AudioCore::Sink { |
| 21 | 20 | ||
| 22 | void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples) { | 21 | void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) { |
| 23 | if (type == StreamType::In) { | 22 | if (type == StreamType::In) { |
| 24 | queue.enqueue(buffer); | 23 | queue.enqueue(buffer); |
| 25 | queued_buffers++; | 24 | queued_buffers++; |
| @@ -67,15 +66,16 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples) { | |||
| 67 | static_cast<s16>(std::clamp(right_sample, min, max)); | 66 | static_cast<s16>(std::clamp(right_sample, min, max)); |
| 68 | } | 67 | } |
| 69 | 68 | ||
| 70 | samples.resize(samples.size() / system_channels * device_channels); | 69 | samples = samples.subspan(0, samples.size() / system_channels * device_channels); |
| 71 | 70 | ||
| 72 | } else if (system_channels == 2 && device_channels == 6) { | 71 | } else if (system_channels == 2 && device_channels == 6) { |
| 73 | // We need moar samples! Not all games will provide 6 channel audio. | 72 | // We need moar samples! Not all games will provide 6 channel audio. |
| 74 | // TODO: Implement some upmixing here. Currently just passthrough, with other | 73 | // TODO: Implement some upmixing here. Currently just passthrough, with other |
| 75 | // channels left as silence. | 74 | // channels left as silence. |
| 76 | std::vector<s16> new_samples(samples.size() / system_channels * device_channels, 0); | 75 | auto new_size = samples.size() / system_channels * device_channels; |
| 76 | tmp_samples.resize_destructive(new_size); | ||
| 77 | 77 | ||
| 78 | for (u32 read_index = 0, write_index = 0; read_index < samples.size(); | 78 | for (u32 read_index = 0, write_index = 0; read_index < new_size; |
| 79 | read_index += system_channels, write_index += device_channels) { | 79 | read_index += system_channels, write_index += device_channels) { |
| 80 | const auto left_sample{static_cast<s16>(std::clamp( | 80 | const auto left_sample{static_cast<s16>(std::clamp( |
| 81 | static_cast<s32>( | 81 | static_cast<s32>( |
| @@ -83,7 +83,7 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples) { | |||
| 83 | volume), | 83 | volume), |
| 84 | min, max))}; | 84 | min, max))}; |
| 85 | 85 | ||
| 86 | new_samples[write_index + static_cast<u32>(Channels::FrontLeft)] = left_sample; | 86 | tmp_samples[write_index + static_cast<u32>(Channels::FrontLeft)] = left_sample; |
| 87 | 87 | ||
| 88 | const auto right_sample{static_cast<s16>(std::clamp( | 88 | const auto right_sample{static_cast<s16>(std::clamp( |
| 89 | static_cast<s32>( | 89 | static_cast<s32>( |
| @@ -91,9 +91,9 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples) { | |||
| 91 | volume), | 91 | volume), |
| 92 | min, max))}; | 92 | min, max))}; |
| 93 | 93 | ||
| 94 | new_samples[write_index + static_cast<u32>(Channels::FrontRight)] = right_sample; | 94 | tmp_samples[write_index + static_cast<u32>(Channels::FrontRight)] = right_sample; |
| 95 | } | 95 | } |
| 96 | samples = std::move(new_samples); | 96 | samples = std::span<s16>(tmp_samples); |
| 97 | 97 | ||
| 98 | } else if (volume != 1.0f) { | 98 | } else if (volume != 1.0f) { |
| 99 | for (u32 i = 0; i < samples.size(); i++) { | 99 | for (u32 i = 0; i < samples.size(); i++) { |
diff --git a/src/audio_core/sink/sink_stream.h b/src/audio_core/sink/sink_stream.h index 41cbadc9c..98d72ace1 100644 --- a/src/audio_core/sink/sink_stream.h +++ b/src/audio_core/sink/sink_stream.h | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include "common/polyfill_thread.h" | 16 | #include "common/polyfill_thread.h" |
| 17 | #include "common/reader_writer_queue.h" | 17 | #include "common/reader_writer_queue.h" |
| 18 | #include "common/ring_buffer.h" | 18 | #include "common/ring_buffer.h" |
| 19 | #include "common/scratch_buffer.h" | ||
| 19 | #include "common/thread.h" | 20 | #include "common/thread.h" |
| 20 | 21 | ||
| 21 | namespace Core { | 22 | namespace Core { |
| @@ -170,7 +171,7 @@ public: | |||
| 170 | * @param buffer - Audio buffer information to be queued. | 171 | * @param buffer - Audio buffer information to be queued. |
| 171 | * @param samples - The s16 samples to be queue for playback. | 172 | * @param samples - The s16 samples to be queue for playback. |
| 172 | */ | 173 | */ |
| 173 | virtual void AppendBuffer(SinkBuffer& buffer, std::vector<s16>& samples); | 174 | virtual void AppendBuffer(SinkBuffer& buffer, std::span<s16> samples); |
| 174 | 175 | ||
| 175 | /** | 176 | /** |
| 176 | * Release a buffer. Audio In only, will fill a buffer with recorded samples. | 177 | * Release a buffer. Audio In only, will fill a buffer with recorded samples. |
| @@ -255,6 +256,8 @@ private: | |||
| 255 | /// Signalled when ring buffer entries are consumed | 256 | /// Signalled when ring buffer entries are consumed |
| 256 | std::condition_variable_any release_cv; | 257 | std::condition_variable_any release_cv; |
| 257 | std::mutex release_mutex; | 258 | std::mutex release_mutex; |
| 259 | /// Temporary buffer for appending samples when upmixing | ||
| 260 | Common::ScratchBuffer<s16> tmp_samples{}; | ||
| 258 | }; | 261 | }; |
| 259 | 262 | ||
| 260 | using SinkStreamPtr = std::unique_ptr<SinkStream>; | 263 | using SinkStreamPtr = std::unique_ptr<SinkStream>; |
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index efc4a9fe9..3adf13a3f 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -172,6 +172,8 @@ if(ARCHITECTURE_x86_64) | |||
| 172 | x64/cpu_wait.h | 172 | x64/cpu_wait.h |
| 173 | x64/native_clock.cpp | 173 | x64/native_clock.cpp |
| 174 | x64/native_clock.h | 174 | x64/native_clock.h |
| 175 | x64/rdtsc.cpp | ||
| 176 | x64/rdtsc.h | ||
| 175 | x64/xbyak_abi.h | 177 | x64/xbyak_abi.h |
| 176 | x64/xbyak_util.h | 178 | x64/xbyak_util.h |
| 177 | ) | 179 | ) |
diff --git a/src/common/fs/fs.cpp b/src/common/fs/fs.cpp index 6d66c926d..36e67c145 100644 --- a/src/common/fs/fs.cpp +++ b/src/common/fs/fs.cpp | |||
| @@ -436,7 +436,7 @@ void IterateDirEntries(const std::filesystem::path& path, const DirEntryCallable | |||
| 436 | 436 | ||
| 437 | if (True(filter & DirEntryFilter::File) && | 437 | if (True(filter & DirEntryFilter::File) && |
| 438 | entry.status().type() == fs::file_type::regular) { | 438 | entry.status().type() == fs::file_type::regular) { |
| 439 | if (!callback(entry.path())) { | 439 | if (!callback(entry)) { |
| 440 | callback_error = true; | 440 | callback_error = true; |
| 441 | break; | 441 | break; |
| 442 | } | 442 | } |
| @@ -444,7 +444,7 @@ void IterateDirEntries(const std::filesystem::path& path, const DirEntryCallable | |||
| 444 | 444 | ||
| 445 | if (True(filter & DirEntryFilter::Directory) && | 445 | if (True(filter & DirEntryFilter::Directory) && |
| 446 | entry.status().type() == fs::file_type::directory) { | 446 | entry.status().type() == fs::file_type::directory) { |
| 447 | if (!callback(entry.path())) { | 447 | if (!callback(entry)) { |
| 448 | callback_error = true; | 448 | callback_error = true; |
| 449 | break; | 449 | break; |
| 450 | } | 450 | } |
| @@ -493,7 +493,7 @@ void IterateDirEntriesRecursively(const std::filesystem::path& path, | |||
| 493 | 493 | ||
| 494 | if (True(filter & DirEntryFilter::File) && | 494 | if (True(filter & DirEntryFilter::File) && |
| 495 | entry.status().type() == fs::file_type::regular) { | 495 | entry.status().type() == fs::file_type::regular) { |
| 496 | if (!callback(entry.path())) { | 496 | if (!callback(entry)) { |
| 497 | callback_error = true; | 497 | callback_error = true; |
| 498 | break; | 498 | break; |
| 499 | } | 499 | } |
| @@ -501,7 +501,7 @@ void IterateDirEntriesRecursively(const std::filesystem::path& path, | |||
| 501 | 501 | ||
| 502 | if (True(filter & DirEntryFilter::Directory) && | 502 | if (True(filter & DirEntryFilter::Directory) && |
| 503 | entry.status().type() == fs::file_type::directory) { | 503 | entry.status().type() == fs::file_type::directory) { |
| 504 | if (!callback(entry.path())) { | 504 | if (!callback(entry)) { |
| 505 | callback_error = true; | 505 | callback_error = true; |
| 506 | break; | 506 | break; |
| 507 | } | 507 | } |
| @@ -605,6 +605,12 @@ fs::file_type GetEntryType(const fs::path& path) { | |||
| 605 | } | 605 | } |
| 606 | 606 | ||
| 607 | u64 GetSize(const fs::path& path) { | 607 | u64 GetSize(const fs::path& path) { |
| 608 | #ifdef ANDROID | ||
| 609 | if (Android::IsContentUri(path)) { | ||
| 610 | return Android::GetSize(path); | ||
| 611 | } | ||
| 612 | #endif | ||
| 613 | |||
| 608 | std::error_code ec; | 614 | std::error_code ec; |
| 609 | 615 | ||
| 610 | const auto file_size = fs::file_size(path, ec); | 616 | const auto file_size = fs::file_size(path, ec); |
diff --git a/src/common/fs/fs_types.h b/src/common/fs/fs_types.h index 5a4090c19..900f85d24 100644 --- a/src/common/fs/fs_types.h +++ b/src/common/fs/fs_types.h | |||
| @@ -66,6 +66,6 @@ DECLARE_ENUM_FLAG_OPERATORS(DirEntryFilter); | |||
| 66 | * @returns A boolean value. | 66 | * @returns A boolean value. |
| 67 | * Return true to indicate whether the callback is successful, false otherwise. | 67 | * Return true to indicate whether the callback is successful, false otherwise. |
| 68 | */ | 68 | */ |
| 69 | using DirEntryCallable = std::function<bool(const std::filesystem::path& path)>; | 69 | using DirEntryCallable = std::function<bool(const std::filesystem::directory_entry& entry)>; |
| 70 | 70 | ||
| 71 | } // namespace Common::FS | 71 | } // namespace Common::FS |
diff --git a/src/common/input.h b/src/common/input.h index 66fb15f0a..2c4ccea22 100644 --- a/src/common/input.h +++ b/src/common/input.h | |||
| @@ -75,8 +75,10 @@ enum class DriverResult { | |||
| 75 | ErrorWritingData, | 75 | ErrorWritingData, |
| 76 | NoDeviceDetected, | 76 | NoDeviceDetected, |
| 77 | InvalidHandle, | 77 | InvalidHandle, |
| 78 | InvalidParameters, | ||
| 78 | NotSupported, | 79 | NotSupported, |
| 79 | Disabled, | 80 | Disabled, |
| 81 | Delayed, | ||
| 80 | Unknown, | 82 | Unknown, |
| 81 | }; | 83 | }; |
| 82 | 84 | ||
| @@ -86,7 +88,7 @@ enum class NfcState { | |||
| 86 | NewAmiibo, | 88 | NewAmiibo, |
| 87 | WaitingForAmiibo, | 89 | WaitingForAmiibo, |
| 88 | AmiiboRemoved, | 90 | AmiiboRemoved, |
| 89 | NotAnAmiibo, | 91 | InvalidTagType, |
| 90 | NotSupported, | 92 | NotSupported, |
| 91 | WrongDeviceState, | 93 | WrongDeviceState, |
| 92 | WriteFailed, | 94 | WriteFailed, |
| @@ -218,8 +220,22 @@ struct CameraStatus { | |||
| 218 | }; | 220 | }; |
| 219 | 221 | ||
| 220 | struct NfcStatus { | 222 | struct NfcStatus { |
| 221 | NfcState state{}; | 223 | NfcState state{NfcState::Unknown}; |
| 222 | std::vector<u8> data{}; | 224 | u8 uuid_length; |
| 225 | u8 protocol; | ||
| 226 | u8 tag_type; | ||
| 227 | std::array<u8, 10> uuid; | ||
| 228 | }; | ||
| 229 | |||
| 230 | struct MifareData { | ||
| 231 | u8 command; | ||
| 232 | u8 sector; | ||
| 233 | std::array<u8, 0x6> key; | ||
| 234 | std::array<u8, 0x10> data; | ||
| 235 | }; | ||
| 236 | |||
| 237 | struct MifareRequest { | ||
| 238 | std::array<MifareData, 0x10> data; | ||
| 223 | }; | 239 | }; |
| 224 | 240 | ||
| 225 | // List of buttons to be passed to Qt that can be translated | 241 | // List of buttons to be passed to Qt that can be translated |
| @@ -294,7 +310,7 @@ struct CallbackStatus { | |||
| 294 | BatteryStatus battery_status{}; | 310 | BatteryStatus battery_status{}; |
| 295 | VibrationStatus vibration_status{}; | 311 | VibrationStatus vibration_status{}; |
| 296 | CameraFormat camera_status{CameraFormat::None}; | 312 | CameraFormat camera_status{CameraFormat::None}; |
| 297 | NfcState nfc_status{NfcState::Unknown}; | 313 | NfcStatus nfc_status{}; |
| 298 | std::vector<u8> raw_data{}; | 314 | std::vector<u8> raw_data{}; |
| 299 | }; | 315 | }; |
| 300 | 316 | ||
| @@ -356,9 +372,30 @@ public: | |||
| 356 | return NfcState::NotSupported; | 372 | return NfcState::NotSupported; |
| 357 | } | 373 | } |
| 358 | 374 | ||
| 375 | virtual NfcState StartNfcPolling() { | ||
| 376 | return NfcState::NotSupported; | ||
| 377 | } | ||
| 378 | |||
| 379 | virtual NfcState StopNfcPolling() { | ||
| 380 | return NfcState::NotSupported; | ||
| 381 | } | ||
| 382 | |||
| 383 | virtual NfcState ReadAmiiboData([[maybe_unused]] std::vector<u8>& out_data) { | ||
| 384 | return NfcState::NotSupported; | ||
| 385 | } | ||
| 386 | |||
| 359 | virtual NfcState WriteNfcData([[maybe_unused]] const std::vector<u8>& data) { | 387 | virtual NfcState WriteNfcData([[maybe_unused]] const std::vector<u8>& data) { |
| 360 | return NfcState::NotSupported; | 388 | return NfcState::NotSupported; |
| 361 | } | 389 | } |
| 390 | |||
| 391 | virtual NfcState ReadMifareData([[maybe_unused]] const MifareRequest& request, | ||
| 392 | [[maybe_unused]] MifareRequest& out_data) { | ||
| 393 | return NfcState::NotSupported; | ||
| 394 | } | ||
| 395 | |||
| 396 | virtual NfcState WriteMifareData([[maybe_unused]] const MifareRequest& request) { | ||
| 397 | return NfcState::NotSupported; | ||
| 398 | } | ||
| 362 | }; | 399 | }; |
| 363 | 400 | ||
| 364 | /// An abstract class template for a factory that can create input devices. | 401 | /// An abstract class template for a factory that can create input devices. |
diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h index 4c328ab44..416680d44 100644 --- a/src/common/ring_buffer.h +++ b/src/common/ring_buffer.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <cstddef> | 9 | #include <cstddef> |
| 10 | #include <cstring> | 10 | #include <cstring> |
| 11 | #include <new> | 11 | #include <new> |
| 12 | #include <span> | ||
| 12 | #include <type_traits> | 13 | #include <type_traits> |
| 13 | #include <vector> | 14 | #include <vector> |
| 14 | 15 | ||
| @@ -53,7 +54,7 @@ public: | |||
| 53 | return push_count; | 54 | return push_count; |
| 54 | } | 55 | } |
| 55 | 56 | ||
| 56 | std::size_t Push(const std::vector<T>& input) { | 57 | std::size_t Push(const std::span<T> input) { |
| 57 | return Push(input.data(), input.size()); | 58 | return Push(input.data(), input.size()); |
| 58 | } | 59 | } |
| 59 | 60 | ||
diff --git a/src/common/scratch_buffer.h b/src/common/scratch_buffer.h index a69a5a7af..6fe907953 100644 --- a/src/common/scratch_buffer.h +++ b/src/common/scratch_buffer.h | |||
| @@ -3,6 +3,9 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <iterator> | ||
| 7 | |||
| 8 | #include "common/concepts.h" | ||
| 6 | #include "common/make_unique_for_overwrite.h" | 9 | #include "common/make_unique_for_overwrite.h" |
| 7 | 10 | ||
| 8 | namespace Common { | 11 | namespace Common { |
| @@ -16,6 +19,12 @@ namespace Common { | |||
| 16 | template <typename T> | 19 | template <typename T> |
| 17 | class ScratchBuffer { | 20 | class ScratchBuffer { |
| 18 | public: | 21 | public: |
| 22 | using iterator = T*; | ||
| 23 | using const_iterator = const T*; | ||
| 24 | using value_type = T; | ||
| 25 | using element_type = T; | ||
| 26 | using iterator_category = std::contiguous_iterator_tag; | ||
| 27 | |||
| 19 | ScratchBuffer() = default; | 28 | ScratchBuffer() = default; |
| 20 | 29 | ||
| 21 | explicit ScratchBuffer(size_t initial_capacity) | 30 | explicit ScratchBuffer(size_t initial_capacity) |
diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 66dffc9bf..6cbbea1b2 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp | |||
| @@ -1,8 +1,11 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2021 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 <version> | ||
| 4 | #if __cpp_lib_chrono >= 201907L | 5 | #if __cpp_lib_chrono >= 201907L |
| 5 | #include <chrono> | 6 | #include <chrono> |
| 7 | #include <exception> | ||
| 8 | #include <stdexcept> | ||
| 6 | #endif | 9 | #endif |
| 7 | #include <string_view> | 10 | #include <string_view> |
| 8 | 11 | ||
| @@ -25,9 +28,19 @@ std::string GetTimeZoneString() { | |||
| 25 | if (time_zone_index == 0) { // Auto | 28 | if (time_zone_index == 0) { // Auto |
| 26 | #if __cpp_lib_chrono >= 201907L | 29 | #if __cpp_lib_chrono >= 201907L |
| 27 | const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb(); | 30 | const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb(); |
| 28 | const std::chrono::time_zone* current_zone = time_zone_data.current_zone(); | 31 | try { |
| 29 | std::string_view current_zone_name = current_zone->name(); | 32 | const std::chrono::time_zone* current_zone = time_zone_data.current_zone(); |
| 30 | location_name = current_zone_name; | 33 | std::string_view current_zone_name = current_zone->name(); |
| 34 | location_name = current_zone_name; | ||
| 35 | } catch (std::runtime_error& runtime_error) { | ||
| 36 | // VCRUNTIME will throw a runtime_error if the operating system's selected time zone | ||
| 37 | // cannot be found | ||
| 38 | location_name = Common::TimeZone::FindSystemTimeZone(); | ||
| 39 | LOG_WARNING(Common, | ||
| 40 | "Error occurred when trying to determine system time zone:\n{}\nFalling " | ||
| 41 | "back to hour offset \"{}\"", | ||
| 42 | runtime_error.what(), location_name); | ||
| 43 | } | ||
| 31 | #else | 44 | #else |
| 32 | location_name = Common::TimeZone::FindSystemTimeZone(); | 45 | location_name = Common::TimeZone::FindSystemTimeZone(); |
| 33 | #endif | 46 | #endif |
diff --git a/src/common/settings.h b/src/common/settings.h index 9682281b0..ae5ed93d8 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -483,6 +483,7 @@ struct Values { | |||
| 483 | AstcRecompression::Uncompressed, AstcRecompression::Uncompressed, AstcRecompression::Bc3, | 483 | AstcRecompression::Uncompressed, AstcRecompression::Uncompressed, AstcRecompression::Bc3, |
| 484 | "astc_recompression"}; | 484 | "astc_recompression"}; |
| 485 | SwitchableSetting<bool> use_video_framerate{false, "use_video_framerate"}; | 485 | SwitchableSetting<bool> use_video_framerate{false, "use_video_framerate"}; |
| 486 | SwitchableSetting<bool> barrier_feedback_loops{true, "barrier_feedback_loops"}; | ||
| 486 | 487 | ||
| 487 | SwitchableSetting<u8> bg_red{0, "bg_red"}; | 488 | SwitchableSetting<u8> bg_red{0, "bg_red"}; |
| 488 | SwitchableSetting<u8> bg_green{0, "bg_green"}; | 489 | SwitchableSetting<u8> bg_green{0, "bg_green"}; |
| @@ -524,9 +525,16 @@ struct Values { | |||
| 524 | Setting<bool> tas_loop{false, "tas_loop"}; | 525 | Setting<bool> tas_loop{false, "tas_loop"}; |
| 525 | 526 | ||
| 526 | Setting<bool> mouse_panning{false, "mouse_panning"}; | 527 | Setting<bool> mouse_panning{false, "mouse_panning"}; |
| 527 | Setting<u8, true> mouse_panning_sensitivity{50, 1, 100, "mouse_panning_sensitivity"}; | 528 | Setting<u8, true> mouse_panning_x_sensitivity{50, 1, 100, "mouse_panning_x_sensitivity"}; |
| 528 | Setting<bool> mouse_enabled{false, "mouse_enabled"}; | 529 | Setting<u8, true> mouse_panning_y_sensitivity{50, 1, 100, "mouse_panning_y_sensitivity"}; |
| 530 | Setting<u8, true> mouse_panning_deadzone_x_counterweight{ | ||
| 531 | 0, 0, 100, "mouse_panning_deadzone_x_counterweight"}; | ||
| 532 | Setting<u8, true> mouse_panning_deadzone_y_counterweight{ | ||
| 533 | 0, 0, 100, "mouse_panning_deadzone_y_counterweight"}; | ||
| 534 | Setting<u8, true> mouse_panning_decay_strength{22, 0, 100, "mouse_panning_decay_strength"}; | ||
| 535 | Setting<u8, true> mouse_panning_min_decay{5, 0, 100, "mouse_panning_min_decay"}; | ||
| 529 | 536 | ||
| 537 | Setting<bool> mouse_enabled{false, "mouse_enabled"}; | ||
| 530 | Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"}; | 538 | Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"}; |
| 531 | Setting<bool> keyboard_enabled{false, "keyboard_enabled"}; | 539 | Setting<bool> keyboard_enabled{false, "keyboard_enabled"}; |
| 532 | 540 | ||
diff --git a/src/common/steady_clock.cpp b/src/common/steady_clock.cpp index 782859196..9415eed29 100644 --- a/src/common/steady_clock.cpp +++ b/src/common/steady_clock.cpp | |||
| @@ -28,13 +28,12 @@ static s64 GetSystemTimeNS() { | |||
| 28 | // GetSystemTimePreciseAsFileTime returns the file time in 100ns units. | 28 | // GetSystemTimePreciseAsFileTime returns the file time in 100ns units. |
| 29 | static constexpr s64 Multiplier = 100; | 29 | static constexpr s64 Multiplier = 100; |
| 30 | // Convert Windows epoch to Unix epoch. | 30 | // Convert Windows epoch to Unix epoch. |
| 31 | static constexpr s64 WindowsEpochToUnixEpochNS = 0x19DB1DED53E8000LL; | 31 | static constexpr s64 WindowsEpochToUnixEpoch = 0x19DB1DED53E8000LL; |
| 32 | 32 | ||
| 33 | FILETIME filetime; | 33 | FILETIME filetime; |
| 34 | GetSystemTimePreciseAsFileTime(&filetime); | 34 | GetSystemTimePreciseAsFileTime(&filetime); |
| 35 | return Multiplier * ((static_cast<s64>(filetime.dwHighDateTime) << 32) + | 35 | return Multiplier * ((static_cast<s64>(filetime.dwHighDateTime) << 32) + |
| 36 | static_cast<s64>(filetime.dwLowDateTime)) - | 36 | static_cast<s64>(filetime.dwLowDateTime) - WindowsEpochToUnixEpoch); |
| 37 | WindowsEpochToUnixEpochNS; | ||
| 38 | } | 37 | } |
| 39 | #endif | 38 | #endif |
| 40 | 39 | ||
diff --git a/src/common/telemetry.cpp b/src/common/telemetry.cpp index 91352912d..929ed67e4 100644 --- a/src/common/telemetry.cpp +++ b/src/common/telemetry.cpp | |||
| @@ -93,6 +93,7 @@ void AppendCPUInfo(FieldCollection& fc) { | |||
| 93 | add_field("CPU_Extension_x64_GFNI", caps.gfni); | 93 | add_field("CPU_Extension_x64_GFNI", caps.gfni); |
| 94 | add_field("CPU_Extension_x64_INVARIANT_TSC", caps.invariant_tsc); | 94 | add_field("CPU_Extension_x64_INVARIANT_TSC", caps.invariant_tsc); |
| 95 | add_field("CPU_Extension_x64_LZCNT", caps.lzcnt); | 95 | add_field("CPU_Extension_x64_LZCNT", caps.lzcnt); |
| 96 | add_field("CPU_Extension_x64_MONITORX", caps.monitorx); | ||
| 96 | add_field("CPU_Extension_x64_MOVBE", caps.movbe); | 97 | add_field("CPU_Extension_x64_MOVBE", caps.movbe); |
| 97 | add_field("CPU_Extension_x64_PCLMULQDQ", caps.pclmulqdq); | 98 | add_field("CPU_Extension_x64_PCLMULQDQ", caps.pclmulqdq); |
| 98 | add_field("CPU_Extension_x64_POPCNT", caps.popcnt); | 99 | add_field("CPU_Extension_x64_POPCNT", caps.popcnt); |
diff --git a/src/common/thread.h b/src/common/thread.h index 8ae169b4e..c6976fb6c 100644 --- a/src/common/thread.h +++ b/src/common/thread.h | |||
| @@ -55,7 +55,7 @@ public: | |||
| 55 | is_set = false; | 55 | is_set = false; |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | [[nodiscard]] bool IsSet() { | 58 | [[nodiscard]] bool IsSet() const { |
| 59 | return is_set; | 59 | return is_set; |
| 60 | } | 60 | } |
| 61 | 61 | ||
diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp index 817e71d52..dc0dcbd68 100644 --- a/src/common/wall_clock.cpp +++ b/src/common/wall_clock.cpp | |||
| @@ -2,88 +2,75 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "common/steady_clock.h" | 4 | #include "common/steady_clock.h" |
| 5 | #include "common/uint128.h" | ||
| 6 | #include "common/wall_clock.h" | 5 | #include "common/wall_clock.h" |
| 7 | 6 | ||
| 8 | #ifdef ARCHITECTURE_x86_64 | 7 | #ifdef ARCHITECTURE_x86_64 |
| 9 | #include "common/x64/cpu_detect.h" | 8 | #include "common/x64/cpu_detect.h" |
| 10 | #include "common/x64/native_clock.h" | 9 | #include "common/x64/native_clock.h" |
| 10 | #include "common/x64/rdtsc.h" | ||
| 11 | #endif | 11 | #endif |
| 12 | 12 | ||
| 13 | namespace Common { | 13 | namespace Common { |
| 14 | 14 | ||
| 15 | class StandardWallClock final : public WallClock { | 15 | class StandardWallClock final : public WallClock { |
| 16 | public: | 16 | public: |
| 17 | explicit StandardWallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_) | 17 | explicit StandardWallClock() : start_time{SteadyClock::Now()} {} |
| 18 | : WallClock{emulated_cpu_frequency_, emulated_clock_frequency_, false}, | ||
| 19 | start_time{SteadyClock::Now()} {} | ||
| 20 | 18 | ||
| 21 | std::chrono::nanoseconds GetTimeNS() override { | 19 | std::chrono::nanoseconds GetTimeNS() const override { |
| 22 | return SteadyClock::Now() - start_time; | 20 | return SteadyClock::Now() - start_time; |
| 23 | } | 21 | } |
| 24 | 22 | ||
| 25 | std::chrono::microseconds GetTimeUS() override { | 23 | std::chrono::microseconds GetTimeUS() const override { |
| 26 | return std::chrono::duration_cast<std::chrono::microseconds>(GetTimeNS()); | 24 | return static_cast<std::chrono::microseconds>(GetHostTicksElapsed() / NsToUsRatio::den); |
| 27 | } | 25 | } |
| 28 | 26 | ||
| 29 | std::chrono::milliseconds GetTimeMS() override { | 27 | std::chrono::milliseconds GetTimeMS() const override { |
| 30 | return std::chrono::duration_cast<std::chrono::milliseconds>(GetTimeNS()); | 28 | return static_cast<std::chrono::milliseconds>(GetHostTicksElapsed() / NsToMsRatio::den); |
| 31 | } | 29 | } |
| 32 | 30 | ||
| 33 | u64 GetClockCycles() override { | 31 | u64 GetCNTPCT() const override { |
| 34 | const u128 temp = Common::Multiply64Into128(GetTimeNS().count(), emulated_clock_frequency); | 32 | return GetHostTicksElapsed() * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den; |
| 35 | return Common::Divide128On32(temp, NS_RATIO).first; | ||
| 36 | } | 33 | } |
| 37 | 34 | ||
| 38 | u64 GetCPUCycles() override { | 35 | u64 GetGPUTick() const override { |
| 39 | const u128 temp = Common::Multiply64Into128(GetTimeNS().count(), emulated_cpu_frequency); | 36 | return GetHostTicksElapsed() * NsToGPUTickRatio::num / NsToGPUTickRatio::den; |
| 40 | return Common::Divide128On32(temp, NS_RATIO).first; | ||
| 41 | } | 37 | } |
| 42 | 38 | ||
| 43 | void Pause([[maybe_unused]] bool is_paused) override { | 39 | u64 GetHostTicksNow() const override { |
| 44 | // Do nothing in this clock type. | 40 | return static_cast<u64>(SteadyClock::Now().time_since_epoch().count()); |
| 41 | } | ||
| 42 | |||
| 43 | u64 GetHostTicksElapsed() const override { | ||
| 44 | return static_cast<u64>(GetTimeNS().count()); | ||
| 45 | } | ||
| 46 | |||
| 47 | bool IsNative() const override { | ||
| 48 | return false; | ||
| 45 | } | 49 | } |
| 46 | 50 | ||
| 47 | private: | 51 | private: |
| 48 | SteadyClock::time_point start_time; | 52 | SteadyClock::time_point start_time; |
| 49 | }; | 53 | }; |
| 50 | 54 | ||
| 55 | std::unique_ptr<WallClock> CreateOptimalClock() { | ||
| 51 | #ifdef ARCHITECTURE_x86_64 | 56 | #ifdef ARCHITECTURE_x86_64 |
| 52 | |||
| 53 | std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency, | ||
| 54 | u64 emulated_clock_frequency) { | ||
| 55 | const auto& caps = GetCPUCaps(); | 57 | const auto& caps = GetCPUCaps(); |
| 56 | u64 rtsc_frequency = 0; | ||
| 57 | if (caps.invariant_tsc) { | ||
| 58 | rtsc_frequency = caps.tsc_frequency ? caps.tsc_frequency : EstimateRDTSCFrequency(); | ||
| 59 | } | ||
| 60 | 58 | ||
| 61 | // Fallback to StandardWallClock if the hardware TSC does not have the precision greater than: | 59 | if (caps.invariant_tsc && caps.tsc_frequency >= WallClock::GPUTickFreq) { |
| 62 | // - A nanosecond | 60 | return std::make_unique<X64::NativeClock>(caps.tsc_frequency); |
| 63 | // - The emulated CPU frequency | ||
| 64 | // - The emulated clock counter frequency (CNTFRQ) | ||
| 65 | if (rtsc_frequency <= WallClock::NS_RATIO || rtsc_frequency <= emulated_cpu_frequency || | ||
| 66 | rtsc_frequency <= emulated_clock_frequency) { | ||
| 67 | return std::make_unique<StandardWallClock>(emulated_cpu_frequency, | ||
| 68 | emulated_clock_frequency); | ||
| 69 | } else { | 61 | } else { |
| 70 | return std::make_unique<X64::NativeClock>(emulated_cpu_frequency, emulated_clock_frequency, | 62 | // Fallback to StandardWallClock if the hardware TSC |
| 71 | rtsc_frequency); | 63 | // - Is not invariant |
| 64 | // - Is not more precise than GPUTickFreq | ||
| 65 | return std::make_unique<StandardWallClock>(); | ||
| 72 | } | 66 | } |
| 73 | } | ||
| 74 | |||
| 75 | #else | 67 | #else |
| 76 | 68 | return std::make_unique<StandardWallClock>(); | |
| 77 | std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency, | ||
| 78 | u64 emulated_clock_frequency) { | ||
| 79 | return std::make_unique<StandardWallClock>(emulated_cpu_frequency, emulated_clock_frequency); | ||
| 80 | } | ||
| 81 | |||
| 82 | #endif | 69 | #endif |
| 70 | } | ||
| 83 | 71 | ||
| 84 | std::unique_ptr<WallClock> CreateStandardWallClock(u64 emulated_cpu_frequency, | 72 | std::unique_ptr<WallClock> CreateStandardWallClock() { |
| 85 | u64 emulated_clock_frequency) { | 73 | return std::make_unique<StandardWallClock>(); |
| 86 | return std::make_unique<StandardWallClock>(emulated_cpu_frequency, emulated_clock_frequency); | ||
| 87 | } | 74 | } |
| 88 | 75 | ||
| 89 | } // namespace Common | 76 | } // namespace Common |
diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h index 157ec5eae..f45d3d8c5 100644 --- a/src/common/wall_clock.h +++ b/src/common/wall_clock.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include <chrono> | 6 | #include <chrono> |
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <ratio> | ||
| 8 | 9 | ||
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 10 | 11 | ||
| @@ -12,50 +13,82 @@ namespace Common { | |||
| 12 | 13 | ||
| 13 | class WallClock { | 14 | class WallClock { |
| 14 | public: | 15 | public: |
| 15 | static constexpr u64 NS_RATIO = 1'000'000'000; | 16 | static constexpr u64 CNTFRQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz |
| 16 | static constexpr u64 US_RATIO = 1'000'000; | 17 | static constexpr u64 GPUTickFreq = 614'400'000; // GM20B GPU Tick Frequency = 614.4 MHz |
| 17 | static constexpr u64 MS_RATIO = 1'000; | 18 | static constexpr u64 CPUTickFreq = 1'020'000'000; // T210/4 A57 CPU Tick Frequency = 1020.0 MHz |
| 18 | 19 | ||
| 19 | virtual ~WallClock() = default; | 20 | virtual ~WallClock() = default; |
| 20 | 21 | ||
| 21 | /// Returns current wall time in nanoseconds | 22 | /// @returns The time in nanoseconds since the construction of this clock. |
| 22 | [[nodiscard]] virtual std::chrono::nanoseconds GetTimeNS() = 0; | 23 | virtual std::chrono::nanoseconds GetTimeNS() const = 0; |
| 23 | 24 | ||
| 24 | /// Returns current wall time in microseconds | 25 | /// @returns The time in microseconds since the construction of this clock. |
| 25 | [[nodiscard]] virtual std::chrono::microseconds GetTimeUS() = 0; | 26 | virtual std::chrono::microseconds GetTimeUS() const = 0; |
| 26 | 27 | ||
| 27 | /// Returns current wall time in milliseconds | 28 | /// @returns The time in milliseconds since the construction of this clock. |
| 28 | [[nodiscard]] virtual std::chrono::milliseconds GetTimeMS() = 0; | 29 | virtual std::chrono::milliseconds GetTimeMS() const = 0; |
| 29 | 30 | ||
| 30 | /// Returns current wall time in emulated clock cycles | 31 | /// @returns The guest CNTPCT ticks since the construction of this clock. |
| 31 | [[nodiscard]] virtual u64 GetClockCycles() = 0; | 32 | virtual u64 GetCNTPCT() const = 0; |
| 32 | 33 | ||
| 33 | /// Returns current wall time in emulated cpu cycles | 34 | /// @returns The guest GPU ticks since the construction of this clock. |
| 34 | [[nodiscard]] virtual u64 GetCPUCycles() = 0; | 35 | virtual u64 GetGPUTick() const = 0; |
| 35 | 36 | ||
| 36 | virtual void Pause(bool is_paused) = 0; | 37 | /// @returns The raw host timer ticks since an indeterminate epoch. |
| 38 | virtual u64 GetHostTicksNow() const = 0; | ||
| 37 | 39 | ||
| 38 | /// Tells if the wall clock, uses the host CPU's hardware clock | 40 | /// @returns The raw host timer ticks since the construction of this clock. |
| 39 | [[nodiscard]] bool IsNative() const { | 41 | virtual u64 GetHostTicksElapsed() const = 0; |
| 40 | return is_native; | 42 | |
| 43 | /// @returns Whether the clock directly uses the host's hardware clock. | ||
| 44 | virtual bool IsNative() const = 0; | ||
| 45 | |||
| 46 | static inline u64 NSToCNTPCT(u64 ns) { | ||
| 47 | return ns * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den; | ||
| 48 | } | ||
| 49 | |||
| 50 | static inline u64 NSToGPUTick(u64 ns) { | ||
| 51 | return ns * NsToGPUTickRatio::num / NsToGPUTickRatio::den; | ||
| 52 | } | ||
| 53 | |||
| 54 | // Cycle Timing | ||
| 55 | |||
| 56 | static inline u64 CPUTickToNS(u64 cpu_tick) { | ||
| 57 | return cpu_tick * CPUTickToNsRatio::num / CPUTickToNsRatio::den; | ||
| 58 | } | ||
| 59 | |||
| 60 | static inline u64 CPUTickToUS(u64 cpu_tick) { | ||
| 61 | return cpu_tick * CPUTickToUsRatio::num / CPUTickToUsRatio::den; | ||
| 62 | } | ||
| 63 | |||
| 64 | static inline u64 CPUTickToCNTPCT(u64 cpu_tick) { | ||
| 65 | return cpu_tick * CPUTickToCNTPCTRatio::num / CPUTickToCNTPCTRatio::den; | ||
| 66 | } | ||
| 67 | |||
| 68 | static inline u64 CPUTickToGPUTick(u64 cpu_tick) { | ||
| 69 | return cpu_tick * CPUTickToGPUTickRatio::num / CPUTickToGPUTickRatio::den; | ||
| 41 | } | 70 | } |
| 42 | 71 | ||
| 43 | protected: | 72 | protected: |
| 44 | explicit WallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, bool is_native_) | 73 | using NsRatio = std::nano; |
| 45 | : emulated_cpu_frequency{emulated_cpu_frequency_}, | 74 | using UsRatio = std::micro; |
| 46 | emulated_clock_frequency{emulated_clock_frequency_}, is_native{is_native_} {} | 75 | using MsRatio = std::milli; |
| 76 | |||
| 77 | using NsToUsRatio = std::ratio_divide<std::nano, std::micro>; | ||
| 78 | using NsToMsRatio = std::ratio_divide<std::nano, std::milli>; | ||
| 79 | using NsToCNTPCTRatio = std::ratio<CNTFRQ, std::nano::den>; | ||
| 80 | using NsToGPUTickRatio = std::ratio<GPUTickFreq, std::nano::den>; | ||
| 47 | 81 | ||
| 48 | u64 emulated_cpu_frequency; | 82 | // Cycle Timing |
| 49 | u64 emulated_clock_frequency; | ||
| 50 | 83 | ||
| 51 | private: | 84 | using CPUTickToNsRatio = std::ratio<std::nano::den, CPUTickFreq>; |
| 52 | bool is_native; | 85 | using CPUTickToUsRatio = std::ratio<std::micro::den, CPUTickFreq>; |
| 86 | using CPUTickToCNTPCTRatio = std::ratio<CNTFRQ, CPUTickFreq>; | ||
| 87 | using CPUTickToGPUTickRatio = std::ratio<GPUTickFreq, CPUTickFreq>; | ||
| 53 | }; | 88 | }; |
| 54 | 89 | ||
| 55 | [[nodiscard]] std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency, | 90 | std::unique_ptr<WallClock> CreateOptimalClock(); |
| 56 | u64 emulated_clock_frequency); | ||
| 57 | 91 | ||
| 58 | [[nodiscard]] std::unique_ptr<WallClock> CreateStandardWallClock(u64 emulated_cpu_frequency, | 92 | std::unique_ptr<WallClock> CreateStandardWallClock(); |
| 59 | u64 emulated_clock_frequency); | ||
| 60 | 93 | ||
| 61 | } // namespace Common | 94 | } // namespace Common |
diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp index 72ed6e96c..780120a5b 100644 --- a/src/common/x64/cpu_detect.cpp +++ b/src/common/x64/cpu_detect.cpp | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| 15 | #include "common/logging/log.h" | 15 | #include "common/logging/log.h" |
| 16 | #include "common/x64/cpu_detect.h" | 16 | #include "common/x64/cpu_detect.h" |
| 17 | #include "common/x64/rdtsc.h" | ||
| 17 | 18 | ||
| 18 | #ifdef _WIN32 | 19 | #ifdef _WIN32 |
| 19 | #include <windows.h> | 20 | #include <windows.h> |
| @@ -167,6 +168,7 @@ static CPUCaps Detect() { | |||
| 167 | __cpuid(cpu_id, 0x80000001); | 168 | __cpuid(cpu_id, 0x80000001); |
| 168 | caps.lzcnt = Common::Bit<5>(cpu_id[2]); | 169 | caps.lzcnt = Common::Bit<5>(cpu_id[2]); |
| 169 | caps.fma4 = Common::Bit<16>(cpu_id[2]); | 170 | caps.fma4 = Common::Bit<16>(cpu_id[2]); |
| 171 | caps.monitorx = Common::Bit<29>(cpu_id[2]); | ||
| 170 | } | 172 | } |
| 171 | 173 | ||
| 172 | if (max_ex_fn >= 0x80000007) { | 174 | if (max_ex_fn >= 0x80000007) { |
| @@ -187,6 +189,8 @@ static CPUCaps Detect() { | |||
| 187 | caps.tsc_frequency = static_cast<u64>(caps.crystal_frequency) * | 189 | caps.tsc_frequency = static_cast<u64>(caps.crystal_frequency) * |
| 188 | caps.tsc_crystal_ratio_numerator / | 190 | caps.tsc_crystal_ratio_numerator / |
| 189 | caps.tsc_crystal_ratio_denominator; | 191 | caps.tsc_crystal_ratio_denominator; |
| 192 | } else { | ||
| 193 | caps.tsc_frequency = X64::EstimateRDTSCFrequency(); | ||
| 190 | } | 194 | } |
| 191 | } | 195 | } |
| 192 | 196 | ||
diff --git a/src/common/x64/cpu_detect.h b/src/common/x64/cpu_detect.h index 8253944d6..756459417 100644 --- a/src/common/x64/cpu_detect.h +++ b/src/common/x64/cpu_detect.h | |||
| @@ -63,6 +63,7 @@ struct CPUCaps { | |||
| 63 | bool gfni : 1; | 63 | bool gfni : 1; |
| 64 | bool invariant_tsc : 1; | 64 | bool invariant_tsc : 1; |
| 65 | bool lzcnt : 1; | 65 | bool lzcnt : 1; |
| 66 | bool monitorx : 1; | ||
| 66 | bool movbe : 1; | 67 | bool movbe : 1; |
| 67 | bool pclmulqdq : 1; | 68 | bool pclmulqdq : 1; |
| 68 | bool popcnt : 1; | 69 | bool popcnt : 1; |
diff --git a/src/common/x64/cpu_wait.cpp b/src/common/x64/cpu_wait.cpp index cfeef6a3d..41d385f59 100644 --- a/src/common/x64/cpu_wait.cpp +++ b/src/common/x64/cpu_wait.cpp | |||
| @@ -9,58 +9,64 @@ | |||
| 9 | 9 | ||
| 10 | #include "common/x64/cpu_detect.h" | 10 | #include "common/x64/cpu_detect.h" |
| 11 | #include "common/x64/cpu_wait.h" | 11 | #include "common/x64/cpu_wait.h" |
| 12 | #include "common/x64/rdtsc.h" | ||
| 12 | 13 | ||
| 13 | namespace Common::X64 { | 14 | namespace Common::X64 { |
| 14 | 15 | ||
| 16 | namespace { | ||
| 17 | |||
| 18 | // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. | ||
| 19 | // For reference: | ||
| 20 | // At 1 GHz, 100K cycles is 100us | ||
| 21 | // At 2 GHz, 100K cycles is 50us | ||
| 22 | // At 4 GHz, 100K cycles is 25us | ||
| 23 | constexpr auto PauseCycles = 100'000U; | ||
| 24 | |||
| 25 | } // Anonymous namespace | ||
| 26 | |||
| 15 | #ifdef _MSC_VER | 27 | #ifdef _MSC_VER |
| 16 | __forceinline static u64 FencedRDTSC() { | 28 | __forceinline static void TPAUSE() { |
| 17 | _mm_lfence(); | 29 | static constexpr auto RequestC02State = 0U; |
| 18 | _ReadWriteBarrier(); | 30 | _tpause(RequestC02State, FencedRDTSC() + PauseCycles); |
| 19 | const u64 result = __rdtsc(); | ||
| 20 | _mm_lfence(); | ||
| 21 | _ReadWriteBarrier(); | ||
| 22 | return result; | ||
| 23 | } | 31 | } |
| 24 | 32 | ||
| 25 | __forceinline static void TPAUSE() { | 33 | __forceinline static void MWAITX() { |
| 26 | // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. | 34 | static constexpr auto EnableWaitTimeFlag = 1U << 1; |
| 27 | // For reference: | 35 | static constexpr auto RequestC1State = 0U; |
| 28 | // At 1 GHz, 100K cycles is 100us | 36 | |
| 29 | // At 2 GHz, 100K cycles is 50us | 37 | // monitor_var should be aligned to a cache line. |
| 30 | // At 4 GHz, 100K cycles is 25us | 38 | alignas(64) u64 monitor_var{}; |
| 31 | static constexpr auto PauseCycles = 100'000; | 39 | _mm_monitorx(&monitor_var, 0, 0); |
| 32 | _tpause(0, FencedRDTSC() + PauseCycles); | 40 | _mm_mwaitx(EnableWaitTimeFlag, RequestC1State, PauseCycles); |
| 33 | } | 41 | } |
| 34 | #else | 42 | #else |
| 35 | static u64 FencedRDTSC() { | ||
| 36 | u64 eax; | ||
| 37 | u64 edx; | ||
| 38 | asm volatile("lfence\n\t" | ||
| 39 | "rdtsc\n\t" | ||
| 40 | "lfence\n\t" | ||
| 41 | : "=a"(eax), "=d"(edx)); | ||
| 42 | return (edx << 32) | eax; | ||
| 43 | } | ||
| 44 | |||
| 45 | static void TPAUSE() { | 43 | static void TPAUSE() { |
| 46 | // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. | 44 | static constexpr auto RequestC02State = 0U; |
| 47 | // For reference: | ||
| 48 | // At 1 GHz, 100K cycles is 100us | ||
| 49 | // At 2 GHz, 100K cycles is 50us | ||
| 50 | // At 4 GHz, 100K cycles is 25us | ||
| 51 | static constexpr auto PauseCycles = 100'000; | ||
| 52 | const auto tsc = FencedRDTSC() + PauseCycles; | 45 | const auto tsc = FencedRDTSC() + PauseCycles; |
| 53 | const auto eax = static_cast<u32>(tsc & 0xFFFFFFFF); | 46 | const auto eax = static_cast<u32>(tsc & 0xFFFFFFFF); |
| 54 | const auto edx = static_cast<u32>(tsc >> 32); | 47 | const auto edx = static_cast<u32>(tsc >> 32); |
| 55 | asm volatile("tpause %0" : : "r"(0), "d"(edx), "a"(eax)); | 48 | asm volatile("tpause %0" : : "r"(RequestC02State), "d"(edx), "a"(eax)); |
| 49 | } | ||
| 50 | |||
| 51 | static void MWAITX() { | ||
| 52 | static constexpr auto EnableWaitTimeFlag = 1U << 1; | ||
| 53 | static constexpr auto RequestC1State = 0U; | ||
| 54 | |||
| 55 | // monitor_var should be aligned to a cache line. | ||
| 56 | alignas(64) u64 monitor_var{}; | ||
| 57 | asm volatile("monitorx" : : "a"(&monitor_var), "c"(0), "d"(0)); | ||
| 58 | asm volatile("mwaitx" : : "a"(RequestC1State), "b"(PauseCycles), "c"(EnableWaitTimeFlag)); | ||
| 56 | } | 59 | } |
| 57 | #endif | 60 | #endif |
| 58 | 61 | ||
| 59 | void MicroSleep() { | 62 | void MicroSleep() { |
| 60 | static const bool has_waitpkg = GetCPUCaps().waitpkg; | 63 | static const bool has_waitpkg = GetCPUCaps().waitpkg; |
| 64 | static const bool has_monitorx = GetCPUCaps().monitorx; | ||
| 61 | 65 | ||
| 62 | if (has_waitpkg) { | 66 | if (has_waitpkg) { |
| 63 | TPAUSE(); | 67 | TPAUSE(); |
| 68 | } else if (has_monitorx) { | ||
| 69 | MWAITX(); | ||
| 64 | } else { | 70 | } else { |
| 65 | std::this_thread::yield(); | 71 | std::this_thread::yield(); |
| 66 | } | 72 | } |
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 277b00662..7d2a26bd9 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp | |||
| @@ -1,164 +1,50 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2020 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 <array> | ||
| 5 | #include <chrono> | ||
| 6 | #include <thread> | ||
| 7 | |||
| 8 | #include "common/atomic_ops.h" | ||
| 9 | #include "common/steady_clock.h" | ||
| 10 | #include "common/uint128.h" | 4 | #include "common/uint128.h" |
| 11 | #include "common/x64/native_clock.h" | 5 | #include "common/x64/native_clock.h" |
| 6 | #include "common/x64/rdtsc.h" | ||
| 12 | 7 | ||
| 13 | #ifdef _MSC_VER | 8 | namespace Common::X64 { |
| 14 | #include <intrin.h> | ||
| 15 | #endif | ||
| 16 | |||
| 17 | namespace Common { | ||
| 18 | 9 | ||
| 19 | #ifdef _MSC_VER | 10 | NativeClock::NativeClock(u64 rdtsc_frequency_) |
| 20 | __forceinline static u64 FencedRDTSC() { | 11 | : start_ticks{FencedRDTSC()}, rdtsc_frequency{rdtsc_frequency_}, |
| 21 | _mm_lfence(); | 12 | ns_rdtsc_factor{GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency)}, |
| 22 | _ReadWriteBarrier(); | 13 | us_rdtsc_factor{GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency)}, |
| 23 | const u64 result = __rdtsc(); | 14 | ms_rdtsc_factor{GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency)}, |
| 24 | _mm_lfence(); | 15 | cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency)}, |
| 25 | _ReadWriteBarrier(); | 16 | gputick_rdtsc_factor{GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency)} {} |
| 26 | return result; | ||
| 27 | } | ||
| 28 | #else | ||
| 29 | static u64 FencedRDTSC() { | ||
| 30 | u64 eax; | ||
| 31 | u64 edx; | ||
| 32 | asm volatile("lfence\n\t" | ||
| 33 | "rdtsc\n\t" | ||
| 34 | "lfence\n\t" | ||
| 35 | : "=a"(eax), "=d"(edx)); | ||
| 36 | return (edx << 32) | eax; | ||
| 37 | } | ||
| 38 | #endif | ||
| 39 | 17 | ||
| 40 | template <u64 Nearest> | 18 | std::chrono::nanoseconds NativeClock::GetTimeNS() const { |
| 41 | static u64 RoundToNearest(u64 value) { | 19 | return std::chrono::nanoseconds{MultiplyHigh(GetHostTicksElapsed(), ns_rdtsc_factor)}; |
| 42 | const auto mod = value % Nearest; | ||
| 43 | return mod >= (Nearest / 2) ? (value - mod + Nearest) : (value - mod); | ||
| 44 | } | 20 | } |
| 45 | 21 | ||
| 46 | u64 EstimateRDTSCFrequency() { | 22 | std::chrono::microseconds NativeClock::GetTimeUS() const { |
| 47 | // Discard the first result measuring the rdtsc. | 23 | return std::chrono::microseconds{MultiplyHigh(GetHostTicksElapsed(), us_rdtsc_factor)}; |
| 48 | FencedRDTSC(); | ||
| 49 | std::this_thread::sleep_for(std::chrono::milliseconds{1}); | ||
| 50 | FencedRDTSC(); | ||
| 51 | |||
| 52 | // Get the current time. | ||
| 53 | const auto start_time = Common::RealTimeClock::Now(); | ||
| 54 | const u64 tsc_start = FencedRDTSC(); | ||
| 55 | // Wait for 250 milliseconds. | ||
| 56 | std::this_thread::sleep_for(std::chrono::milliseconds{250}); | ||
| 57 | const auto end_time = Common::RealTimeClock::Now(); | ||
| 58 | const u64 tsc_end = FencedRDTSC(); | ||
| 59 | // Calculate differences. | ||
| 60 | const u64 timer_diff = static_cast<u64>( | ||
| 61 | std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count()); | ||
| 62 | const u64 tsc_diff = tsc_end - tsc_start; | ||
| 63 | const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff); | ||
| 64 | return RoundToNearest<1000>(tsc_freq); | ||
| 65 | } | 24 | } |
| 66 | 25 | ||
| 67 | namespace X64 { | 26 | std::chrono::milliseconds NativeClock::GetTimeMS() const { |
| 68 | NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, | 27 | return std::chrono::milliseconds{MultiplyHigh(GetHostTicksElapsed(), ms_rdtsc_factor)}; |
| 69 | u64 rtsc_frequency_) | ||
| 70 | : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ | ||
| 71 | rtsc_frequency_} { | ||
| 72 | // Thread to re-adjust the RDTSC frequency after 10 seconds has elapsed. | ||
| 73 | time_sync_thread = std::jthread{[this](std::stop_token token) { | ||
| 74 | // Get the current time. | ||
| 75 | const auto start_time = Common::RealTimeClock::Now(); | ||
| 76 | const u64 tsc_start = FencedRDTSC(); | ||
| 77 | // Wait for 10 seconds. | ||
| 78 | if (!Common::StoppableTimedWait(token, std::chrono::seconds{10})) { | ||
| 79 | return; | ||
| 80 | } | ||
| 81 | const auto end_time = Common::RealTimeClock::Now(); | ||
| 82 | const u64 tsc_end = FencedRDTSC(); | ||
| 83 | // Calculate differences. | ||
| 84 | const u64 timer_diff = static_cast<u64>( | ||
| 85 | std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count()); | ||
| 86 | const u64 tsc_diff = tsc_end - tsc_start; | ||
| 87 | const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff); | ||
| 88 | rtsc_frequency = tsc_freq; | ||
| 89 | CalculateAndSetFactors(); | ||
| 90 | }}; | ||
| 91 | |||
| 92 | time_point.inner.last_measure = FencedRDTSC(); | ||
| 93 | time_point.inner.accumulated_ticks = 0U; | ||
| 94 | CalculateAndSetFactors(); | ||
| 95 | } | 28 | } |
| 96 | 29 | ||
| 97 | u64 NativeClock::GetRTSC() { | 30 | u64 NativeClock::GetCNTPCT() const { |
| 98 | TimePoint new_time_point{}; | 31 | return MultiplyHigh(GetHostTicksElapsed(), cntpct_rdtsc_factor); |
| 99 | TimePoint current_time_point{}; | ||
| 100 | |||
| 101 | current_time_point.pack = Common::AtomicLoad128(time_point.pack.data()); | ||
| 102 | do { | ||
| 103 | const u64 current_measure = FencedRDTSC(); | ||
| 104 | u64 diff = current_measure - current_time_point.inner.last_measure; | ||
| 105 | diff = diff & ~static_cast<u64>(static_cast<s64>(diff) >> 63); // max(diff, 0) | ||
| 106 | new_time_point.inner.last_measure = current_measure > current_time_point.inner.last_measure | ||
| 107 | ? current_measure | ||
| 108 | : current_time_point.inner.last_measure; | ||
| 109 | new_time_point.inner.accumulated_ticks = current_time_point.inner.accumulated_ticks + diff; | ||
| 110 | } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, | ||
| 111 | current_time_point.pack, current_time_point.pack)); | ||
| 112 | return new_time_point.inner.accumulated_ticks; | ||
| 113 | } | 32 | } |
| 114 | 33 | ||
| 115 | void NativeClock::Pause(bool is_paused) { | 34 | u64 NativeClock::GetGPUTick() const { |
| 116 | if (!is_paused) { | 35 | return MultiplyHigh(GetHostTicksElapsed(), gputick_rdtsc_factor); |
| 117 | TimePoint current_time_point{}; | ||
| 118 | TimePoint new_time_point{}; | ||
| 119 | |||
| 120 | current_time_point.pack = Common::AtomicLoad128(time_point.pack.data()); | ||
| 121 | do { | ||
| 122 | new_time_point.pack = current_time_point.pack; | ||
| 123 | new_time_point.inner.last_measure = FencedRDTSC(); | ||
| 124 | } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, | ||
| 125 | current_time_point.pack, current_time_point.pack)); | ||
| 126 | } | ||
| 127 | } | 36 | } |
| 128 | 37 | ||
| 129 | std::chrono::nanoseconds NativeClock::GetTimeNS() { | 38 | u64 NativeClock::GetHostTicksNow() const { |
| 130 | const u64 rtsc_value = GetRTSC(); | 39 | return FencedRDTSC(); |
| 131 | return std::chrono::nanoseconds{MultiplyHigh(rtsc_value, ns_rtsc_factor)}; | ||
| 132 | } | 40 | } |
| 133 | 41 | ||
| 134 | std::chrono::microseconds NativeClock::GetTimeUS() { | 42 | u64 NativeClock::GetHostTicksElapsed() const { |
| 135 | const u64 rtsc_value = GetRTSC(); | 43 | return FencedRDTSC() - start_ticks; |
| 136 | return std::chrono::microseconds{MultiplyHigh(rtsc_value, us_rtsc_factor)}; | ||
| 137 | } | 44 | } |
| 138 | 45 | ||
| 139 | std::chrono::milliseconds NativeClock::GetTimeMS() { | 46 | bool NativeClock::IsNative() const { |
| 140 | const u64 rtsc_value = GetRTSC(); | 47 | return true; |
| 141 | return std::chrono::milliseconds{MultiplyHigh(rtsc_value, ms_rtsc_factor)}; | ||
| 142 | } | 48 | } |
| 143 | 49 | ||
| 144 | u64 NativeClock::GetClockCycles() { | 50 | } // namespace Common::X64 |
| 145 | const u64 rtsc_value = GetRTSC(); | ||
| 146 | return MultiplyHigh(rtsc_value, clock_rtsc_factor); | ||
| 147 | } | ||
| 148 | |||
| 149 | u64 NativeClock::GetCPUCycles() { | ||
| 150 | const u64 rtsc_value = GetRTSC(); | ||
| 151 | return MultiplyHigh(rtsc_value, cpu_rtsc_factor); | ||
| 152 | } | ||
| 153 | |||
| 154 | void NativeClock::CalculateAndSetFactors() { | ||
| 155 | ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency); | ||
| 156 | us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency); | ||
| 157 | ms_rtsc_factor = GetFixedPoint64Factor(MS_RATIO, rtsc_frequency); | ||
| 158 | clock_rtsc_factor = GetFixedPoint64Factor(emulated_clock_frequency, rtsc_frequency); | ||
| 159 | cpu_rtsc_factor = GetFixedPoint64Factor(emulated_cpu_frequency, rtsc_frequency); | ||
| 160 | } | ||
| 161 | |||
| 162 | } // namespace X64 | ||
| 163 | |||
| 164 | } // namespace Common | ||
diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h index 03ca291d8..334415eff 100644 --- a/src/common/x64/native_clock.h +++ b/src/common/x64/native_clock.h | |||
| @@ -3,58 +3,39 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include "common/polyfill_thread.h" | ||
| 7 | #include "common/wall_clock.h" | 6 | #include "common/wall_clock.h" |
| 8 | 7 | ||
| 9 | namespace Common { | 8 | namespace Common::X64 { |
| 10 | 9 | ||
| 11 | namespace X64 { | ||
| 12 | class NativeClock final : public WallClock { | 10 | class NativeClock final : public WallClock { |
| 13 | public: | 11 | public: |
| 14 | explicit NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, | 12 | explicit NativeClock(u64 rdtsc_frequency_); |
| 15 | u64 rtsc_frequency_); | ||
| 16 | 13 | ||
| 17 | std::chrono::nanoseconds GetTimeNS() override; | 14 | std::chrono::nanoseconds GetTimeNS() const override; |
| 18 | 15 | ||
| 19 | std::chrono::microseconds GetTimeUS() override; | 16 | std::chrono::microseconds GetTimeUS() const override; |
| 20 | 17 | ||
| 21 | std::chrono::milliseconds GetTimeMS() override; | 18 | std::chrono::milliseconds GetTimeMS() const override; |
| 22 | 19 | ||
| 23 | u64 GetClockCycles() override; | 20 | u64 GetCNTPCT() const override; |
| 24 | 21 | ||
| 25 | u64 GetCPUCycles() override; | 22 | u64 GetGPUTick() const override; |
| 26 | 23 | ||
| 27 | void Pause(bool is_paused) override; | 24 | u64 GetHostTicksNow() const override; |
| 28 | 25 | ||
| 29 | private: | 26 | u64 GetHostTicksElapsed() const override; |
| 30 | u64 GetRTSC(); | ||
| 31 | |||
| 32 | void CalculateAndSetFactors(); | ||
| 33 | |||
| 34 | union alignas(16) TimePoint { | ||
| 35 | TimePoint() : pack{} {} | ||
| 36 | u128 pack{}; | ||
| 37 | struct Inner { | ||
| 38 | u64 last_measure{}; | ||
| 39 | u64 accumulated_ticks{}; | ||
| 40 | } inner; | ||
| 41 | }; | ||
| 42 | |||
| 43 | TimePoint time_point; | ||
| 44 | 27 | ||
| 45 | // factors | 28 | bool IsNative() const override; |
| 46 | u64 clock_rtsc_factor{}; | ||
| 47 | u64 cpu_rtsc_factor{}; | ||
| 48 | u64 ns_rtsc_factor{}; | ||
| 49 | u64 us_rtsc_factor{}; | ||
| 50 | u64 ms_rtsc_factor{}; | ||
| 51 | 29 | ||
| 52 | u64 rtsc_frequency; | 30 | private: |
| 53 | 31 | u64 start_ticks; | |
| 54 | std::jthread time_sync_thread; | 32 | u64 rdtsc_frequency; |
| 33 | |||
| 34 | u64 ns_rdtsc_factor; | ||
| 35 | u64 us_rdtsc_factor; | ||
| 36 | u64 ms_rdtsc_factor; | ||
| 37 | u64 cntpct_rdtsc_factor; | ||
| 38 | u64 gputick_rdtsc_factor; | ||
| 55 | }; | 39 | }; |
| 56 | } // namespace X64 | ||
| 57 | |||
| 58 | u64 EstimateRDTSCFrequency(); | ||
| 59 | 40 | ||
| 60 | } // namespace Common | 41 | } // namespace Common::X64 |
diff --git a/src/common/x64/rdtsc.cpp b/src/common/x64/rdtsc.cpp new file mode 100644 index 000000000..9273274a3 --- /dev/null +++ b/src/common/x64/rdtsc.cpp | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <thread> | ||
| 5 | |||
| 6 | #include "common/steady_clock.h" | ||
| 7 | #include "common/uint128.h" | ||
| 8 | #include "common/x64/rdtsc.h" | ||
| 9 | |||
| 10 | namespace Common::X64 { | ||
| 11 | |||
| 12 | template <u64 Nearest> | ||
| 13 | static u64 RoundToNearest(u64 value) { | ||
| 14 | const auto mod = value % Nearest; | ||
| 15 | return mod >= (Nearest / 2) ? (value - mod + Nearest) : (value - mod); | ||
| 16 | } | ||
| 17 | |||
| 18 | u64 EstimateRDTSCFrequency() { | ||
| 19 | // Discard the first result measuring the rdtsc. | ||
| 20 | FencedRDTSC(); | ||
| 21 | std::this_thread::sleep_for(std::chrono::milliseconds{1}); | ||
| 22 | FencedRDTSC(); | ||
| 23 | |||
| 24 | // Get the current time. | ||
| 25 | const auto start_time = RealTimeClock::Now(); | ||
| 26 | const u64 tsc_start = FencedRDTSC(); | ||
| 27 | // Wait for 100 milliseconds. | ||
| 28 | std::this_thread::sleep_for(std::chrono::milliseconds{100}); | ||
| 29 | const auto end_time = RealTimeClock::Now(); | ||
| 30 | const u64 tsc_end = FencedRDTSC(); | ||
| 31 | // Calculate differences. | ||
| 32 | const u64 timer_diff = static_cast<u64>( | ||
| 33 | std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count()); | ||
| 34 | const u64 tsc_diff = tsc_end - tsc_start; | ||
| 35 | const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff); | ||
| 36 | return RoundToNearest<100'000>(tsc_freq); | ||
| 37 | } | ||
| 38 | |||
| 39 | } // namespace Common::X64 | ||
diff --git a/src/common/x64/rdtsc.h b/src/common/x64/rdtsc.h new file mode 100644 index 000000000..0ec4f52f9 --- /dev/null +++ b/src/common/x64/rdtsc.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #ifdef _MSC_VER | ||
| 7 | #include <intrin.h> | ||
| 8 | #endif | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | |||
| 12 | namespace Common::X64 { | ||
| 13 | |||
| 14 | #ifdef _MSC_VER | ||
| 15 | __forceinline static u64 FencedRDTSC() { | ||
| 16 | _mm_lfence(); | ||
| 17 | _ReadWriteBarrier(); | ||
| 18 | const u64 result = __rdtsc(); | ||
| 19 | _mm_lfence(); | ||
| 20 | _ReadWriteBarrier(); | ||
| 21 | return result; | ||
| 22 | } | ||
| 23 | #else | ||
| 24 | static inline u64 FencedRDTSC() { | ||
| 25 | u64 eax; | ||
| 26 | u64 edx; | ||
| 27 | asm volatile("lfence\n\t" | ||
| 28 | "rdtsc\n\t" | ||
| 29 | "lfence\n\t" | ||
| 30 | : "=a"(eax), "=d"(edx)); | ||
| 31 | return (edx << 32) | eax; | ||
| 32 | } | ||
| 33 | #endif | ||
| 34 | |||
| 35 | u64 EstimateRDTSCFrequency(); | ||
| 36 | |||
| 37 | } // namespace Common::X64 | ||
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 4c53aed72..dd2c053d0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -14,7 +14,6 @@ add_library(core STATIC | |||
| 14 | core.h | 14 | core.h |
| 15 | core_timing.cpp | 15 | core_timing.cpp |
| 16 | core_timing.h | 16 | core_timing.h |
| 17 | core_timing_util.h | ||
| 18 | cpu_manager.cpp | 17 | cpu_manager.cpp |
| 19 | cpu_manager.h | 18 | cpu_manager.h |
| 20 | crypto/aes_util.cpp | 19 | crypto/aes_util.cpp |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 5acf9008d..3b82fb73c 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp | |||
| @@ -322,11 +322,6 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* | |||
| 322 | } | 322 | } |
| 323 | } | 323 | } |
| 324 | 324 | ||
| 325 | #ifdef ARCHITECTURE_arm64 | ||
| 326 | // TODO: remove when fixed in dynarmic | ||
| 327 | config.optimizations &= ~Dynarmic::OptimizationFlag::BlockLinking; | ||
| 328 | #endif | ||
| 329 | |||
| 330 | return std::make_unique<Dynarmic::A32::Jit>(config); | 325 | return std::make_unique<Dynarmic::A32::Jit>(config); |
| 331 | } | 326 | } |
| 332 | 327 | ||
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 4f2692b05..4f0a3f8ea 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp | |||
| @@ -16,12 +16,11 @@ | |||
| 16 | 16 | ||
| 17 | #include "common/microprofile.h" | 17 | #include "common/microprofile.h" |
| 18 | #include "core/core_timing.h" | 18 | #include "core/core_timing.h" |
| 19 | #include "core/core_timing_util.h" | ||
| 20 | #include "core/hardware_properties.h" | 19 | #include "core/hardware_properties.h" |
| 21 | 20 | ||
| 22 | namespace Core::Timing { | 21 | namespace Core::Timing { |
| 23 | 22 | ||
| 24 | constexpr s64 MAX_SLICE_LENGTH = 4000; | 23 | constexpr s64 MAX_SLICE_LENGTH = 10000; |
| 25 | 24 | ||
| 26 | std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) { | 25 | std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) { |
| 27 | return std::make_shared<EventType>(std::move(callback), std::move(name)); | 26 | return std::make_shared<EventType>(std::move(callback), std::move(name)); |
| @@ -45,9 +44,7 @@ struct CoreTiming::Event { | |||
| 45 | } | 44 | } |
| 46 | }; | 45 | }; |
| 47 | 46 | ||
| 48 | CoreTiming::CoreTiming() | 47 | CoreTiming::CoreTiming() : clock{Common::CreateOptimalClock()} {} |
| 49 | : cpu_clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)}, | ||
| 50 | event_clock{Common::CreateStandardWallClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {} | ||
| 51 | 48 | ||
| 52 | CoreTiming::~CoreTiming() { | 49 | CoreTiming::~CoreTiming() { |
| 53 | Reset(); | 50 | Reset(); |
| @@ -68,7 +65,7 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) { | |||
| 68 | on_thread_init = std::move(on_thread_init_); | 65 | on_thread_init = std::move(on_thread_init_); |
| 69 | event_fifo_id = 0; | 66 | event_fifo_id = 0; |
| 70 | shutting_down = false; | 67 | shutting_down = false; |
| 71 | ticks = 0; | 68 | cpu_ticks = 0; |
| 72 | const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds) | 69 | const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds) |
| 73 | -> std::optional<std::chrono::nanoseconds> { return std::nullopt; }; | 70 | -> std::optional<std::chrono::nanoseconds> { return std::nullopt; }; |
| 74 | ev_lost = CreateEvent("_lost_event", empty_timed_callback); | 71 | ev_lost = CreateEvent("_lost_event", empty_timed_callback); |
| @@ -173,38 +170,30 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, | |||
| 173 | } | 170 | } |
| 174 | 171 | ||
| 175 | void CoreTiming::AddTicks(u64 ticks_to_add) { | 172 | void CoreTiming::AddTicks(u64 ticks_to_add) { |
| 176 | ticks += ticks_to_add; | 173 | cpu_ticks += ticks_to_add; |
| 177 | downcount -= static_cast<s64>(ticks); | 174 | downcount -= static_cast<s64>(cpu_ticks); |
| 178 | } | 175 | } |
| 179 | 176 | ||
| 180 | void CoreTiming::Idle() { | 177 | void CoreTiming::Idle() { |
| 181 | if (!event_queue.empty()) { | 178 | cpu_ticks += 1000U; |
| 182 | const u64 next_event_time = event_queue.front().time; | ||
| 183 | const u64 next_ticks = nsToCycles(std::chrono::nanoseconds(next_event_time)) + 10U; | ||
| 184 | if (next_ticks > ticks) { | ||
| 185 | ticks = next_ticks; | ||
| 186 | } | ||
| 187 | return; | ||
| 188 | } | ||
| 189 | ticks += 1000U; | ||
| 190 | } | 179 | } |
| 191 | 180 | ||
| 192 | void CoreTiming::ResetTicks() { | 181 | void CoreTiming::ResetTicks() { |
| 193 | downcount = MAX_SLICE_LENGTH; | 182 | downcount = MAX_SLICE_LENGTH; |
| 194 | } | 183 | } |
| 195 | 184 | ||
| 196 | u64 CoreTiming::GetCPUTicks() const { | 185 | u64 CoreTiming::GetClockTicks() const { |
| 197 | if (is_multicore) [[likely]] { | 186 | if (is_multicore) [[likely]] { |
| 198 | return cpu_clock->GetCPUCycles(); | 187 | return clock->GetCNTPCT(); |
| 199 | } | 188 | } |
| 200 | return ticks; | 189 | return Common::WallClock::CPUTickToCNTPCT(cpu_ticks); |
| 201 | } | 190 | } |
| 202 | 191 | ||
| 203 | u64 CoreTiming::GetClockTicks() const { | 192 | u64 CoreTiming::GetGPUTicks() const { |
| 204 | if (is_multicore) [[likely]] { | 193 | if (is_multicore) [[likely]] { |
| 205 | return cpu_clock->GetClockCycles(); | 194 | return clock->GetGPUTick(); |
| 206 | } | 195 | } |
| 207 | return CpuCyclesToClockCycles(ticks); | 196 | return Common::WallClock::CPUTickToGPUTick(cpu_ticks); |
| 208 | } | 197 | } |
| 209 | 198 | ||
| 210 | std::optional<s64> CoreTiming::Advance() { | 199 | std::optional<s64> CoreTiming::Advance() { |
| @@ -297,9 +286,7 @@ void CoreTiming::ThreadLoop() { | |||
| 297 | } | 286 | } |
| 298 | 287 | ||
| 299 | paused_set = true; | 288 | paused_set = true; |
| 300 | event_clock->Pause(true); | ||
| 301 | pause_event.Wait(); | 289 | pause_event.Wait(); |
| 302 | event_clock->Pause(false); | ||
| 303 | } | 290 | } |
| 304 | } | 291 | } |
| 305 | 292 | ||
| @@ -315,25 +302,18 @@ void CoreTiming::Reset() { | |||
| 315 | has_started = false; | 302 | has_started = false; |
| 316 | } | 303 | } |
| 317 | 304 | ||
| 318 | std::chrono::nanoseconds CoreTiming::GetCPUTimeNs() const { | ||
| 319 | if (is_multicore) [[likely]] { | ||
| 320 | return cpu_clock->GetTimeNS(); | ||
| 321 | } | ||
| 322 | return CyclesToNs(ticks); | ||
| 323 | } | ||
| 324 | |||
| 325 | std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { | 305 | std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { |
| 326 | if (is_multicore) [[likely]] { | 306 | if (is_multicore) [[likely]] { |
| 327 | return event_clock->GetTimeNS(); | 307 | return clock->GetTimeNS(); |
| 328 | } | 308 | } |
| 329 | return CyclesToNs(ticks); | 309 | return std::chrono::nanoseconds{Common::WallClock::CPUTickToNS(cpu_ticks)}; |
| 330 | } | 310 | } |
| 331 | 311 | ||
| 332 | std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { | 312 | std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { |
| 333 | if (is_multicore) [[likely]] { | 313 | if (is_multicore) [[likely]] { |
| 334 | return event_clock->GetTimeUS(); | 314 | return clock->GetTimeUS(); |
| 335 | } | 315 | } |
| 336 | return CyclesToUs(ticks); | 316 | return std::chrono::microseconds{Common::WallClock::CPUTickToUS(cpu_ticks)}; |
| 337 | } | 317 | } |
| 338 | 318 | ||
| 339 | } // namespace Core::Timing | 319 | } // namespace Core::Timing |
diff --git a/src/core/core_timing.h b/src/core/core_timing.h index e7c4a949f..10db1de55 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h | |||
| @@ -116,14 +116,11 @@ public: | |||
| 116 | return downcount; | 116 | return downcount; |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | /// Returns current time in emulated CPU cycles | 119 | /// Returns the current CNTPCT tick value. |
| 120 | u64 GetCPUTicks() const; | ||
| 121 | |||
| 122 | /// Returns current time in emulated in Clock cycles | ||
| 123 | u64 GetClockTicks() const; | 120 | u64 GetClockTicks() const; |
| 124 | 121 | ||
| 125 | /// Returns current time in nanoseconds. | 122 | /// Returns the current GPU tick value. |
| 126 | std::chrono::nanoseconds GetCPUTimeNs() const; | 123 | u64 GetGPUTicks() const; |
| 127 | 124 | ||
| 128 | /// Returns current time in microseconds. | 125 | /// Returns current time in microseconds. |
| 129 | std::chrono::microseconds GetGlobalTimeUs() const; | 126 | std::chrono::microseconds GetGlobalTimeUs() const; |
| @@ -142,8 +139,7 @@ private: | |||
| 142 | 139 | ||
| 143 | void Reset(); | 140 | void Reset(); |
| 144 | 141 | ||
| 145 | std::unique_ptr<Common::WallClock> cpu_clock; | 142 | std::unique_ptr<Common::WallClock> clock; |
| 146 | std::unique_ptr<Common::WallClock> event_clock; | ||
| 147 | 143 | ||
| 148 | s64 global_timer = 0; | 144 | s64 global_timer = 0; |
| 149 | 145 | ||
| @@ -171,7 +167,7 @@ private: | |||
| 171 | s64 pause_end_time{}; | 167 | s64 pause_end_time{}; |
| 172 | 168 | ||
| 173 | /// Cycle timing | 169 | /// Cycle timing |
| 174 | u64 ticks{}; | 170 | u64 cpu_ticks{}; |
| 175 | s64 downcount{}; | 171 | s64 downcount{}; |
| 176 | }; | 172 | }; |
| 177 | 173 | ||
diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h deleted file mode 100644 index fe5aaefc7..000000000 --- a/src/core/core_timing_util.h +++ /dev/null | |||
| @@ -1,58 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <chrono> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/hardware_properties.h" | ||
| 10 | |||
| 11 | namespace Core::Timing { | ||
| 12 | |||
| 13 | namespace detail { | ||
| 14 | constexpr u64 CNTFREQ_ADJUSTED = Hardware::CNTFREQ / 1000; | ||
| 15 | constexpr u64 BASE_CLOCK_RATE_ADJUSTED = Hardware::BASE_CLOCK_RATE / 1000; | ||
| 16 | } // namespace detail | ||
| 17 | |||
| 18 | [[nodiscard]] constexpr s64 msToCycles(std::chrono::milliseconds ms) { | ||
| 19 | return ms.count() * detail::BASE_CLOCK_RATE_ADJUSTED; | ||
| 20 | } | ||
| 21 | |||
| 22 | [[nodiscard]] constexpr s64 usToCycles(std::chrono::microseconds us) { | ||
| 23 | return us.count() * detail::BASE_CLOCK_RATE_ADJUSTED / 1000; | ||
| 24 | } | ||
| 25 | |||
| 26 | [[nodiscard]] constexpr s64 nsToCycles(std::chrono::nanoseconds ns) { | ||
| 27 | return ns.count() * detail::BASE_CLOCK_RATE_ADJUSTED / 1000000; | ||
| 28 | } | ||
| 29 | |||
| 30 | [[nodiscard]] constexpr u64 msToClockCycles(std::chrono::milliseconds ms) { | ||
| 31 | return static_cast<u64>(ms.count()) * detail::CNTFREQ_ADJUSTED; | ||
| 32 | } | ||
| 33 | |||
| 34 | [[nodiscard]] constexpr u64 usToClockCycles(std::chrono::microseconds us) { | ||
| 35 | return us.count() * detail::CNTFREQ_ADJUSTED / 1000; | ||
| 36 | } | ||
| 37 | |||
| 38 | [[nodiscard]] constexpr u64 nsToClockCycles(std::chrono::nanoseconds ns) { | ||
| 39 | return ns.count() * detail::CNTFREQ_ADJUSTED / 1000000; | ||
| 40 | } | ||
| 41 | |||
| 42 | [[nodiscard]] constexpr u64 CpuCyclesToClockCycles(u64 ticks) { | ||
| 43 | return ticks * detail::CNTFREQ_ADJUSTED / detail::BASE_CLOCK_RATE_ADJUSTED; | ||
| 44 | } | ||
| 45 | |||
| 46 | [[nodiscard]] constexpr std::chrono::milliseconds CyclesToMs(s64 cycles) { | ||
| 47 | return std::chrono::milliseconds(cycles / detail::BASE_CLOCK_RATE_ADJUSTED); | ||
| 48 | } | ||
| 49 | |||
| 50 | [[nodiscard]] constexpr std::chrono::nanoseconds CyclesToNs(s64 cycles) { | ||
| 51 | return std::chrono::nanoseconds(cycles * 1000000 / detail::BASE_CLOCK_RATE_ADJUSTED); | ||
| 52 | } | ||
| 53 | |||
| 54 | [[nodiscard]] constexpr std::chrono::microseconds CyclesToUs(s64 cycles) { | ||
| 55 | return std::chrono::microseconds(cycles * 1000 / detail::BASE_CLOCK_RATE_ADJUSTED); | ||
| 56 | } | ||
| 57 | |||
| 58 | } // namespace Core::Timing | ||
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 4e61d4335..d3286b352 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp | |||
| @@ -153,7 +153,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { | |||
| 153 | const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id); | 153 | const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id); |
| 154 | 154 | ||
| 155 | std::vector<VirtualDir> patch_dirs = {sdmc_load_dir}; | 155 | std::vector<VirtualDir> patch_dirs = {sdmc_load_dir}; |
| 156 | if (load_dir != nullptr && load_dir->GetSize() > 0) { | 156 | if (load_dir != nullptr) { |
| 157 | const auto load_patch_dirs = load_dir->GetSubdirectories(); | 157 | const auto load_patch_dirs = load_dir->GetSubdirectories(); |
| 158 | patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end()); | 158 | patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end()); |
| 159 | } | 159 | } |
| @@ -354,8 +354,7 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t | |||
| 354 | const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); | 354 | const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); |
| 355 | const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id); | 355 | const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id); |
| 356 | if ((type != ContentRecordType::Program && type != ContentRecordType::Data) || | 356 | if ((type != ContentRecordType::Program && type != ContentRecordType::Data) || |
| 357 | ((load_dir == nullptr || load_dir->GetSize() <= 0) && | 357 | (load_dir == nullptr && sdmc_load_dir == nullptr)) { |
| 358 | (sdmc_load_dir == nullptr || sdmc_load_dir->GetSize() <= 0))) { | ||
| 359 | return; | 358 | return; |
| 360 | } | 359 | } |
| 361 | 360 | ||
| @@ -496,7 +495,7 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u | |||
| 496 | 495 | ||
| 497 | // General Mods (LayeredFS and IPS) | 496 | // General Mods (LayeredFS and IPS) |
| 498 | const auto mod_dir = fs_controller.GetModificationLoadRoot(title_id); | 497 | const auto mod_dir = fs_controller.GetModificationLoadRoot(title_id); |
| 499 | if (mod_dir != nullptr && mod_dir->GetSize() > 0) { | 498 | if (mod_dir != nullptr) { |
| 500 | for (const auto& mod : mod_dir->GetSubdirectories()) { | 499 | for (const auto& mod : mod_dir->GetSubdirectories()) { |
| 501 | std::string types; | 500 | std::string types; |
| 502 | 501 | ||
| @@ -540,7 +539,7 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u | |||
| 540 | 539 | ||
| 541 | // SDMC mod directory (RomFS LayeredFS) | 540 | // SDMC mod directory (RomFS LayeredFS) |
| 542 | const auto sdmc_mod_dir = fs_controller.GetSDMCModificationLoadRoot(title_id); | 541 | const auto sdmc_mod_dir = fs_controller.GetSDMCModificationLoadRoot(title_id); |
| 543 | if (sdmc_mod_dir != nullptr && sdmc_mod_dir->GetSize() > 0) { | 542 | if (sdmc_mod_dir != nullptr) { |
| 544 | std::string types; | 543 | std::string types; |
| 545 | if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(sdmc_mod_dir, "exefs"))) { | 544 | if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(sdmc_mod_dir, "exefs"))) { |
| 546 | AppendCommaIfNotEmpty(types, "LayeredExeFS"); | 545 | AppendCommaIfNotEmpty(types, "LayeredExeFS"); |
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp index 853b893a1..311a59e5f 100644 --- a/src/core/file_sys/vfs_concat.cpp +++ b/src/core/file_sys/vfs_concat.cpp | |||
| @@ -150,23 +150,29 @@ std::size_t ConcatenatedVfsFile::Read(u8* data, std::size_t length, std::size_t | |||
| 150 | while (cur_length > 0 && it != concatenation_map.end()) { | 150 | while (cur_length > 0 && it != concatenation_map.end()) { |
| 151 | // Check if we can read the file at this position. | 151 | // Check if we can read the file at this position. |
| 152 | const auto& file = it->file; | 152 | const auto& file = it->file; |
| 153 | const u64 file_offset = it->offset; | 153 | const u64 map_offset = it->offset; |
| 154 | const u64 file_size = file->GetSize(); | 154 | const u64 file_size = file->GetSize(); |
| 155 | 155 | ||
| 156 | if (cur_offset >= file_offset + file_size) { | 156 | if (cur_offset > map_offset + file_size) { |
| 157 | // Entirely out of bounds read. | 157 | // Entirely out of bounds read. |
| 158 | break; | 158 | break; |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | // Read the file at this position. | 161 | // Read the file at this position. |
| 162 | const u64 intended_read_size = std::min<u64>(cur_length, file_size); | 162 | const u64 file_seek = cur_offset - map_offset; |
| 163 | const u64 intended_read_size = std::min<u64>(cur_length, file_size - file_seek); | ||
| 163 | const u64 actual_read_size = | 164 | const u64 actual_read_size = |
| 164 | file->Read(data + (cur_offset - offset), intended_read_size, cur_offset - file_offset); | 165 | file->Read(data + (cur_offset - offset), intended_read_size, file_seek); |
| 165 | 166 | ||
| 166 | // Update tracking. | 167 | // Update tracking. |
| 167 | cur_offset += actual_read_size; | 168 | cur_offset += actual_read_size; |
| 168 | cur_length -= actual_read_size; | 169 | cur_length -= actual_read_size; |
| 169 | it++; | 170 | it++; |
| 171 | |||
| 172 | // If we encountered a short read, we're done. | ||
| 173 | if (actual_read_size < intended_read_size) { | ||
| 174 | break; | ||
| 175 | } | ||
| 170 | } | 176 | } |
| 171 | 177 | ||
| 172 | return cur_offset - offset; | 178 | return cur_offset - offset; |
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index 7a15d8438..b0515ec05 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "common/fs/fs.h" | 10 | #include "common/fs/fs.h" |
| 11 | #include "common/fs/path_util.h" | 11 | #include "common/fs/path_util.h" |
| 12 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 13 | #include "core/file_sys/vfs.h" | ||
| 13 | #include "core/file_sys/vfs_real.h" | 14 | #include "core/file_sys/vfs_real.h" |
| 14 | 15 | ||
| 15 | // For FileTimeStampRaw | 16 | // For FileTimeStampRaw |
| @@ -72,8 +73,10 @@ VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const { | |||
| 72 | return VfsEntryType::File; | 73 | return VfsEntryType::File; |
| 73 | } | 74 | } |
| 74 | 75 | ||
| 75 | VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { | 76 | VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::optional<u64> size, |
| 77 | Mode perms) { | ||
| 76 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); | 78 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); |
| 79 | std::scoped_lock lk{list_lock}; | ||
| 77 | 80 | ||
| 78 | if (auto it = cache.find(path); it != cache.end()) { | 81 | if (auto it = cache.find(path); it != cache.end()) { |
| 79 | if (auto file = it->second.lock(); file) { | 82 | if (auto file = it->second.lock(); file) { |
| @@ -81,23 +84,30 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { | |||
| 81 | } | 84 | } |
| 82 | } | 85 | } |
| 83 | 86 | ||
| 84 | if (!FS::Exists(path) || !FS::IsFile(path)) { | 87 | if (!size && !FS::IsFile(path)) { |
| 85 | return nullptr; | 88 | return nullptr; |
| 86 | } | 89 | } |
| 87 | 90 | ||
| 88 | auto reference = std::make_unique<FileReference>(); | 91 | auto reference = std::make_unique<FileReference>(); |
| 89 | this->InsertReferenceIntoList(*reference); | 92 | this->InsertReferenceIntoListLocked(*reference); |
| 90 | 93 | ||
| 91 | auto file = | 94 | auto file = std::shared_ptr<RealVfsFile>( |
| 92 | std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, std::move(reference), path, perms)); | 95 | new RealVfsFile(*this, std::move(reference), path, perms, size)); |
| 93 | cache[path] = file; | 96 | cache[path] = file; |
| 94 | 97 | ||
| 95 | return file; | 98 | return file; |
| 96 | } | 99 | } |
| 97 | 100 | ||
| 101 | VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { | ||
| 102 | return OpenFileFromEntry(path_, {}, perms); | ||
| 103 | } | ||
| 104 | |||
| 98 | VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { | 105 | VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { |
| 99 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); | 106 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); |
| 100 | cache.erase(path); | 107 | { |
| 108 | std::scoped_lock lk{list_lock}; | ||
| 109 | cache.erase(path); | ||
| 110 | } | ||
| 101 | 111 | ||
| 102 | // Current usages of CreateFile expect to delete the contents of an existing file. | 112 | // Current usages of CreateFile expect to delete the contents of an existing file. |
| 103 | if (FS::IsFile(path)) { | 113 | if (FS::IsFile(path)) { |
| @@ -127,8 +137,11 @@ VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_ | |||
| 127 | VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) { | 137 | VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) { |
| 128 | const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault); | 138 | const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault); |
| 129 | const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault); | 139 | const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault); |
| 130 | cache.erase(old_path); | 140 | { |
| 131 | cache.erase(new_path); | 141 | std::scoped_lock lk{list_lock}; |
| 142 | cache.erase(old_path); | ||
| 143 | cache.erase(new_path); | ||
| 144 | } | ||
| 132 | if (!FS::RenameFile(old_path, new_path)) { | 145 | if (!FS::RenameFile(old_path, new_path)) { |
| 133 | return nullptr; | 146 | return nullptr; |
| 134 | } | 147 | } |
| @@ -137,7 +150,10 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_ | |||
| 137 | 150 | ||
| 138 | bool RealVfsFilesystem::DeleteFile(std::string_view path_) { | 151 | bool RealVfsFilesystem::DeleteFile(std::string_view path_) { |
| 139 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); | 152 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); |
| 140 | cache.erase(path); | 153 | { |
| 154 | std::scoped_lock lk{list_lock}; | ||
| 155 | cache.erase(path); | ||
| 156 | } | ||
| 141 | return FS::RemoveFile(path); | 157 | return FS::RemoveFile(path); |
| 142 | } | 158 | } |
| 143 | 159 | ||
| @@ -176,14 +192,17 @@ bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) { | |||
| 176 | return FS::RemoveDirRecursively(path); | 192 | return FS::RemoveDirRecursively(path); |
| 177 | } | 193 | } |
| 178 | 194 | ||
| 179 | void RealVfsFilesystem::RefreshReference(const std::string& path, Mode perms, | 195 | std::unique_lock<std::mutex> RealVfsFilesystem::RefreshReference(const std::string& path, |
| 180 | FileReference& reference) { | 196 | Mode perms, |
| 197 | FileReference& reference) { | ||
| 198 | std::unique_lock lk{list_lock}; | ||
| 199 | |||
| 181 | // Temporarily remove from list. | 200 | // Temporarily remove from list. |
| 182 | this->RemoveReferenceFromList(reference); | 201 | this->RemoveReferenceFromListLocked(reference); |
| 183 | 202 | ||
| 184 | // Restore file if needed. | 203 | // Restore file if needed. |
| 185 | if (!reference.file) { | 204 | if (!reference.file) { |
| 186 | this->EvictSingleReference(); | 205 | this->EvictSingleReferenceLocked(); |
| 187 | 206 | ||
| 188 | reference.file = | 207 | reference.file = |
| 189 | FS::FileOpen(path, ModeFlagsToFileAccessMode(perms), FS::FileType::BinaryFile); | 208 | FS::FileOpen(path, ModeFlagsToFileAccessMode(perms), FS::FileType::BinaryFile); |
| @@ -193,12 +212,16 @@ void RealVfsFilesystem::RefreshReference(const std::string& path, Mode perms, | |||
| 193 | } | 212 | } |
| 194 | 213 | ||
| 195 | // Reinsert into list. | 214 | // Reinsert into list. |
| 196 | this->InsertReferenceIntoList(reference); | 215 | this->InsertReferenceIntoListLocked(reference); |
| 216 | |||
| 217 | return lk; | ||
| 197 | } | 218 | } |
| 198 | 219 | ||
| 199 | void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference) { | 220 | void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference) { |
| 221 | std::scoped_lock lk{list_lock}; | ||
| 222 | |||
| 200 | // Remove from list. | 223 | // Remove from list. |
| 201 | this->RemoveReferenceFromList(*reference); | 224 | this->RemoveReferenceFromListLocked(*reference); |
| 202 | 225 | ||
| 203 | // Close the file. | 226 | // Close the file. |
| 204 | if (reference->file) { | 227 | if (reference->file) { |
| @@ -207,14 +230,14 @@ void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference | |||
| 207 | } | 230 | } |
| 208 | } | 231 | } |
| 209 | 232 | ||
| 210 | void RealVfsFilesystem::EvictSingleReference() { | 233 | void RealVfsFilesystem::EvictSingleReferenceLocked() { |
| 211 | if (num_open_files < MaxOpenFiles || open_references.empty()) { | 234 | if (num_open_files < MaxOpenFiles || open_references.empty()) { |
| 212 | return; | 235 | return; |
| 213 | } | 236 | } |
| 214 | 237 | ||
| 215 | // Get and remove from list. | 238 | // Get and remove from list. |
| 216 | auto& reference = open_references.back(); | 239 | auto& reference = open_references.back(); |
| 217 | this->RemoveReferenceFromList(reference); | 240 | this->RemoveReferenceFromListLocked(reference); |
| 218 | 241 | ||
| 219 | // Close the file. | 242 | // Close the file. |
| 220 | if (reference.file) { | 243 | if (reference.file) { |
| @@ -223,10 +246,10 @@ void RealVfsFilesystem::EvictSingleReference() { | |||
| 223 | } | 246 | } |
| 224 | 247 | ||
| 225 | // Reinsert into closed list. | 248 | // Reinsert into closed list. |
| 226 | this->InsertReferenceIntoList(reference); | 249 | this->InsertReferenceIntoListLocked(reference); |
| 227 | } | 250 | } |
| 228 | 251 | ||
| 229 | void RealVfsFilesystem::InsertReferenceIntoList(FileReference& reference) { | 252 | void RealVfsFilesystem::InsertReferenceIntoListLocked(FileReference& reference) { |
| 230 | if (reference.file) { | 253 | if (reference.file) { |
| 231 | open_references.push_front(reference); | 254 | open_references.push_front(reference); |
| 232 | } else { | 255 | } else { |
| @@ -234,7 +257,7 @@ void RealVfsFilesystem::InsertReferenceIntoList(FileReference& reference) { | |||
| 234 | } | 257 | } |
| 235 | } | 258 | } |
| 236 | 259 | ||
| 237 | void RealVfsFilesystem::RemoveReferenceFromList(FileReference& reference) { | 260 | void RealVfsFilesystem::RemoveReferenceFromListLocked(FileReference& reference) { |
| 238 | if (reference.file) { | 261 | if (reference.file) { |
| 239 | open_references.erase(open_references.iterator_to(reference)); | 262 | open_references.erase(open_references.iterator_to(reference)); |
| 240 | } else { | 263 | } else { |
| @@ -243,10 +266,10 @@ void RealVfsFilesystem::RemoveReferenceFromList(FileReference& reference) { | |||
| 243 | } | 266 | } |
| 244 | 267 | ||
| 245 | RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::unique_ptr<FileReference> reference_, | 268 | RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::unique_ptr<FileReference> reference_, |
| 246 | const std::string& path_, Mode perms_) | 269 | const std::string& path_, Mode perms_, std::optional<u64> size_) |
| 247 | : base(base_), reference(std::move(reference_)), path(path_), | 270 | : base(base_), reference(std::move(reference_)), path(path_), |
| 248 | parent_path(FS::GetParentPath(path_)), path_components(FS::SplitPathComponents(path_)), | 271 | parent_path(FS::GetParentPath(path_)), path_components(FS::SplitPathComponents(path_)), |
| 249 | perms(perms_) {} | 272 | size(size_), perms(perms_) {} |
| 250 | 273 | ||
| 251 | RealVfsFile::~RealVfsFile() { | 274 | RealVfsFile::~RealVfsFile() { |
| 252 | base.DropReference(std::move(reference)); | 275 | base.DropReference(std::move(reference)); |
| @@ -257,12 +280,15 @@ std::string RealVfsFile::GetName() const { | |||
| 257 | } | 280 | } |
| 258 | 281 | ||
| 259 | std::size_t RealVfsFile::GetSize() const { | 282 | std::size_t RealVfsFile::GetSize() const { |
| 260 | base.RefreshReference(path, perms, *reference); | 283 | if (size) { |
| 261 | return reference->file ? reference->file->GetSize() : 0; | 284 | return *size; |
| 285 | } | ||
| 286 | return FS::GetSize(path); | ||
| 262 | } | 287 | } |
| 263 | 288 | ||
| 264 | bool RealVfsFile::Resize(std::size_t new_size) { | 289 | bool RealVfsFile::Resize(std::size_t new_size) { |
| 265 | base.RefreshReference(path, perms, *reference); | 290 | size.reset(); |
| 291 | auto lk = base.RefreshReference(path, perms, *reference); | ||
| 266 | return reference->file ? reference->file->SetSize(new_size) : false; | 292 | return reference->file ? reference->file->SetSize(new_size) : false; |
| 267 | } | 293 | } |
| 268 | 294 | ||
| @@ -279,7 +305,7 @@ bool RealVfsFile::IsReadable() const { | |||
| 279 | } | 305 | } |
| 280 | 306 | ||
| 281 | std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { | 307 | std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { |
| 282 | base.RefreshReference(path, perms, *reference); | 308 | auto lk = base.RefreshReference(path, perms, *reference); |
| 283 | if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) { | 309 | if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) { |
| 284 | return 0; | 310 | return 0; |
| 285 | } | 311 | } |
| @@ -287,7 +313,8 @@ std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) | |||
| 287 | } | 313 | } |
| 288 | 314 | ||
| 289 | std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { | 315 | std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { |
| 290 | base.RefreshReference(path, perms, *reference); | 316 | size.reset(); |
| 317 | auto lk = base.RefreshReference(path, perms, *reference); | ||
| 291 | if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) { | 318 | if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) { |
| 292 | return 0; | 319 | return 0; |
| 293 | } | 320 | } |
| @@ -309,10 +336,11 @@ std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>( | |||
| 309 | 336 | ||
| 310 | std::vector<VirtualFile> out; | 337 | std::vector<VirtualFile> out; |
| 311 | 338 | ||
| 312 | const FS::DirEntryCallable callback = [this, &out](const std::filesystem::path& full_path) { | 339 | const FS::DirEntryCallable callback = [this, |
| 313 | const auto full_path_string = FS::PathToUTF8String(full_path); | 340 | &out](const std::filesystem::directory_entry& entry) { |
| 341 | const auto full_path_string = FS::PathToUTF8String(entry.path()); | ||
| 314 | 342 | ||
| 315 | out.emplace_back(base.OpenFile(full_path_string, perms)); | 343 | out.emplace_back(base.OpenFileFromEntry(full_path_string, entry.file_size(), perms)); |
| 316 | 344 | ||
| 317 | return true; | 345 | return true; |
| 318 | }; | 346 | }; |
| @@ -330,8 +358,9 @@ std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDi | |||
| 330 | 358 | ||
| 331 | std::vector<VirtualDir> out; | 359 | std::vector<VirtualDir> out; |
| 332 | 360 | ||
| 333 | const FS::DirEntryCallable callback = [this, &out](const std::filesystem::path& full_path) { | 361 | const FS::DirEntryCallable callback = [this, |
| 334 | const auto full_path_string = FS::PathToUTF8String(full_path); | 362 | &out](const std::filesystem::directory_entry& entry) { |
| 363 | const auto full_path_string = FS::PathToUTF8String(entry.path()); | ||
| 335 | 364 | ||
| 336 | out.emplace_back(base.OpenDirectory(full_path_string, perms)); | 365 | out.emplace_back(base.OpenDirectory(full_path_string, perms)); |
| 337 | 366 | ||
| @@ -483,12 +512,10 @@ std::map<std::string, VfsEntryType, std::less<>> RealVfsDirectory::GetEntries() | |||
| 483 | 512 | ||
| 484 | std::map<std::string, VfsEntryType, std::less<>> out; | 513 | std::map<std::string, VfsEntryType, std::less<>> out; |
| 485 | 514 | ||
| 486 | const FS::DirEntryCallable callback = [&out](const std::filesystem::path& full_path) { | 515 | const FS::DirEntryCallable callback = [&out](const std::filesystem::directory_entry& entry) { |
| 487 | const auto filename = FS::PathToUTF8String(full_path.filename()); | 516 | const auto filename = FS::PathToUTF8String(entry.path().filename()); |
| 488 | |||
| 489 | out.insert_or_assign(filename, | 517 | out.insert_or_assign(filename, |
| 490 | FS::IsDir(full_path) ? VfsEntryType::Directory : VfsEntryType::File); | 518 | entry.is_directory() ? VfsEntryType::Directory : VfsEntryType::File); |
| 491 | |||
| 492 | return true; | 519 | return true; |
| 493 | }; | 520 | }; |
| 494 | 521 | ||
diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h index d8c900e33..26ea7df62 100644 --- a/src/core/file_sys/vfs_real.h +++ b/src/core/file_sys/vfs_real.h | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <map> | 6 | #include <map> |
| 7 | #include <mutex> | ||
| 8 | #include <optional> | ||
| 7 | #include <string_view> | 9 | #include <string_view> |
| 8 | #include "common/intrusive_list.h" | 10 | #include "common/intrusive_list.h" |
| 9 | #include "core/file_sys/mode.h" | 11 | #include "core/file_sys/mode.h" |
| @@ -20,6 +22,8 @@ struct FileReference : public Common::IntrusiveListBaseNode<FileReference> { | |||
| 20 | }; | 22 | }; |
| 21 | 23 | ||
| 22 | class RealVfsFile; | 24 | class RealVfsFile; |
| 25 | class RealVfsDirectory; | ||
| 26 | |||
| 23 | class RealVfsFilesystem : public VfsFilesystem { | 27 | class RealVfsFilesystem : public VfsFilesystem { |
| 24 | public: | 28 | public: |
| 25 | RealVfsFilesystem(); | 29 | RealVfsFilesystem(); |
| @@ -45,17 +49,24 @@ private: | |||
| 45 | std::map<std::string, std::weak_ptr<VfsFile>, std::less<>> cache; | 49 | std::map<std::string, std::weak_ptr<VfsFile>, std::less<>> cache; |
| 46 | ReferenceListType open_references; | 50 | ReferenceListType open_references; |
| 47 | ReferenceListType closed_references; | 51 | ReferenceListType closed_references; |
| 52 | std::mutex list_lock; | ||
| 48 | size_t num_open_files{}; | 53 | size_t num_open_files{}; |
| 49 | 54 | ||
| 50 | private: | 55 | private: |
| 51 | friend class RealVfsFile; | 56 | friend class RealVfsFile; |
| 52 | void RefreshReference(const std::string& path, Mode perms, FileReference& reference); | 57 | std::unique_lock<std::mutex> RefreshReference(const std::string& path, Mode perms, |
| 58 | FileReference& reference); | ||
| 53 | void DropReference(std::unique_ptr<FileReference>&& reference); | 59 | void DropReference(std::unique_ptr<FileReference>&& reference); |
| 54 | void EvictSingleReference(); | ||
| 55 | 60 | ||
| 56 | private: | 61 | private: |
| 57 | void InsertReferenceIntoList(FileReference& reference); | 62 | friend class RealVfsDirectory; |
| 58 | void RemoveReferenceFromList(FileReference& reference); | 63 | VirtualFile OpenFileFromEntry(std::string_view path, std::optional<u64> size, |
| 64 | Mode perms = Mode::Read); | ||
| 65 | |||
| 66 | private: | ||
| 67 | void EvictSingleReferenceLocked(); | ||
| 68 | void InsertReferenceIntoListLocked(FileReference& reference); | ||
| 69 | void RemoveReferenceFromListLocked(FileReference& reference); | ||
| 59 | }; | 70 | }; |
| 60 | 71 | ||
| 61 | // An implementation of VfsFile that represents a file on the user's computer. | 72 | // An implementation of VfsFile that represents a file on the user's computer. |
| @@ -78,13 +89,14 @@ public: | |||
| 78 | 89 | ||
| 79 | private: | 90 | private: |
| 80 | RealVfsFile(RealVfsFilesystem& base, std::unique_ptr<FileReference> reference, | 91 | RealVfsFile(RealVfsFilesystem& base, std::unique_ptr<FileReference> reference, |
| 81 | const std::string& path, Mode perms = Mode::Read); | 92 | const std::string& path, Mode perms = Mode::Read, std::optional<u64> size = {}); |
| 82 | 93 | ||
| 83 | RealVfsFilesystem& base; | 94 | RealVfsFilesystem& base; |
| 84 | std::unique_ptr<FileReference> reference; | 95 | std::unique_ptr<FileReference> reference; |
| 85 | std::string path; | 96 | std::string path; |
| 86 | std::string parent_path; | 97 | std::string parent_path; |
| 87 | std::vector<std::string> path_components; | 98 | std::vector<std::string> path_components; |
| 99 | std::optional<u64> size; | ||
| 88 | Mode perms; | 100 | Mode perms; |
| 89 | }; | 101 | }; |
| 90 | 102 | ||
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 0a7777732..1ebc32c1e 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp | |||
| @@ -149,12 +149,16 @@ void EmulatedController::LoadDevices() { | |||
| 149 | 149 | ||
| 150 | camera_params[0] = right_joycon; | 150 | camera_params[0] = right_joycon; |
| 151 | camera_params[0].Set("camera", true); | 151 | camera_params[0].Set("camera", true); |
| 152 | camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"}; | ||
| 153 | ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"}; | ||
| 154 | nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"}; | ||
| 155 | nfc_params[1] = right_joycon; | 152 | nfc_params[1] = right_joycon; |
| 156 | nfc_params[1].Set("nfc", true); | 153 | nfc_params[1].Set("nfc", true); |
| 157 | 154 | ||
| 155 | // Only map virtual devices to the first controller | ||
| 156 | if (npad_id_type == NpadIdType::Player1 || npad_id_type == NpadIdType::Handheld) { | ||
| 157 | camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"}; | ||
| 158 | ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"}; | ||
| 159 | nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"}; | ||
| 160 | } | ||
| 161 | |||
| 158 | output_params[LeftIndex] = left_joycon; | 162 | output_params[LeftIndex] = left_joycon; |
| 159 | output_params[RightIndex] = right_joycon; | 163 | output_params[RightIndex] = right_joycon; |
| 160 | output_params[2] = camera_params[1]; | 164 | output_params[2] = camera_params[1]; |
| @@ -1176,10 +1180,7 @@ void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) { | |||
| 1176 | return; | 1180 | return; |
| 1177 | } | 1181 | } |
| 1178 | 1182 | ||
| 1179 | controller.nfc_state = { | 1183 | controller.nfc_state = controller.nfc_values; |
| 1180 | controller.nfc_values.state, | ||
| 1181 | controller.nfc_values.data, | ||
| 1182 | }; | ||
| 1183 | } | 1184 | } |
| 1184 | 1185 | ||
| 1185 | bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { | 1186 | bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { |
| @@ -1249,6 +1250,11 @@ Common::Input::DriverResult EmulatedController::SetPollingMode( | |||
| 1249 | const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode); | 1250 | const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode); |
| 1250 | const auto mapped_nfc_result = right_output_device->SetPollingMode(polling_mode); | 1251 | const auto mapped_nfc_result = right_output_device->SetPollingMode(polling_mode); |
| 1251 | 1252 | ||
| 1253 | // Restore previous state | ||
| 1254 | if (mapped_nfc_result != Common::Input::DriverResult::Success) { | ||
| 1255 | right_output_device->SetPollingMode(Common::Input::PollingMode::Active); | ||
| 1256 | } | ||
| 1257 | |||
| 1252 | if (virtual_nfc_result == Common::Input::DriverResult::Success) { | 1258 | if (virtual_nfc_result == Common::Input::DriverResult::Success) { |
| 1253 | return virtual_nfc_result; | 1259 | return virtual_nfc_result; |
| 1254 | } | 1260 | } |
| @@ -1308,6 +1314,79 @@ bool EmulatedController::HasNfc() const { | |||
| 1308 | return is_connected && (has_virtual_nfc && is_virtual_nfc_supported); | 1314 | return is_connected && (has_virtual_nfc && is_virtual_nfc_supported); |
| 1309 | } | 1315 | } |
| 1310 | 1316 | ||
| 1317 | bool EmulatedController::AddNfcHandle() { | ||
| 1318 | nfc_handles++; | ||
| 1319 | return SetPollingMode(EmulatedDeviceIndex::RightIndex, Common::Input::PollingMode::NFC) == | ||
| 1320 | Common::Input::DriverResult::Success; | ||
| 1321 | } | ||
| 1322 | |||
| 1323 | bool EmulatedController::RemoveNfcHandle() { | ||
| 1324 | nfc_handles--; | ||
| 1325 | if (nfc_handles <= 0) { | ||
| 1326 | return SetPollingMode(EmulatedDeviceIndex::RightIndex, | ||
| 1327 | Common::Input::PollingMode::Active) == | ||
| 1328 | Common::Input::DriverResult::Success; | ||
| 1329 | } | ||
| 1330 | return true; | ||
| 1331 | } | ||
| 1332 | |||
| 1333 | bool EmulatedController::StartNfcPolling() { | ||
| 1334 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | ||
| 1335 | auto& nfc_virtual_output_device = output_devices[3]; | ||
| 1336 | |||
| 1337 | const auto device_result = nfc_output_device->StartNfcPolling(); | ||
| 1338 | const auto virtual_device_result = nfc_virtual_output_device->StartNfcPolling(); | ||
| 1339 | |||
| 1340 | return device_result == Common::Input::NfcState::Success || | ||
| 1341 | virtual_device_result == Common::Input::NfcState::Success; | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | bool EmulatedController::StopNfcPolling() { | ||
| 1345 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | ||
| 1346 | auto& nfc_virtual_output_device = output_devices[3]; | ||
| 1347 | |||
| 1348 | const auto device_result = nfc_output_device->StopNfcPolling(); | ||
| 1349 | const auto virtual_device_result = nfc_virtual_output_device->StopNfcPolling(); | ||
| 1350 | |||
| 1351 | return device_result == Common::Input::NfcState::Success || | ||
| 1352 | virtual_device_result == Common::Input::NfcState::Success; | ||
| 1353 | } | ||
| 1354 | |||
| 1355 | bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) { | ||
| 1356 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | ||
| 1357 | auto& nfc_virtual_output_device = output_devices[3]; | ||
| 1358 | |||
| 1359 | if (nfc_output_device->ReadAmiiboData(data) == Common::Input::NfcState::Success) { | ||
| 1360 | return true; | ||
| 1361 | } | ||
| 1362 | |||
| 1363 | return nfc_virtual_output_device->ReadAmiiboData(data) == Common::Input::NfcState::Success; | ||
| 1364 | } | ||
| 1365 | |||
| 1366 | bool EmulatedController::ReadMifareData(const Common::Input::MifareRequest& request, | ||
| 1367 | Common::Input::MifareRequest& out_data) { | ||
| 1368 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | ||
| 1369 | auto& nfc_virtual_output_device = output_devices[3]; | ||
| 1370 | |||
| 1371 | if (nfc_output_device->ReadMifareData(request, out_data) == Common::Input::NfcState::Success) { | ||
| 1372 | return true; | ||
| 1373 | } | ||
| 1374 | |||
| 1375 | return nfc_virtual_output_device->ReadMifareData(request, out_data) == | ||
| 1376 | Common::Input::NfcState::Success; | ||
| 1377 | } | ||
| 1378 | |||
| 1379 | bool EmulatedController::WriteMifareData(const Common::Input::MifareRequest& request) { | ||
| 1380 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | ||
| 1381 | auto& nfc_virtual_output_device = output_devices[3]; | ||
| 1382 | |||
| 1383 | if (nfc_output_device->WriteMifareData(request) == Common::Input::NfcState::Success) { | ||
| 1384 | return true; | ||
| 1385 | } | ||
| 1386 | |||
| 1387 | return nfc_virtual_output_device->WriteMifareData(request) == Common::Input::NfcState::Success; | ||
| 1388 | } | ||
| 1389 | |||
| 1311 | bool EmulatedController::WriteNfc(const std::vector<u8>& data) { | 1390 | bool EmulatedController::WriteNfc(const std::vector<u8>& data) { |
| 1312 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | 1391 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; |
| 1313 | auto& nfc_virtual_output_device = output_devices[3]; | 1392 | auto& nfc_virtual_output_device = output_devices[3]; |
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 09fe1a0ab..d511e5fac 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h | |||
| @@ -97,10 +97,7 @@ struct RingSensorForce { | |||
| 97 | f32 force; | 97 | f32 force; |
| 98 | }; | 98 | }; |
| 99 | 99 | ||
| 100 | struct NfcState { | 100 | using NfcState = Common::Input::NfcStatus; |
| 101 | Common::Input::NfcState state{}; | ||
| 102 | std::vector<u8> data{}; | ||
| 103 | }; | ||
| 104 | 101 | ||
| 105 | struct ControllerMotion { | 102 | struct ControllerMotion { |
| 106 | Common::Vec3f accel{}; | 103 | Common::Vec3f accel{}; |
| @@ -393,9 +390,31 @@ public: | |||
| 393 | /// Returns true if the device has nfc support | 390 | /// Returns true if the device has nfc support |
| 394 | bool HasNfc() const; | 391 | bool HasNfc() const; |
| 395 | 392 | ||
| 393 | /// Sets the joycon in nfc mode and increments the handle count | ||
| 394 | bool AddNfcHandle(); | ||
| 395 | |||
| 396 | /// Decrements the handle count if zero sets the joycon in active mode | ||
| 397 | bool RemoveNfcHandle(); | ||
| 398 | |||
| 399 | /// Start searching for nfc tags | ||
| 400 | bool StartNfcPolling(); | ||
| 401 | |||
| 402 | /// Stop searching for nfc tags | ||
| 403 | bool StopNfcPolling(); | ||
| 404 | |||
| 405 | /// Returns true if the nfc tag was readable | ||
| 406 | bool ReadAmiiboData(std::vector<u8>& data); | ||
| 407 | |||
| 396 | /// Returns true if the nfc tag was written | 408 | /// Returns true if the nfc tag was written |
| 397 | bool WriteNfc(const std::vector<u8>& data); | 409 | bool WriteNfc(const std::vector<u8>& data); |
| 398 | 410 | ||
| 411 | /// Returns true if the nfc tag was readable | ||
| 412 | bool ReadMifareData(const Common::Input::MifareRequest& request, | ||
| 413 | Common::Input::MifareRequest& out_data); | ||
| 414 | |||
| 415 | /// Returns true if the nfc tag was written | ||
| 416 | bool WriteMifareData(const Common::Input::MifareRequest& request); | ||
| 417 | |||
| 399 | /// Returns the led pattern corresponding to this emulated controller | 418 | /// Returns the led pattern corresponding to this emulated controller |
| 400 | LedPattern GetLedPattern() const; | 419 | LedPattern GetLedPattern() const; |
| 401 | 420 | ||
| @@ -532,6 +551,7 @@ private: | |||
| 532 | bool system_buttons_enabled{true}; | 551 | bool system_buttons_enabled{true}; |
| 533 | f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; | 552 | f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; |
| 534 | u32 turbo_button_state{0}; | 553 | u32 turbo_button_state{0}; |
| 554 | std::size_t nfc_handles{0}; | ||
| 535 | 555 | ||
| 536 | // Temporary values to avoid doing changes while the controller is in configuring mode | 556 | // Temporary values to avoid doing changes while the controller is in configuring mode |
| 537 | NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; | 557 | NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; |
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 4ccb1c596..a05716fd8 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp | |||
| @@ -299,11 +299,7 @@ Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& cal | |||
| 299 | Common::Input::NfcStatus nfc{}; | 299 | Common::Input::NfcStatus nfc{}; |
| 300 | switch (callback.type) { | 300 | switch (callback.type) { |
| 301 | case Common::Input::InputType::Nfc: | 301 | case Common::Input::InputType::Nfc: |
| 302 | nfc = { | 302 | return callback.nfc_status; |
| 303 | .state = callback.nfc_status, | ||
| 304 | .data = callback.raw_data, | ||
| 305 | }; | ||
| 306 | break; | ||
| 307 | default: | 303 | default: |
| 308 | LOG_ERROR(Input, "Conversion from type {} to NFC not implemented", callback.type); | 304 | LOG_ERROR(Input, "Conversion from type {} to NFC not implemented", callback.type); |
| 309 | break; | 305 | break; |
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index faa12b4f0..75ce5a23c 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp | |||
| @@ -184,7 +184,8 @@ u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) { | |||
| 184 | prev_highest_thread != highest_thread) [[likely]] { | 184 | prev_highest_thread != highest_thread) [[likely]] { |
| 185 | if (prev_highest_thread != nullptr) [[likely]] { | 185 | if (prev_highest_thread != nullptr) [[likely]] { |
| 186 | IncrementScheduledCount(prev_highest_thread); | 186 | IncrementScheduledCount(prev_highest_thread); |
| 187 | prev_highest_thread->SetLastScheduledTick(m_kernel.System().CoreTiming().GetCPUTicks()); | 187 | prev_highest_thread->SetLastScheduledTick( |
| 188 | m_kernel.System().CoreTiming().GetClockTicks()); | ||
| 188 | } | 189 | } |
| 189 | if (m_state.should_count_idle) { | 190 | if (m_state.should_count_idle) { |
| 190 | if (highest_thread != nullptr) [[likely]] { | 191 | if (highest_thread != nullptr) [[likely]] { |
| @@ -351,7 +352,7 @@ void KScheduler::SwitchThread(KThread* next_thread) { | |||
| 351 | 352 | ||
| 352 | // Update the CPU time tracking variables. | 353 | // Update the CPU time tracking variables. |
| 353 | const s64 prev_tick = m_last_context_switch_time; | 354 | const s64 prev_tick = m_last_context_switch_time; |
| 354 | const s64 cur_tick = m_kernel.System().CoreTiming().GetCPUTicks(); | 355 | const s64 cur_tick = m_kernel.System().CoreTiming().GetClockTicks(); |
| 355 | const s64 tick_diff = cur_tick - prev_tick; | 356 | const s64 tick_diff = cur_tick - prev_tick; |
| 356 | cur_thread->AddCpuTime(m_core_id, tick_diff); | 357 | cur_thread->AddCpuTime(m_core_id, tick_diff); |
| 357 | if (cur_process != nullptr) { | 358 | if (cur_process != nullptr) { |
diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp index b7da3eee7..3e5b735b1 100644 --- a/src/core/hle/kernel/k_synchronization_object.cpp +++ b/src/core/hle/kernel/k_synchronization_object.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include "common/assert.h" | 4 | #include "common/assert.h" |
| 5 | #include "common/common_types.h" | 5 | #include "common/common_types.h" |
| 6 | #include "common/scratch_buffer.h" | ||
| 6 | #include "core/hle/kernel/k_scheduler.h" | 7 | #include "core/hle/kernel/k_scheduler.h" |
| 7 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 8 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 8 | #include "core/hle/kernel/k_synchronization_object.h" | 9 | #include "core/hle/kernel/k_synchronization_object.h" |
| @@ -75,7 +76,7 @@ Result KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, | |||
| 75 | KSynchronizationObject** objects, const s32 num_objects, | 76 | KSynchronizationObject** objects, const s32 num_objects, |
| 76 | s64 timeout) { | 77 | s64 timeout) { |
| 77 | // Allocate space on stack for thread nodes. | 78 | // Allocate space on stack for thread nodes. |
| 78 | std::vector<ThreadListNode> thread_nodes(num_objects); | 79 | std::array<ThreadListNode, Svc::ArgumentHandleCountMax> thread_nodes; |
| 79 | 80 | ||
| 80 | // Prepare for wait. | 81 | // Prepare for wait. |
| 81 | KThread* thread = GetCurrentThreadPointer(kernel); | 82 | KThread* thread = GetCurrentThreadPointer(kernel); |
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 908811e2c..adb6ec581 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp | |||
| @@ -909,7 +909,7 @@ Result KThread::SetActivity(Svc::ThreadActivity activity) { | |||
| 909 | R_SUCCEED(); | 909 | R_SUCCEED(); |
| 910 | } | 910 | } |
| 911 | 911 | ||
| 912 | Result KThread::GetThreadContext3(std::vector<u8>& out) { | 912 | Result KThread::GetThreadContext3(Common::ScratchBuffer<u8>& out) { |
| 913 | // Lock ourselves. | 913 | // Lock ourselves. |
| 914 | KScopedLightLock lk{m_activity_pause_lock}; | 914 | KScopedLightLock lk{m_activity_pause_lock}; |
| 915 | 915 | ||
| @@ -927,15 +927,13 @@ Result KThread::GetThreadContext3(std::vector<u8>& out) { | |||
| 927 | // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. | 927 | // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. |
| 928 | auto context = GetContext64(); | 928 | auto context = GetContext64(); |
| 929 | context.pstate &= 0xFF0FFE20; | 929 | context.pstate &= 0xFF0FFE20; |
| 930 | 930 | out.resize_destructive(sizeof(context)); | |
| 931 | out.resize(sizeof(context)); | ||
| 932 | std::memcpy(out.data(), std::addressof(context), sizeof(context)); | 931 | std::memcpy(out.data(), std::addressof(context), sizeof(context)); |
| 933 | } else { | 932 | } else { |
| 934 | // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. | 933 | // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. |
| 935 | auto context = GetContext32(); | 934 | auto context = GetContext32(); |
| 936 | context.cpsr &= 0xFF0FFE20; | 935 | context.cpsr &= 0xFF0FFE20; |
| 937 | 936 | out.resize_destructive(sizeof(context)); | |
| 938 | out.resize(sizeof(context)); | ||
| 939 | std::memcpy(out.data(), std::addressof(context), sizeof(context)); | 937 | std::memcpy(out.data(), std::addressof(context), sizeof(context)); |
| 940 | } | 938 | } |
| 941 | } | 939 | } |
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 37fe5db77..dd662b3f8 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include "common/intrusive_list.h" | 15 | #include "common/intrusive_list.h" |
| 16 | 16 | ||
| 17 | #include "common/intrusive_red_black_tree.h" | 17 | #include "common/intrusive_red_black_tree.h" |
| 18 | #include "common/scratch_buffer.h" | ||
| 18 | #include "common/spin_lock.h" | 19 | #include "common/spin_lock.h" |
| 19 | #include "core/arm/arm_interface.h" | 20 | #include "core/arm/arm_interface.h" |
| 20 | #include "core/hle/kernel/k_affinity_mask.h" | 21 | #include "core/hle/kernel/k_affinity_mask.h" |
| @@ -567,7 +568,7 @@ public: | |||
| 567 | 568 | ||
| 568 | void RemoveWaiter(KThread* thread); | 569 | void RemoveWaiter(KThread* thread); |
| 569 | 570 | ||
| 570 | Result GetThreadContext3(std::vector<u8>& out); | 571 | Result GetThreadContext3(Common::ScratchBuffer<u8>& out); |
| 571 | 572 | ||
| 572 | KThread* RemoveUserWaiterByKey(bool* out_has_waiters, KProcessAddress key) { | 573 | KThread* RemoveUserWaiterByKey(bool* out_has_waiters, KProcessAddress key) { |
| 573 | return this->RemoveWaiterByKey(out_has_waiters, key, false); | 574 | return this->RemoveWaiterByKey(out_has_waiters, key, false); |
diff --git a/src/core/hle/kernel/svc/svc_info.cpp b/src/core/hle/kernel/svc/svc_info.cpp index 2b2c878b5..445cdd87b 100644 --- a/src/core/hle/kernel/svc/svc_info.cpp +++ b/src/core/hle/kernel/svc/svc_info.cpp | |||
| @@ -199,9 +199,9 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle | |||
| 199 | if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { | 199 | if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { |
| 200 | const u64 thread_ticks = current_thread->GetCpuTime(); | 200 | const u64 thread_ticks = current_thread->GetCpuTime(); |
| 201 | 201 | ||
| 202 | out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks); | 202 | out_ticks = thread_ticks + (core_timing.GetClockTicks() - prev_ctx_ticks); |
| 203 | } else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) { | 203 | } else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) { |
| 204 | out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks; | 204 | out_ticks = core_timing.GetClockTicks() - prev_ctx_ticks; |
| 205 | } | 205 | } |
| 206 | 206 | ||
| 207 | *result = out_ticks; | 207 | *result = out_ticks; |
diff --git a/src/core/hle/kernel/svc/svc_ipc.cpp b/src/core/hle/kernel/svc/svc_ipc.cpp index ea03068aa..60247df2e 100644 --- a/src/core/hle/kernel/svc/svc_ipc.cpp +++ b/src/core/hle/kernel/svc/svc_ipc.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "common/scope_exit.h" | 4 | #include "common/scope_exit.h" |
| 5 | #include "common/scratch_buffer.h" | ||
| 5 | #include "core/core.h" | 6 | #include "core/core.h" |
| 6 | #include "core/hle/kernel/k_client_session.h" | 7 | #include "core/hle/kernel/k_client_session.h" |
| 7 | #include "core/hle/kernel/k_process.h" | 8 | #include "core/hle/kernel/k_process.h" |
| @@ -45,11 +46,11 @@ Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_ad | |||
| 45 | handles_addr, static_cast<u64>(sizeof(Handle) * num_handles)), | 46 | handles_addr, static_cast<u64>(sizeof(Handle) * num_handles)), |
| 46 | ResultInvalidPointer); | 47 | ResultInvalidPointer); |
| 47 | 48 | ||
| 48 | std::vector<Handle> handles(num_handles); | 49 | std::array<Handle, Svc::ArgumentHandleCountMax> handles; |
| 49 | GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(), sizeof(Handle) * num_handles); | 50 | GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(), sizeof(Handle) * num_handles); |
| 50 | 51 | ||
| 51 | // Convert handle list to object table. | 52 | // Convert handle list to object table. |
| 52 | std::vector<KSynchronizationObject*> objs(num_handles); | 53 | std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> objs; |
| 53 | R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles.data(), | 54 | R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles.data(), |
| 54 | num_handles), | 55 | num_handles), |
| 55 | ResultInvalidHandle); | 56 | ResultInvalidHandle); |
| @@ -80,7 +81,7 @@ Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_ad | |||
| 80 | // Wait for an object. | 81 | // Wait for an object. |
| 81 | s32 index; | 82 | s32 index; |
| 82 | Result result = KSynchronizationObject::Wait(kernel, std::addressof(index), objs.data(), | 83 | Result result = KSynchronizationObject::Wait(kernel, std::addressof(index), objs.data(), |
| 83 | static_cast<s32>(objs.size()), timeout_ns); | 84 | num_handles, timeout_ns); |
| 84 | if (result == ResultTimedOut) { | 85 | if (result == ResultTimedOut) { |
| 85 | R_RETURN(result); | 86 | R_RETURN(result); |
| 86 | } | 87 | } |
diff --git a/src/core/hle/kernel/svc/svc_synchronization.cpp b/src/core/hle/kernel/svc/svc_synchronization.cpp index 04d65f0bd..53df5bcd8 100644 --- a/src/core/hle/kernel/svc/svc_synchronization.cpp +++ b/src/core/hle/kernel/svc/svc_synchronization.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "common/scope_exit.h" | 4 | #include "common/scope_exit.h" |
| 5 | #include "common/scratch_buffer.h" | ||
| 5 | #include "core/core.h" | 6 | #include "core/core.h" |
| 6 | #include "core/hle/kernel/k_process.h" | 7 | #include "core/hle/kernel/k_process.h" |
| 7 | #include "core/hle/kernel/k_readable_event.h" | 8 | #include "core/hle/kernel/k_readable_event.h" |
| @@ -54,7 +55,7 @@ static Result WaitSynchronization(Core::System& system, int32_t* out_index, cons | |||
| 54 | // Get the synchronization context. | 55 | // Get the synchronization context. |
| 55 | auto& kernel = system.Kernel(); | 56 | auto& kernel = system.Kernel(); |
| 56 | auto& handle_table = GetCurrentProcess(kernel).GetHandleTable(); | 57 | auto& handle_table = GetCurrentProcess(kernel).GetHandleTable(); |
| 57 | std::vector<KSynchronizationObject*> objs(num_handles); | 58 | std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> objs; |
| 58 | 59 | ||
| 59 | // Copy user handles. | 60 | // Copy user handles. |
| 60 | if (num_handles > 0) { | 61 | if (num_handles > 0) { |
| @@ -72,8 +73,8 @@ static Result WaitSynchronization(Core::System& system, int32_t* out_index, cons | |||
| 72 | }); | 73 | }); |
| 73 | 74 | ||
| 74 | // Wait on the objects. | 75 | // Wait on the objects. |
| 75 | Result res = KSynchronizationObject::Wait(kernel, out_index, objs.data(), | 76 | Result res = |
| 76 | static_cast<s32>(objs.size()), timeout_ns); | 77 | KSynchronizationObject::Wait(kernel, out_index, objs.data(), num_handles, timeout_ns); |
| 77 | 78 | ||
| 78 | R_SUCCEED_IF(res == ResultSessionClosed); | 79 | R_SUCCEED_IF(res == ResultSessionClosed); |
| 79 | R_RETURN(res); | 80 | R_RETURN(res); |
| @@ -87,8 +88,7 @@ Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_ha | |||
| 87 | 88 | ||
| 88 | // Ensure number of handles is valid. | 89 | // Ensure number of handles is valid. |
| 89 | R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange); | 90 | R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange); |
| 90 | 91 | std::array<Handle, Svc::ArgumentHandleCountMax> handles; | |
| 91 | std::vector<Handle> handles(num_handles); | ||
| 92 | if (num_handles > 0) { | 92 | if (num_handles > 0) { |
| 93 | GetCurrentMemory(system.Kernel()) | 93 | GetCurrentMemory(system.Kernel()) |
| 94 | .ReadBlock(user_handles, handles.data(), num_handles * sizeof(Handle)); | 94 | .ReadBlock(user_handles, handles.data(), num_handles * sizeof(Handle)); |
diff --git a/src/core/hle/kernel/svc/svc_thread.cpp b/src/core/hle/kernel/svc/svc_thread.cpp index 37b54079c..36b94e6bf 100644 --- a/src/core/hle/kernel/svc/svc_thread.cpp +++ b/src/core/hle/kernel/svc/svc_thread.cpp | |||
| @@ -174,7 +174,7 @@ Result GetThreadContext3(Core::System& system, u64 out_context, Handle thread_ha | |||
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | // Get the thread context. | 176 | // Get the thread context. |
| 177 | std::vector<u8> context; | 177 | static thread_local Common::ScratchBuffer<u8> context; |
| 178 | R_TRY(thread->GetThreadContext3(context)); | 178 | R_TRY(thread->GetThreadContext3(context)); |
| 179 | 179 | ||
| 180 | // Copy the thread context to user space. | 180 | // Copy the thread context to user space. |
diff --git a/src/core/hle/kernel/svc/svc_tick.cpp b/src/core/hle/kernel/svc/svc_tick.cpp index 561336482..7dd7c6e51 100644 --- a/src/core/hle/kernel/svc/svc_tick.cpp +++ b/src/core/hle/kernel/svc/svc_tick.cpp | |||
| @@ -12,16 +12,8 @@ namespace Kernel::Svc { | |||
| 12 | int64_t GetSystemTick(Core::System& system) { | 12 | int64_t GetSystemTick(Core::System& system) { |
| 13 | LOG_TRACE(Kernel_SVC, "called"); | 13 | LOG_TRACE(Kernel_SVC, "called"); |
| 14 | 14 | ||
| 15 | auto& core_timing = system.CoreTiming(); | ||
| 16 | |||
| 17 | // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) | 15 | // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) |
| 18 | const u64 result{core_timing.GetClockTicks()}; | 16 | return static_cast<int64_t>(system.CoreTiming().GetClockTicks()); |
| 19 | |||
| 20 | if (!system.Kernel().IsMulticore()) { | ||
| 21 | core_timing.AddTicks(400U); | ||
| 22 | } | ||
| 23 | |||
| 24 | return static_cast<int64_t>(result); | ||
| 25 | } | 17 | } |
| 26 | 18 | ||
| 27 | int64_t GetSystemTick64(Core::System& system) { | 19 | int64_t GetSystemTick64(Core::System& system) { |
diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp index 8b754e9d4..19ed184e8 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp | |||
| @@ -141,7 +141,7 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) | |||
| 141 | applet_output.device_handle = applet_input_common.device_handle; | 141 | applet_output.device_handle = applet_input_common.device_handle; |
| 142 | applet_output.result = CabinetResult::Cancel; | 142 | applet_output.result = CabinetResult::Cancel; |
| 143 | const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info); | 143 | const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info); |
| 144 | const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info, false); | 144 | const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info); |
| 145 | nfp_device->Finalize(); | 145 | nfp_device->Finalize(); |
| 146 | 146 | ||
| 147 | if (reg_result.IsSuccess()) { | 147 | if (reg_result.IsSuccess()) { |
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp index f0640c64f..c8d574993 100644 --- a/src/core/hle/service/audio/audin_u.cpp +++ b/src/core/hle/service/audio/audin_u.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include "audio_core/renderer/audio_device.h" | 5 | #include "audio_core/renderer/audio_device.h" |
| 6 | #include "common/common_funcs.h" | 6 | #include "common/common_funcs.h" |
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "common/settings.h" | ||
| 8 | #include "common/string_util.h" | 9 | #include "common/string_util.h" |
| 9 | #include "core/core.h" | 10 | #include "core/core.h" |
| 10 | #include "core/hle/kernel/k_event.h" | 11 | #include "core/hle/kernel/k_event.h" |
| @@ -123,19 +124,13 @@ private: | |||
| 123 | 124 | ||
| 124 | void GetReleasedAudioInBuffer(HLERequestContext& ctx) { | 125 | void GetReleasedAudioInBuffer(HLERequestContext& ctx) { |
| 125 | const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>(); | 126 | const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>(); |
| 126 | std::vector<u64> released_buffers(write_buffer_size); | 127 | tmp_buffer.resize_destructive(write_buffer_size); |
| 128 | tmp_buffer[0] = 0; | ||
| 127 | 129 | ||
| 128 | const auto count = impl->GetReleasedBuffers(released_buffers); | 130 | const auto count = impl->GetReleasedBuffers(tmp_buffer); |
| 129 | 131 | ||
| 130 | [[maybe_unused]] std::string tags{}; | 132 | ctx.WriteBuffer(tmp_buffer); |
| 131 | for (u32 i = 0; i < count; i++) { | ||
| 132 | tags += fmt::format("{:08X}, ", released_buffers[i]); | ||
| 133 | } | ||
| 134 | [[maybe_unused]] auto sessionid{impl->GetSystem().GetSessionId()}; | ||
| 135 | LOG_TRACE(Service_Audio, "called. Session {} released {} buffers: {}", sessionid, count, | ||
| 136 | tags); | ||
| 137 | 133 | ||
| 138 | ctx.WriteBuffer(released_buffers); | ||
| 139 | IPC::ResponseBuilder rb{ctx, 3}; | 134 | IPC::ResponseBuilder rb{ctx, 3}; |
| 140 | rb.Push(ResultSuccess); | 135 | rb.Push(ResultSuccess); |
| 141 | rb.Push(count); | 136 | rb.Push(count); |
| @@ -200,6 +195,7 @@ private: | |||
| 200 | KernelHelpers::ServiceContext service_context; | 195 | KernelHelpers::ServiceContext service_context; |
| 201 | Kernel::KEvent* event; | 196 | Kernel::KEvent* event; |
| 202 | std::shared_ptr<AudioCore::AudioIn::In> impl; | 197 | std::shared_ptr<AudioCore::AudioIn::In> impl; |
| 198 | Common::ScratchBuffer<u64> tmp_buffer; | ||
| 203 | }; | 199 | }; |
| 204 | 200 | ||
| 205 | AudInU::AudInU(Core::System& system_) | 201 | AudInU::AudInU(Core::System& system_) |
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 3e62fa4fc..032c8c11f 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp | |||
| @@ -123,19 +123,13 @@ private: | |||
| 123 | 123 | ||
| 124 | void GetReleasedAudioOutBuffers(HLERequestContext& ctx) { | 124 | void GetReleasedAudioOutBuffers(HLERequestContext& ctx) { |
| 125 | const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>(); | 125 | const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>(); |
| 126 | std::vector<u64> released_buffers(write_buffer_size); | 126 | tmp_buffer.resize_destructive(write_buffer_size); |
| 127 | tmp_buffer[0] = 0; | ||
| 127 | 128 | ||
| 128 | const auto count = impl->GetReleasedBuffers(released_buffers); | 129 | const auto count = impl->GetReleasedBuffers(tmp_buffer); |
| 129 | 130 | ||
| 130 | [[maybe_unused]] std::string tags{}; | 131 | ctx.WriteBuffer(tmp_buffer); |
| 131 | for (u32 i = 0; i < count; i++) { | ||
| 132 | tags += fmt::format("{:08X}, ", released_buffers[i]); | ||
| 133 | } | ||
| 134 | [[maybe_unused]] const auto sessionid{impl->GetSystem().GetSessionId()}; | ||
| 135 | LOG_TRACE(Service_Audio, "called. Session {} released {} buffers: {}", sessionid, count, | ||
| 136 | tags); | ||
| 137 | 132 | ||
| 138 | ctx.WriteBuffer(released_buffers); | ||
| 139 | IPC::ResponseBuilder rb{ctx, 3}; | 133 | IPC::ResponseBuilder rb{ctx, 3}; |
| 140 | rb.Push(ResultSuccess); | 134 | rb.Push(ResultSuccess); |
| 141 | rb.Push(count); | 135 | rb.Push(count); |
| @@ -211,6 +205,7 @@ private: | |||
| 211 | KernelHelpers::ServiceContext service_context; | 205 | KernelHelpers::ServiceContext service_context; |
| 212 | Kernel::KEvent* event; | 206 | Kernel::KEvent* event; |
| 213 | std::shared_ptr<AudioCore::AudioOut::Out> impl; | 207 | std::shared_ptr<AudioCore::AudioOut::Out> impl; |
| 208 | Common::ScratchBuffer<u64> tmp_buffer; | ||
| 214 | }; | 209 | }; |
| 215 | 210 | ||
| 216 | AudOutU::AudOutU(Core::System& system_) | 211 | AudOutU::AudOutU(Core::System& system_) |
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 7086d4750..12845c23a 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp | |||
| @@ -116,28 +116,26 @@ private: | |||
| 116 | // These buffers are written manually to avoid an issue with WriteBuffer throwing errors for | 116 | // These buffers are written manually to avoid an issue with WriteBuffer throwing errors for |
| 117 | // checking size 0. Performance size is 0 for most games. | 117 | // checking size 0. Performance size is 0 for most games. |
| 118 | 118 | ||
| 119 | std::vector<u8> output{}; | ||
| 120 | std::vector<u8> performance{}; | ||
| 121 | auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0}; | 119 | auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0}; |
| 122 | if (is_buffer_b) { | 120 | if (is_buffer_b) { |
| 123 | const auto buffersB{ctx.BufferDescriptorB()}; | 121 | const auto buffersB{ctx.BufferDescriptorB()}; |
| 124 | output.resize(buffersB[0].Size(), 0); | 122 | tmp_output.resize_destructive(buffersB[0].Size()); |
| 125 | performance.resize(buffersB[1].Size(), 0); | 123 | tmp_performance.resize_destructive(buffersB[1].Size()); |
| 126 | } else { | 124 | } else { |
| 127 | const auto buffersC{ctx.BufferDescriptorC()}; | 125 | const auto buffersC{ctx.BufferDescriptorC()}; |
| 128 | output.resize(buffersC[0].Size(), 0); | 126 | tmp_output.resize_destructive(buffersC[0].Size()); |
| 129 | performance.resize(buffersC[1].Size(), 0); | 127 | tmp_performance.resize_destructive(buffersC[1].Size()); |
| 130 | } | 128 | } |
| 131 | 129 | ||
| 132 | auto result = impl->RequestUpdate(input, performance, output); | 130 | auto result = impl->RequestUpdate(input, tmp_performance, tmp_output); |
| 133 | 131 | ||
| 134 | if (result.IsSuccess()) { | 132 | if (result.IsSuccess()) { |
| 135 | if (is_buffer_b) { | 133 | if (is_buffer_b) { |
| 136 | ctx.WriteBufferB(output.data(), output.size(), 0); | 134 | ctx.WriteBufferB(tmp_output.data(), tmp_output.size(), 0); |
| 137 | ctx.WriteBufferB(performance.data(), performance.size(), 1); | 135 | ctx.WriteBufferB(tmp_performance.data(), tmp_performance.size(), 1); |
| 138 | } else { | 136 | } else { |
| 139 | ctx.WriteBufferC(output.data(), output.size(), 0); | 137 | ctx.WriteBufferC(tmp_output.data(), tmp_output.size(), 0); |
| 140 | ctx.WriteBufferC(performance.data(), performance.size(), 1); | 138 | ctx.WriteBufferC(tmp_performance.data(), tmp_performance.size(), 1); |
| 141 | } | 139 | } |
| 142 | } else { | 140 | } else { |
| 143 | LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.description); | 141 | LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.description); |
| @@ -235,6 +233,8 @@ private: | |||
| 235 | Kernel::KEvent* rendered_event; | 233 | Kernel::KEvent* rendered_event; |
| 236 | Manager& manager; | 234 | Manager& manager; |
| 237 | std::unique_ptr<Renderer> impl; | 235 | std::unique_ptr<Renderer> impl; |
| 236 | Common::ScratchBuffer<u8> tmp_output; | ||
| 237 | Common::ScratchBuffer<u8> tmp_performance; | ||
| 238 | }; | 238 | }; |
| 239 | 239 | ||
| 240 | class IAudioDevice final : public ServiceFramework<IAudioDevice> { | 240 | class IAudioDevice final : public ServiceFramework<IAudioDevice> { |
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index 24ce37e87..d8e9c8719 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include "audio_core/audio_render_manager.h" | 6 | #include "audio_core/audio_render_manager.h" |
| 7 | #include "common/scratch_buffer.h" | ||
| 7 | #include "core/hle/service/kernel_helpers.h" | 8 | #include "core/hle/service/kernel_helpers.h" |
| 8 | #include "core/hle/service/service.h" | 9 | #include "core/hle/service/service.h" |
| 9 | 10 | ||
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 451ac224a..c835f6cb7 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp | |||
| @@ -68,13 +68,13 @@ private: | |||
| 68 | ExtraBehavior extra_behavior) { | 68 | ExtraBehavior extra_behavior) { |
| 69 | u32 consumed = 0; | 69 | u32 consumed = 0; |
| 70 | u32 sample_count = 0; | 70 | u32 sample_count = 0; |
| 71 | std::vector<opus_int16> samples(ctx.GetWriteBufferNumElements<opus_int16>()); | 71 | tmp_samples.resize_destructive(ctx.GetWriteBufferNumElements<opus_int16>()); |
| 72 | 72 | ||
| 73 | if (extra_behavior == ExtraBehavior::ResetContext) { | 73 | if (extra_behavior == ExtraBehavior::ResetContext) { |
| 74 | ResetDecoderContext(); | 74 | ResetDecoderContext(); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | if (!DecodeOpusData(consumed, sample_count, ctx.ReadBuffer(), samples, performance)) { | 77 | if (!DecodeOpusData(consumed, sample_count, ctx.ReadBuffer(), tmp_samples, performance)) { |
| 78 | LOG_ERROR(Audio, "Failed to decode opus data"); | 78 | LOG_ERROR(Audio, "Failed to decode opus data"); |
| 79 | IPC::ResponseBuilder rb{ctx, 2}; | 79 | IPC::ResponseBuilder rb{ctx, 2}; |
| 80 | // TODO(ogniK): Use correct error code | 80 | // TODO(ogniK): Use correct error code |
| @@ -90,11 +90,11 @@ private: | |||
| 90 | if (performance) { | 90 | if (performance) { |
| 91 | rb.Push<u64>(*performance); | 91 | rb.Push<u64>(*performance); |
| 92 | } | 92 | } |
| 93 | ctx.WriteBuffer(samples); | 93 | ctx.WriteBuffer(tmp_samples); |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | bool DecodeOpusData(u32& consumed, u32& sample_count, std::span<const u8> input, | 96 | bool DecodeOpusData(u32& consumed, u32& sample_count, std::span<const u8> input, |
| 97 | std::vector<opus_int16>& output, u64* out_performance_time) const { | 97 | std::span<opus_int16> output, u64* out_performance_time) const { |
| 98 | const auto start_time = std::chrono::steady_clock::now(); | 98 | const auto start_time = std::chrono::steady_clock::now(); |
| 99 | const std::size_t raw_output_sz = output.size() * sizeof(opus_int16); | 99 | const std::size_t raw_output_sz = output.size() * sizeof(opus_int16); |
| 100 | if (sizeof(OpusPacketHeader) > input.size()) { | 100 | if (sizeof(OpusPacketHeader) > input.size()) { |
| @@ -154,6 +154,7 @@ private: | |||
| 154 | OpusDecoderPtr decoder; | 154 | OpusDecoderPtr decoder; |
| 155 | u32 sample_rate; | 155 | u32 sample_rate; |
| 156 | u32 channel_count; | 156 | u32 channel_count; |
| 157 | Common::ScratchBuffer<opus_int16> tmp_samples; | ||
| 157 | }; | 158 | }; |
| 158 | 159 | ||
| 159 | class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> { | 160 | class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> { |
diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp index 5604a6fda..80aac221b 100644 --- a/src/core/hle/service/hid/hidbus.cpp +++ b/src/core/hle/service/hid/hidbus.cpp | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #include "common/settings.h" | 5 | #include "common/settings.h" |
| 6 | #include "core/core.h" | 6 | #include "core/core.h" |
| 7 | #include "core/core_timing.h" | 7 | #include "core/core_timing.h" |
| 8 | #include "core/core_timing_util.h" | ||
| 9 | #include "core/hid/hid_types.h" | 8 | #include "core/hid/hid_types.h" |
| 10 | #include "core/hle/kernel/k_event.h" | 9 | #include "core/hle/kernel/k_event.h" |
| 11 | #include "core/hle/kernel/k_readable_event.h" | 10 | #include "core/hle/kernel/k_readable_event.h" |
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp index f4b180b06..5bf289818 100644 --- a/src/core/hle/service/nfc/common/device.cpp +++ b/src/core/hle/service/nfc/common/device.cpp | |||
| @@ -93,7 +93,8 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { | |||
| 93 | const auto nfc_status = npad_device->GetNfc(); | 93 | const auto nfc_status = npad_device->GetNfc(); |
| 94 | switch (nfc_status.state) { | 94 | switch (nfc_status.state) { |
| 95 | case Common::Input::NfcState::NewAmiibo: | 95 | case Common::Input::NfcState::NewAmiibo: |
| 96 | LoadNfcTag(nfc_status.data); | 96 | LoadNfcTag(nfc_status.protocol, nfc_status.tag_type, nfc_status.uuid_length, |
| 97 | nfc_status.uuid); | ||
| 97 | break; | 98 | break; |
| 98 | case Common::Input::NfcState::AmiiboRemoved: | 99 | case Common::Input::NfcState::AmiiboRemoved: |
| 99 | if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { | 100 | if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { |
| @@ -108,28 +109,46 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { | |||
| 108 | } | 109 | } |
| 109 | } | 110 | } |
| 110 | 111 | ||
| 111 | bool NfcDevice::LoadNfcTag(std::span<const u8> data) { | 112 | bool NfcDevice::LoadNfcTag(u8 protocol, u8 tag_type, u8 uuid_length, UniqueSerialNumber uuid) { |
| 112 | if (device_state != DeviceState::SearchingForTag) { | 113 | if (device_state != DeviceState::SearchingForTag) { |
| 113 | LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state); | 114 | LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state); |
| 114 | return false; | 115 | return false; |
| 115 | } | 116 | } |
| 116 | 117 | ||
| 118 | if ((protocol & static_cast<u8>(allowed_protocols)) == 0) { | ||
| 119 | LOG_ERROR(Service_NFC, "Protocol not supported {}", protocol); | ||
| 120 | return false; | ||
| 121 | } | ||
| 122 | |||
| 123 | real_tag_info = { | ||
| 124 | .uuid = uuid, | ||
| 125 | .uuid_length = uuid_length, | ||
| 126 | .protocol = static_cast<NfcProtocol>(protocol), | ||
| 127 | .tag_type = static_cast<TagType>(tag_type), | ||
| 128 | }; | ||
| 129 | |||
| 130 | device_state = DeviceState::TagFound; | ||
| 131 | deactivate_event->GetReadableEvent().Clear(); | ||
| 132 | activate_event->Signal(); | ||
| 133 | return true; | ||
| 134 | } | ||
| 135 | |||
| 136 | bool NfcDevice::LoadAmiiboData() { | ||
| 137 | std::vector<u8> data{}; | ||
| 138 | |||
| 139 | if (!npad_device->ReadAmiiboData(data)) { | ||
| 140 | return false; | ||
| 141 | } | ||
| 142 | |||
| 117 | if (data.size() < sizeof(NFP::EncryptedNTAG215File)) { | 143 | if (data.size() < sizeof(NFP::EncryptedNTAG215File)) { |
| 118 | LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size()); | 144 | LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size()); |
| 119 | return false; | 145 | return false; |
| 120 | } | 146 | } |
| 121 | 147 | ||
| 122 | mifare_data.resize(data.size()); | ||
| 123 | memcpy(mifare_data.data(), data.data(), data.size()); | ||
| 124 | |||
| 125 | memcpy(&tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); | 148 | memcpy(&tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); |
| 126 | is_plain_amiibo = NFP::AmiiboCrypto::IsAmiiboValid(tag_data); | 149 | is_plain_amiibo = NFP::AmiiboCrypto::IsAmiiboValid(tag_data); |
| 127 | is_write_protected = false; | 150 | is_write_protected = false; |
| 128 | 151 | ||
| 129 | device_state = DeviceState::TagFound; | ||
| 130 | deactivate_event->GetReadableEvent().Clear(); | ||
| 131 | activate_event->Signal(); | ||
| 132 | |||
| 133 | // Fallback for plain amiibos | 152 | // Fallback for plain amiibos |
| 134 | if (is_plain_amiibo) { | 153 | if (is_plain_amiibo) { |
| 135 | LOG_INFO(Service_NFP, "Using plain amiibo"); | 154 | LOG_INFO(Service_NFP, "Using plain amiibo"); |
| @@ -147,6 +166,7 @@ bool NfcDevice::LoadNfcTag(std::span<const u8> data) { | |||
| 147 | return true; | 166 | return true; |
| 148 | } | 167 | } |
| 149 | 168 | ||
| 169 | LOG_INFO(Service_NFP, "Using encrypted amiibo"); | ||
| 150 | tag_data = {}; | 170 | tag_data = {}; |
| 151 | memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); | 171 | memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); |
| 152 | return true; | 172 | return true; |
| @@ -162,7 +182,6 @@ void NfcDevice::CloseNfcTag() { | |||
| 162 | device_state = DeviceState::TagRemoved; | 182 | device_state = DeviceState::TagRemoved; |
| 163 | encrypted_tag_data = {}; | 183 | encrypted_tag_data = {}; |
| 164 | tag_data = {}; | 184 | tag_data = {}; |
| 165 | mifare_data = {}; | ||
| 166 | activate_event->GetReadableEvent().Clear(); | 185 | activate_event->GetReadableEvent().Clear(); |
| 167 | deactivate_event->Signal(); | 186 | deactivate_event->Signal(); |
| 168 | } | 187 | } |
| @@ -179,8 +198,12 @@ void NfcDevice::Initialize() { | |||
| 179 | device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable; | 198 | device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable; |
| 180 | encrypted_tag_data = {}; | 199 | encrypted_tag_data = {}; |
| 181 | tag_data = {}; | 200 | tag_data = {}; |
| 182 | mifare_data = {}; | 201 | |
| 183 | is_initalized = true; | 202 | if (device_state != DeviceState::Initialized) { |
| 203 | return; | ||
| 204 | } | ||
| 205 | |||
| 206 | is_initalized = npad_device->AddNfcHandle(); | ||
| 184 | } | 207 | } |
| 185 | 208 | ||
| 186 | void NfcDevice::Finalize() { | 209 | void NfcDevice::Finalize() { |
| @@ -190,6 +213,11 @@ void NfcDevice::Finalize() { | |||
| 190 | if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { | 213 | if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { |
| 191 | StopDetection(); | 214 | StopDetection(); |
| 192 | } | 215 | } |
| 216 | |||
| 217 | if (device_state != DeviceState::Unavailable) { | ||
| 218 | npad_device->RemoveNfcHandle(); | ||
| 219 | } | ||
| 220 | |||
| 193 | device_state = DeviceState::Unavailable; | 221 | device_state = DeviceState::Unavailable; |
| 194 | is_initalized = false; | 222 | is_initalized = false; |
| 195 | } | 223 | } |
| @@ -200,10 +228,8 @@ Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) { | |||
| 200 | return ResultWrongDeviceState; | 228 | return ResultWrongDeviceState; |
| 201 | } | 229 | } |
| 202 | 230 | ||
| 203 | if (npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, | 231 | if (!npad_device->StartNfcPolling()) { |
| 204 | Common::Input::PollingMode::NFC) != | 232 | LOG_ERROR(Service_NFC, "Nfc polling not supported"); |
| 205 | Common::Input::DriverResult::Success) { | ||
| 206 | LOG_ERROR(Service_NFC, "Nfc not supported"); | ||
| 207 | return ResultNfcDisabled; | 233 | return ResultNfcDisabled; |
| 208 | } | 234 | } |
| 209 | 235 | ||
| @@ -213,9 +239,6 @@ Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) { | |||
| 213 | } | 239 | } |
| 214 | 240 | ||
| 215 | Result NfcDevice::StopDetection() { | 241 | Result NfcDevice::StopDetection() { |
| 216 | npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, | ||
| 217 | Common::Input::PollingMode::Active); | ||
| 218 | |||
| 219 | if (device_state == DeviceState::Initialized) { | 242 | if (device_state == DeviceState::Initialized) { |
| 220 | return ResultSuccess; | 243 | return ResultSuccess; |
| 221 | } | 244 | } |
| @@ -225,6 +248,7 @@ Result NfcDevice::StopDetection() { | |||
| 225 | } | 248 | } |
| 226 | 249 | ||
| 227 | if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { | 250 | if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { |
| 251 | npad_device->StopNfcPolling(); | ||
| 228 | device_state = DeviceState::Initialized; | 252 | device_state = DeviceState::Initialized; |
| 229 | return ResultSuccess; | 253 | return ResultSuccess; |
| 230 | } | 254 | } |
| @@ -233,7 +257,7 @@ Result NfcDevice::StopDetection() { | |||
| 233 | return ResultWrongDeviceState; | 257 | return ResultWrongDeviceState; |
| 234 | } | 258 | } |
| 235 | 259 | ||
| 236 | Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const { | 260 | Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const { |
| 237 | if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) { | 261 | if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) { |
| 238 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | 262 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); |
| 239 | if (device_state == DeviceState::TagRemoved) { | 263 | if (device_state == DeviceState::TagRemoved) { |
| @@ -242,41 +266,15 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const { | |||
| 242 | return ResultWrongDeviceState; | 266 | return ResultWrongDeviceState; |
| 243 | } | 267 | } |
| 244 | 268 | ||
| 245 | UniqueSerialNumber uuid{}; | 269 | tag_info = real_tag_info; |
| 246 | u8 uuid_length{}; | ||
| 247 | NfcProtocol protocol{NfcProtocol::TypeA}; | ||
| 248 | TagType tag_type{TagType::Type2}; | ||
| 249 | |||
| 250 | if (is_mifare) { | ||
| 251 | tag_type = TagType::Mifare; | ||
| 252 | uuid_length = sizeof(NFP::NtagTagUuid); | ||
| 253 | memcpy(uuid.data(), mifare_data.data(), uuid_length); | ||
| 254 | } else { | ||
| 255 | tag_type = TagType::Type2; | ||
| 256 | uuid_length = sizeof(NFP::NtagTagUuid); | ||
| 257 | NFP::NtagTagUuid nUuid{ | ||
| 258 | .part1 = encrypted_tag_data.uuid.part1, | ||
| 259 | .part2 = encrypted_tag_data.uuid.part2, | ||
| 260 | .nintendo_id = encrypted_tag_data.uuid.nintendo_id, | ||
| 261 | }; | ||
| 262 | memcpy(uuid.data(), &nUuid, uuid_length); | ||
| 263 | 270 | ||
| 264 | // Generate random UUID to bypass amiibo load limits | 271 | // Generate random UUID to bypass amiibo load limits |
| 265 | if (Settings::values.random_amiibo_id) { | 272 | if (real_tag_info.tag_type == TagType::Type2 && Settings::values.random_amiibo_id) { |
| 266 | Common::TinyMT rng{}; | 273 | Common::TinyMT rng{}; |
| 267 | rng.Initialize(static_cast<u32>(GetCurrentPosixTime())); | 274 | rng.Initialize(static_cast<u32>(GetCurrentPosixTime())); |
| 268 | rng.GenerateRandomBytes(uuid.data(), uuid_length); | 275 | rng.GenerateRandomBytes(tag_info.uuid.data(), tag_info.uuid_length); |
| 269 | } | ||
| 270 | } | 276 | } |
| 271 | 277 | ||
| 272 | // Protocol and tag type may change here | ||
| 273 | tag_info = { | ||
| 274 | .uuid = uuid, | ||
| 275 | .uuid_length = uuid_length, | ||
| 276 | .protocol = protocol, | ||
| 277 | .tag_type = tag_type, | ||
| 278 | }; | ||
| 279 | |||
| 280 | return ResultSuccess; | 278 | return ResultSuccess; |
| 281 | } | 279 | } |
| 282 | 280 | ||
| @@ -293,7 +291,7 @@ Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameter | |||
| 293 | Result result = ResultSuccess; | 291 | Result result = ResultSuccess; |
| 294 | 292 | ||
| 295 | TagInfo tag_info{}; | 293 | TagInfo tag_info{}; |
| 296 | result = GetTagInfo(tag_info, true); | 294 | result = GetTagInfo(tag_info); |
| 297 | 295 | ||
| 298 | if (result.IsError()) { | 296 | if (result.IsError()) { |
| 299 | return result; | 297 | return result; |
| @@ -307,6 +305,8 @@ Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameter | |||
| 307 | return ResultInvalidArgument; | 305 | return ResultInvalidArgument; |
| 308 | } | 306 | } |
| 309 | 307 | ||
| 308 | Common::Input::MifareRequest request{}; | ||
| 309 | Common::Input::MifareRequest out_data{}; | ||
| 310 | const auto unknown = parameters[0].sector_key.unknown; | 310 | const auto unknown = parameters[0].sector_key.unknown; |
| 311 | for (std::size_t i = 0; i < parameters.size(); i++) { | 311 | for (std::size_t i = 0; i < parameters.size(); i++) { |
| 312 | if (unknown != parameters[i].sector_key.unknown) { | 312 | if (unknown != parameters[i].sector_key.unknown) { |
| @@ -315,25 +315,29 @@ Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameter | |||
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | for (std::size_t i = 0; i < parameters.size(); i++) { | 317 | for (std::size_t i = 0; i < parameters.size(); i++) { |
| 318 | result = ReadMifare(parameters[i], read_block_data[i]); | 318 | if (parameters[i].sector_key.command == MifareCmd::None) { |
| 319 | if (result.IsError()) { | 319 | continue; |
| 320 | break; | ||
| 321 | } | 320 | } |
| 321 | request.data[i].command = static_cast<u8>(parameters[i].sector_key.command); | ||
| 322 | request.data[i].sector = parameters[i].sector_number; | ||
| 323 | memcpy(request.data[i].key.data(), parameters[i].sector_key.sector_key.data(), | ||
| 324 | sizeof(KeyData)); | ||
| 322 | } | 325 | } |
| 323 | 326 | ||
| 324 | return result; | 327 | if (!npad_device->ReadMifareData(request, out_data)) { |
| 325 | } | ||
| 326 | |||
| 327 | Result NfcDevice::ReadMifare(const MifareReadBlockParameter& parameter, | ||
| 328 | MifareReadBlockData& read_block_data) const { | ||
| 329 | const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock); | ||
| 330 | read_block_data.sector_number = parameter.sector_number; | ||
| 331 | if (mifare_data.size() < sector_index + sizeof(DataBlock)) { | ||
| 332 | return ResultMifareError288; | 328 | return ResultMifareError288; |
| 333 | } | 329 | } |
| 334 | 330 | ||
| 335 | // TODO: Use parameter.sector_key to read encrypted data | 331 | for (std::size_t i = 0; i < read_block_data.size(); i++) { |
| 336 | memcpy(read_block_data.data.data(), mifare_data.data() + sector_index, sizeof(DataBlock)); | 332 | if (static_cast<MifareCmd>(out_data.data[i].command) == MifareCmd::None) { |
| 333 | continue; | ||
| 334 | } | ||
| 335 | |||
| 336 | read_block_data[i] = { | ||
| 337 | .data = out_data.data[i].data, | ||
| 338 | .sector_number = out_data.data[i].sector, | ||
| 339 | }; | ||
| 340 | } | ||
| 337 | 341 | ||
| 338 | return ResultSuccess; | 342 | return ResultSuccess; |
| 339 | } | 343 | } |
| @@ -342,7 +346,7 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet | |||
| 342 | Result result = ResultSuccess; | 346 | Result result = ResultSuccess; |
| 343 | 347 | ||
| 344 | TagInfo tag_info{}; | 348 | TagInfo tag_info{}; |
| 345 | result = GetTagInfo(tag_info, true); | 349 | result = GetTagInfo(tag_info); |
| 346 | 350 | ||
| 347 | if (result.IsError()) { | 351 | if (result.IsError()) { |
| 348 | return result; | 352 | return result; |
| @@ -363,42 +367,25 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet | |||
| 363 | } | 367 | } |
| 364 | } | 368 | } |
| 365 | 369 | ||
| 370 | Common::Input::MifareRequest request{}; | ||
| 366 | for (std::size_t i = 0; i < parameters.size(); i++) { | 371 | for (std::size_t i = 0; i < parameters.size(); i++) { |
| 367 | result = WriteMifare(parameters[i]); | 372 | if (parameters[i].sector_key.command == MifareCmd::None) { |
| 368 | if (result.IsError()) { | 373 | continue; |
| 369 | break; | ||
| 370 | } | 374 | } |
| 375 | request.data[i].command = static_cast<u8>(parameters[i].sector_key.command); | ||
| 376 | request.data[i].sector = parameters[i].sector_number; | ||
| 377 | memcpy(request.data[i].key.data(), parameters[i].sector_key.sector_key.data(), | ||
| 378 | sizeof(KeyData)); | ||
| 379 | memcpy(request.data[i].data.data(), parameters[i].data.data(), sizeof(KeyData)); | ||
| 371 | } | 380 | } |
| 372 | 381 | ||
| 373 | if (!npad_device->WriteNfc(mifare_data)) { | 382 | if (!npad_device->WriteMifareData(request)) { |
| 374 | LOG_ERROR(Service_NFP, "Error writing to file"); | ||
| 375 | return ResultMifareError288; | 383 | return ResultMifareError288; |
| 376 | } | 384 | } |
| 377 | 385 | ||
| 378 | return result; | 386 | return result; |
| 379 | } | 387 | } |
| 380 | 388 | ||
| 381 | Result NfcDevice::WriteMifare(const MifareWriteBlockParameter& parameter) { | ||
| 382 | const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock); | ||
| 383 | |||
| 384 | if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) { | ||
| 385 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||
| 386 | if (device_state == DeviceState::TagRemoved) { | ||
| 387 | return ResultTagRemoved; | ||
| 388 | } | ||
| 389 | return ResultWrongDeviceState; | ||
| 390 | } | ||
| 391 | |||
| 392 | if (mifare_data.size() < sector_index + sizeof(DataBlock)) { | ||
| 393 | return ResultMifareError288; | ||
| 394 | } | ||
| 395 | |||
| 396 | // TODO: Use parameter.sector_key to encrypt the data | ||
| 397 | memcpy(mifare_data.data() + sector_index, parameter.data.data(), sizeof(DataBlock)); | ||
| 398 | |||
| 399 | return ResultSuccess; | ||
| 400 | } | ||
| 401 | |||
| 402 | Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, | 389 | Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, |
| 403 | std::span<const u8> command_data, | 390 | std::span<const u8> command_data, |
| 404 | std::span<u8> out_data) { | 391 | std::span<u8> out_data) { |
| @@ -412,6 +399,11 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target | |||
| 412 | return ResultWrongDeviceState; | 399 | return ResultWrongDeviceState; |
| 413 | } | 400 | } |
| 414 | 401 | ||
| 402 | if (!LoadAmiiboData()) { | ||
| 403 | LOG_ERROR(Service_NFP, "Not an amiibo"); | ||
| 404 | return ResultInvalidTagType; | ||
| 405 | } | ||
| 406 | |||
| 415 | if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) { | 407 | if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) { |
| 416 | LOG_ERROR(Service_NFP, "Not an amiibo"); | 408 | LOG_ERROR(Service_NFP, "Not an amiibo"); |
| 417 | return ResultInvalidTagType; | 409 | return ResultInvalidTagType; |
| @@ -562,7 +554,7 @@ Result NfcDevice::Restore() { | |||
| 562 | 554 | ||
| 563 | NFC::TagInfo tag_info{}; | 555 | NFC::TagInfo tag_info{}; |
| 564 | std::array<u8, sizeof(NFP::EncryptedNTAG215File)> data{}; | 556 | std::array<u8, sizeof(NFP::EncryptedNTAG215File)> data{}; |
| 565 | Result result = GetTagInfo(tag_info, false); | 557 | Result result = GetTagInfo(tag_info); |
| 566 | 558 | ||
| 567 | if (result.IsError()) { | 559 | if (result.IsError()) { |
| 568 | return result; | 560 | return result; |
| @@ -635,7 +627,7 @@ Result NfcDevice::GetCommonInfo(NFP::CommonInfo& common_info) const { | |||
| 635 | // TODO: Validate this data | 627 | // TODO: Validate this data |
| 636 | common_info = { | 628 | common_info = { |
| 637 | .last_write_date = settings.write_date.GetWriteDate(), | 629 | .last_write_date = settings.write_date.GetWriteDate(), |
| 638 | .write_counter = tag_data.write_counter, | 630 | .write_counter = tag_data.application_write_counter, |
| 639 | .version = tag_data.amiibo_version, | 631 | .version = tag_data.amiibo_version, |
| 640 | .application_area_size = sizeof(NFP::ApplicationArea), | 632 | .application_area_size = sizeof(NFP::ApplicationArea), |
| 641 | }; | 633 | }; |
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h index 7560210d6..0ed1ff34c 100644 --- a/src/core/hle/service/nfc/common/device.h +++ b/src/core/hle/service/nfc/common/device.h | |||
| @@ -42,15 +42,12 @@ public: | |||
| 42 | Result StartDetection(NfcProtocol allowed_protocol); | 42 | Result StartDetection(NfcProtocol allowed_protocol); |
| 43 | Result StopDetection(); | 43 | Result StopDetection(); |
| 44 | 44 | ||
| 45 | Result GetTagInfo(TagInfo& tag_info, bool is_mifare) const; | 45 | Result GetTagInfo(TagInfo& tag_info) const; |
| 46 | 46 | ||
| 47 | Result ReadMifare(std::span<const MifareReadBlockParameter> parameters, | 47 | Result ReadMifare(std::span<const MifareReadBlockParameter> parameters, |
| 48 | std::span<MifareReadBlockData> read_block_data) const; | 48 | std::span<MifareReadBlockData> read_block_data) const; |
| 49 | Result ReadMifare(const MifareReadBlockParameter& parameter, | ||
| 50 | MifareReadBlockData& read_block_data) const; | ||
| 51 | 49 | ||
| 52 | Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters); | 50 | Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters); |
| 53 | Result WriteMifare(const MifareWriteBlockParameter& parameter); | ||
| 54 | 51 | ||
| 55 | Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, | 52 | Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, |
| 56 | std::span<const u8> command_data, std::span<u8> out_data); | 53 | std::span<const u8> command_data, std::span<u8> out_data); |
| @@ -105,7 +102,8 @@ public: | |||
| 105 | 102 | ||
| 106 | private: | 103 | private: |
| 107 | void NpadUpdate(Core::HID::ControllerTriggerType type); | 104 | void NpadUpdate(Core::HID::ControllerTriggerType type); |
| 108 | bool LoadNfcTag(std::span<const u8> data); | 105 | bool LoadNfcTag(u8 protocol, u8 tag_type, u8 uuid_length, UniqueSerialNumber uuid); |
| 106 | bool LoadAmiiboData(); | ||
| 109 | void CloseNfcTag(); | 107 | void CloseNfcTag(); |
| 110 | 108 | ||
| 111 | NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const; | 109 | NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const; |
| @@ -140,8 +138,8 @@ private: | |||
| 140 | bool is_write_protected{}; | 138 | bool is_write_protected{}; |
| 141 | NFP::MountTarget mount_target{NFP::MountTarget::None}; | 139 | NFP::MountTarget mount_target{NFP::MountTarget::None}; |
| 142 | 140 | ||
| 141 | TagInfo real_tag_info{}; | ||
| 143 | NFP::NTAG215File tag_data{}; | 142 | NFP::NTAG215File tag_data{}; |
| 144 | std::vector<u8> mifare_data{}; | ||
| 145 | NFP::EncryptedNTAG215File encrypted_tag_data{}; | 143 | NFP::EncryptedNTAG215File encrypted_tag_data{}; |
| 146 | }; | 144 | }; |
| 147 | 145 | ||
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp index b0456508e..562f3a28e 100644 --- a/src/core/hle/service/nfc/common/device_manager.cpp +++ b/src/core/hle/service/nfc/common/device_manager.cpp | |||
| @@ -29,6 +29,9 @@ DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContex | |||
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | DeviceManager ::~DeviceManager() { | 31 | DeviceManager ::~DeviceManager() { |
| 32 | if (is_initialized) { | ||
| 33 | Finalize(); | ||
| 34 | } | ||
| 32 | service_context.CloseEvent(availability_change_event); | 35 | service_context.CloseEvent(availability_change_event); |
| 33 | } | 36 | } |
| 34 | 37 | ||
| @@ -125,14 +128,14 @@ Result DeviceManager::StopDetection(u64 device_handle) { | |||
| 125 | return result; | 128 | return result; |
| 126 | } | 129 | } |
| 127 | 130 | ||
| 128 | Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info, bool is_mifare) const { | 131 | Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info) const { |
| 129 | std::scoped_lock lock{mutex}; | 132 | std::scoped_lock lock{mutex}; |
| 130 | 133 | ||
| 131 | std::shared_ptr<NfcDevice> device = nullptr; | 134 | std::shared_ptr<NfcDevice> device = nullptr; |
| 132 | auto result = GetDeviceHandle(device_handle, device); | 135 | auto result = GetDeviceHandle(device_handle, device); |
| 133 | 136 | ||
| 134 | if (result.IsSuccess()) { | 137 | if (result.IsSuccess()) { |
| 135 | result = device->GetTagInfo(tag_info, is_mifare); | 138 | result = device->GetTagInfo(tag_info); |
| 136 | result = VerifyDeviceResult(device, result); | 139 | result = VerifyDeviceResult(device, result); |
| 137 | } | 140 | } |
| 138 | 141 | ||
| @@ -546,7 +549,7 @@ Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) cons | |||
| 546 | NFC::TagInfo tag_info{}; | 549 | NFC::TagInfo tag_info{}; |
| 547 | 550 | ||
| 548 | if (result.IsSuccess()) { | 551 | if (result.IsSuccess()) { |
| 549 | result = device->GetTagInfo(tag_info, false); | 552 | result = device->GetTagInfo(tag_info); |
| 550 | } | 553 | } |
| 551 | 554 | ||
| 552 | if (result.IsSuccess()) { | 555 | if (result.IsSuccess()) { |
| @@ -565,7 +568,7 @@ Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> dat | |||
| 565 | NFC::TagInfo tag_info{}; | 568 | NFC::TagInfo tag_info{}; |
| 566 | 569 | ||
| 567 | if (result.IsSuccess()) { | 570 | if (result.IsSuccess()) { |
| 568 | result = device->GetTagInfo(tag_info, false); | 571 | result = device->GetTagInfo(tag_info); |
| 569 | } | 572 | } |
| 570 | 573 | ||
| 571 | if (result.IsSuccess()) { | 574 | if (result.IsSuccess()) { |
diff --git a/src/core/hle/service/nfc/common/device_manager.h b/src/core/hle/service/nfc/common/device_manager.h index 2971e280f..c61ba0cf3 100644 --- a/src/core/hle/service/nfc/common/device_manager.h +++ b/src/core/hle/service/nfc/common/device_manager.h | |||
| @@ -33,7 +33,7 @@ public: | |||
| 33 | Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const; | 33 | Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const; |
| 34 | Result StartDetection(u64 device_handle, NfcProtocol tag_protocol); | 34 | Result StartDetection(u64 device_handle, NfcProtocol tag_protocol); |
| 35 | Result StopDetection(u64 device_handle); | 35 | Result StopDetection(u64 device_handle); |
| 36 | Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info, bool is_mifare) const; | 36 | Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info) const; |
| 37 | Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const; | 37 | Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const; |
| 38 | Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const; | 38 | Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const; |
| 39 | Result ReadMifare(u64 device_handle, | 39 | Result ReadMifare(u64 device_handle, |
diff --git a/src/core/hle/service/nfc/mifare_types.h b/src/core/hle/service/nfc/mifare_types.h index 75b59f021..467937399 100644 --- a/src/core/hle/service/nfc/mifare_types.h +++ b/src/core/hle/service/nfc/mifare_types.h | |||
| @@ -11,9 +11,10 @@ | |||
| 11 | namespace Service::NFC { | 11 | namespace Service::NFC { |
| 12 | 12 | ||
| 13 | enum class MifareCmd : u8 { | 13 | enum class MifareCmd : u8 { |
| 14 | None = 0x00, | ||
| 15 | Read = 0x30, | ||
| 14 | AuthA = 0x60, | 16 | AuthA = 0x60, |
| 15 | AuthB = 0x61, | 17 | AuthB = 0x61, |
| 16 | Read = 0x30, | ||
| 17 | Write = 0xA0, | 18 | Write = 0xA0, |
| 18 | Transfer = 0xB0, | 19 | Transfer = 0xB0, |
| 19 | Decrement = 0xC0, | 20 | Decrement = 0xC0, |
| @@ -35,17 +36,17 @@ static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size"); | |||
| 35 | 36 | ||
| 36 | // This is nn::nfc::MifareReadBlockParameter | 37 | // This is nn::nfc::MifareReadBlockParameter |
| 37 | struct MifareReadBlockParameter { | 38 | struct MifareReadBlockParameter { |
| 38 | u8 sector_number; | 39 | u8 sector_number{}; |
| 39 | INSERT_PADDING_BYTES(0x7); | 40 | INSERT_PADDING_BYTES(0x7); |
| 40 | SectorKey sector_key; | 41 | SectorKey sector_key{}; |
| 41 | }; | 42 | }; |
| 42 | static_assert(sizeof(MifareReadBlockParameter) == 0x18, | 43 | static_assert(sizeof(MifareReadBlockParameter) == 0x18, |
| 43 | "MifareReadBlockParameter is an invalid size"); | 44 | "MifareReadBlockParameter is an invalid size"); |
| 44 | 45 | ||
| 45 | // This is nn::nfc::MifareReadBlockData | 46 | // This is nn::nfc::MifareReadBlockData |
| 46 | struct MifareReadBlockData { | 47 | struct MifareReadBlockData { |
| 47 | DataBlock data; | 48 | DataBlock data{}; |
| 48 | u8 sector_number; | 49 | u8 sector_number{}; |
| 49 | INSERT_PADDING_BYTES(0x7); | 50 | INSERT_PADDING_BYTES(0x7); |
| 50 | }; | 51 | }; |
| 51 | static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size"); | 52 | static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size"); |
diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp index 130fb7f78..e7ca7582e 100644 --- a/src/core/hle/service/nfc/nfc_interface.cpp +++ b/src/core/hle/service/nfc/nfc_interface.cpp | |||
| @@ -174,8 +174,7 @@ void NfcInterface::GetTagInfo(HLERequestContext& ctx) { | |||
| 174 | LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); | 174 | LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); |
| 175 | 175 | ||
| 176 | TagInfo tag_info{}; | 176 | TagInfo tag_info{}; |
| 177 | auto result = | 177 | auto result = GetManager()->GetTagInfo(device_handle, tag_info); |
| 178 | GetManager()->GetTagInfo(device_handle, tag_info, backend_type == BackendType::Mifare); | ||
| 179 | result = TranslateResultToServiceError(result); | 178 | result = TranslateResultToServiceError(result); |
| 180 | 179 | ||
| 181 | if (result.IsSuccess()) { | 180 | if (result.IsSuccess()) { |
| @@ -216,8 +215,8 @@ void NfcInterface::ReadMifare(HLERequestContext& ctx) { | |||
| 216 | memcpy(read_commands.data(), buffer.data(), | 215 | memcpy(read_commands.data(), buffer.data(), |
| 217 | number_of_commands * sizeof(MifareReadBlockParameter)); | 216 | number_of_commands * sizeof(MifareReadBlockParameter)); |
| 218 | 217 | ||
| 219 | LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}", | 218 | LOG_INFO(Service_NFC, "called, device_handle={}, read_commands_size={}", device_handle, |
| 220 | device_handle, number_of_commands); | 219 | number_of_commands); |
| 221 | 220 | ||
| 222 | std::vector<MifareReadBlockData> out_data(number_of_commands); | 221 | std::vector<MifareReadBlockData> out_data(number_of_commands); |
| 223 | auto result = GetManager()->ReadMifare(device_handle, read_commands, out_data); | 222 | auto result = GetManager()->ReadMifare(device_handle, read_commands, out_data); |
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index ab1f30f9e..a04538d5d 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h | |||
| @@ -34,7 +34,7 @@ public: | |||
| 34 | * @returns The result code of the ioctl. | 34 | * @returns The result code of the ioctl. |
| 35 | */ | 35 | */ |
| 36 | virtual NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 36 | virtual NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 37 | std::vector<u8>& output) = 0; | 37 | std::span<u8> output) = 0; |
| 38 | 38 | ||
| 39 | /** | 39 | /** |
| 40 | * Handles an ioctl2 request. | 40 | * Handles an ioctl2 request. |
| @@ -45,7 +45,7 @@ public: | |||
| 45 | * @returns The result code of the ioctl. | 45 | * @returns The result code of the ioctl. |
| 46 | */ | 46 | */ |
| 47 | virtual NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 47 | virtual NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 48 | std::span<const u8> inline_input, std::vector<u8>& output) = 0; | 48 | std::span<const u8> inline_input, std::span<u8> output) = 0; |
| 49 | 49 | ||
| 50 | /** | 50 | /** |
| 51 | * Handles an ioctl3 request. | 51 | * Handles an ioctl3 request. |
| @@ -56,7 +56,7 @@ public: | |||
| 56 | * @returns The result code of the ioctl. | 56 | * @returns The result code of the ioctl. |
| 57 | */ | 57 | */ |
| 58 | virtual NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, | 58 | virtual NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 59 | std::vector<u8>& output, std::vector<u8>& inline_output) = 0; | 59 | std::span<u8> output, std::span<u8> inline_output) = 0; |
| 60 | 60 | ||
| 61 | /** | 61 | /** |
| 62 | * Called once a device is opened | 62 | * Called once a device is opened |
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 5a5b2e305..05a43d8dc 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | |||
| @@ -18,19 +18,19 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system_, NvCore::Container& core) | |||
| 18 | nvdisp_disp0::~nvdisp_disp0() = default; | 18 | nvdisp_disp0::~nvdisp_disp0() = default; |
| 19 | 19 | ||
| 20 | NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 20 | NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 21 | std::vector<u8>& output) { | 21 | std::span<u8> output) { |
| 22 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | 22 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 23 | return NvResult::NotImplemented; | 23 | return NvResult::NotImplemented; |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | NvResult nvdisp_disp0::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 26 | NvResult nvdisp_disp0::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 27 | std::span<const u8> inline_input, std::vector<u8>& output) { | 27 | std::span<const u8> inline_input, std::span<u8> output) { |
| 28 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | 28 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 29 | return NvResult::NotImplemented; | 29 | return NvResult::NotImplemented; |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, | 32 | NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 33 | std::vector<u8>& output, std::vector<u8>& inline_output) { | 33 | std::span<u8> output, std::span<u8> inline_output) { |
| 34 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | 34 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 35 | return NvResult::NotImplemented; | 35 | return NvResult::NotImplemented; |
| 36 | } | 36 | } |
| @@ -51,8 +51,8 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat form | |||
| 51 | stride, format, transform, crop_rect}; | 51 | stride, format, transform, crop_rect}; |
| 52 | 52 | ||
| 53 | system.GPU().RequestSwapBuffers(&framebuffer, fences, num_fences); | 53 | system.GPU().RequestSwapBuffers(&framebuffer, fences, num_fences); |
| 54 | system.GetPerfStats().EndSystemFrame(); | ||
| 55 | system.SpeedLimiter().DoSpeedLimiting(system.CoreTiming().GetGlobalTimeUs()); | 54 | system.SpeedLimiter().DoSpeedLimiting(system.CoreTiming().GetGlobalTimeUs()); |
| 55 | system.GetPerfStats().EndSystemFrame(); | ||
| 56 | system.GetPerfStats().BeginSystemFrame(); | 56 | system.GetPerfStats().BeginSystemFrame(); |
| 57 | } | 57 | } |
| 58 | 58 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index bcd0e3ed5..daee05fe8 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h | |||
| @@ -26,11 +26,11 @@ public: | |||
| 26 | ~nvdisp_disp0() override; | 26 | ~nvdisp_disp0() override; |
| 27 | 27 | ||
| 28 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 28 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 29 | std::vector<u8>& output) override; | 29 | std::span<u8> output) override; |
| 30 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 30 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 31 | std::span<const u8> inline_input, std::vector<u8>& output) override; | 31 | std::span<const u8> inline_input, std::span<u8> output) override; |
| 32 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, | 32 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, |
| 33 | std::vector<u8>& inline_output) override; | 33 | std::span<u8> inline_output) override; |
| 34 | 34 | ||
| 35 | void OnOpen(DeviceFD fd) override; | 35 | void OnOpen(DeviceFD fd) override; |
| 36 | void OnClose(DeviceFD fd) override; | 36 | void OnClose(DeviceFD fd) override; |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 681bd0867..07e570a9f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | |||
| @@ -28,7 +28,7 @@ nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, Module& module_, NvCore::Con | |||
| 28 | nvhost_as_gpu::~nvhost_as_gpu() = default; | 28 | nvhost_as_gpu::~nvhost_as_gpu() = default; |
| 29 | 29 | ||
| 30 | NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 30 | NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 31 | std::vector<u8>& output) { | 31 | std::span<u8> output) { |
| 32 | switch (command.group) { | 32 | switch (command.group) { |
| 33 | case 'A': | 33 | case 'A': |
| 34 | switch (command.cmd) { | 34 | switch (command.cmd) { |
| @@ -61,13 +61,13 @@ NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> i | |||
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | NvResult nvhost_as_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 63 | NvResult nvhost_as_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 64 | std::span<const u8> inline_input, std::vector<u8>& output) { | 64 | std::span<const u8> inline_input, std::span<u8> output) { |
| 65 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | 65 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 66 | return NvResult::NotImplemented; | 66 | return NvResult::NotImplemented; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, | 69 | NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 70 | std::vector<u8>& output, std::vector<u8>& inline_output) { | 70 | std::span<u8> output, std::span<u8> inline_output) { |
| 71 | switch (command.group) { | 71 | switch (command.group) { |
| 72 | case 'A': | 72 | case 'A': |
| 73 | switch (command.cmd) { | 73 | switch (command.cmd) { |
| @@ -87,7 +87,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i | |||
| 87 | void nvhost_as_gpu::OnOpen(DeviceFD fd) {} | 87 | void nvhost_as_gpu::OnOpen(DeviceFD fd) {} |
| 88 | void nvhost_as_gpu::OnClose(DeviceFD fd) {} | 88 | void nvhost_as_gpu::OnClose(DeviceFD fd) {} |
| 89 | 89 | ||
| 90 | NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::vector<u8>& output) { | 90 | NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::span<u8> output) { |
| 91 | IoctlAllocAsEx params{}; | 91 | IoctlAllocAsEx params{}; |
| 92 | std::memcpy(¶ms, input.data(), input.size()); | 92 | std::memcpy(¶ms, input.data(), input.size()); |
| 93 | 93 | ||
| @@ -141,7 +141,7 @@ NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::vector<u8>& ou | |||
| 141 | return NvResult::Success; | 141 | return NvResult::Success; |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | NvResult nvhost_as_gpu::AllocateSpace(std::span<const u8> input, std::vector<u8>& output) { | 144 | NvResult nvhost_as_gpu::AllocateSpace(std::span<const u8> input, std::span<u8> output) { |
| 145 | IoctlAllocSpace params{}; | 145 | IoctlAllocSpace params{}; |
| 146 | std::memcpy(¶ms, input.data(), input.size()); | 146 | std::memcpy(¶ms, input.data(), input.size()); |
| 147 | 147 | ||
| @@ -220,7 +220,7 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) { | |||
| 220 | mapping_map.erase(offset); | 220 | mapping_map.erase(offset); |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::vector<u8>& output) { | 223 | NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::span<u8> output) { |
| 224 | IoctlFreeSpace params{}; | 224 | IoctlFreeSpace params{}; |
| 225 | std::memcpy(¶ms, input.data(), input.size()); | 225 | std::memcpy(¶ms, input.data(), input.size()); |
| 226 | 226 | ||
| @@ -266,15 +266,14 @@ NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::vector<u8>& ou | |||
| 266 | return NvResult::Success; | 266 | return NvResult::Success; |
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::vector<u8>& output) { | 269 | NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::span<u8> output) { |
| 270 | const auto num_entries = input.size() / sizeof(IoctlRemapEntry); | 270 | const auto num_entries = input.size() / sizeof(IoctlRemapEntry); |
| 271 | 271 | ||
| 272 | LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries); | 272 | LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries); |
| 273 | 273 | ||
| 274 | std::vector<IoctlRemapEntry> entries(num_entries); | ||
| 275 | std::memcpy(entries.data(), input.data(), input.size()); | ||
| 276 | |||
| 277 | std::scoped_lock lock(mutex); | 274 | std::scoped_lock lock(mutex); |
| 275 | entries.resize_destructive(num_entries); | ||
| 276 | std::memcpy(entries.data(), input.data(), input.size()); | ||
| 278 | 277 | ||
| 279 | if (!vm.initialised) { | 278 | if (!vm.initialised) { |
| 280 | return NvResult::BadValue; | 279 | return NvResult::BadValue; |
| @@ -320,7 +319,7 @@ NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::vector<u8>& output | |||
| 320 | return NvResult::Success; | 319 | return NvResult::Success; |
| 321 | } | 320 | } |
| 322 | 321 | ||
| 323 | NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::vector<u8>& output) { | 322 | NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::span<u8> output) { |
| 324 | IoctlMapBufferEx params{}; | 323 | IoctlMapBufferEx params{}; |
| 325 | std::memcpy(¶ms, input.data(), input.size()); | 324 | std::memcpy(¶ms, input.data(), input.size()); |
| 326 | 325 | ||
| @@ -424,7 +423,7 @@ NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::vector<u8>& | |||
| 424 | return NvResult::Success; | 423 | return NvResult::Success; |
| 425 | } | 424 | } |
| 426 | 425 | ||
| 427 | NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::vector<u8>& output) { | 426 | NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::span<u8> output) { |
| 428 | IoctlUnmapBuffer params{}; | 427 | IoctlUnmapBuffer params{}; |
| 429 | std::memcpy(¶ms, input.data(), input.size()); | 428 | std::memcpy(¶ms, input.data(), input.size()); |
| 430 | 429 | ||
| @@ -463,7 +462,7 @@ NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::vector<u8>& | |||
| 463 | return NvResult::Success; | 462 | return NvResult::Success; |
| 464 | } | 463 | } |
| 465 | 464 | ||
| 466 | NvResult nvhost_as_gpu::BindChannel(std::span<const u8> input, std::vector<u8>& output) { | 465 | NvResult nvhost_as_gpu::BindChannel(std::span<const u8> input, std::span<u8> output) { |
| 467 | IoctlBindChannel params{}; | 466 | IoctlBindChannel params{}; |
| 468 | std::memcpy(¶ms, input.data(), input.size()); | 467 | std::memcpy(¶ms, input.data(), input.size()); |
| 469 | LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); | 468 | LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); |
| @@ -492,7 +491,7 @@ void nvhost_as_gpu::GetVARegionsImpl(IoctlGetVaRegions& params) { | |||
| 492 | }; | 491 | }; |
| 493 | } | 492 | } |
| 494 | 493 | ||
| 495 | NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::vector<u8>& output) { | 494 | NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> output) { |
| 496 | IoctlGetVaRegions params{}; | 495 | IoctlGetVaRegions params{}; |
| 497 | std::memcpy(¶ms, input.data(), input.size()); | 496 | std::memcpy(¶ms, input.data(), input.size()); |
| 498 | 497 | ||
| @@ -511,8 +510,8 @@ NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::vector<u8>& | |||
| 511 | return NvResult::Success; | 510 | return NvResult::Success; |
| 512 | } | 511 | } |
| 513 | 512 | ||
| 514 | NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::vector<u8>& output, | 513 | NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> output, |
| 515 | std::vector<u8>& inline_output) { | 514 | std::span<u8> inline_output) { |
| 516 | IoctlGetVaRegions params{}; | 515 | IoctlGetVaRegions params{}; |
| 517 | std::memcpy(¶ms, input.data(), input.size()); | 516 | std::memcpy(¶ms, input.data(), input.size()); |
| 518 | 517 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 1aba8d579..2af3e1260 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include "common/address_space.h" | 15 | #include "common/address_space.h" |
| 16 | #include "common/common_funcs.h" | 16 | #include "common/common_funcs.h" |
| 17 | #include "common/common_types.h" | 17 | #include "common/common_types.h" |
| 18 | #include "common/scratch_buffer.h" | ||
| 18 | #include "common/swap.h" | 19 | #include "common/swap.h" |
| 19 | #include "core/hle/service/nvdrv/core/nvmap.h" | 20 | #include "core/hle/service/nvdrv/core/nvmap.h" |
| 20 | #include "core/hle/service/nvdrv/devices/nvdevice.h" | 21 | #include "core/hle/service/nvdrv/devices/nvdevice.h" |
| @@ -48,11 +49,11 @@ public: | |||
| 48 | ~nvhost_as_gpu() override; | 49 | ~nvhost_as_gpu() override; |
| 49 | 50 | ||
| 50 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 51 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 51 | std::vector<u8>& output) override; | 52 | std::span<u8> output) override; |
| 52 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 53 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 53 | std::span<const u8> inline_input, std::vector<u8>& output) override; | 54 | std::span<const u8> inline_input, std::span<u8> output) override; |
| 54 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, | 55 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, |
| 55 | std::vector<u8>& inline_output) override; | 56 | std::span<u8> inline_output) override; |
| 56 | 57 | ||
| 57 | void OnOpen(DeviceFD fd) override; | 58 | void OnOpen(DeviceFD fd) override; |
| 58 | void OnClose(DeviceFD fd) override; | 59 | void OnClose(DeviceFD fd) override; |
| @@ -138,18 +139,18 @@ private: | |||
| 138 | static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(VaRegion) * 2, | 139 | static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(VaRegion) * 2, |
| 139 | "IoctlGetVaRegions is incorrect size"); | 140 | "IoctlGetVaRegions is incorrect size"); |
| 140 | 141 | ||
| 141 | NvResult AllocAsEx(std::span<const u8> input, std::vector<u8>& output); | 142 | NvResult AllocAsEx(std::span<const u8> input, std::span<u8> output); |
| 142 | NvResult AllocateSpace(std::span<const u8> input, std::vector<u8>& output); | 143 | NvResult AllocateSpace(std::span<const u8> input, std::span<u8> output); |
| 143 | NvResult Remap(std::span<const u8> input, std::vector<u8>& output); | 144 | NvResult Remap(std::span<const u8> input, std::span<u8> output); |
| 144 | NvResult MapBufferEx(std::span<const u8> input, std::vector<u8>& output); | 145 | NvResult MapBufferEx(std::span<const u8> input, std::span<u8> output); |
| 145 | NvResult UnmapBuffer(std::span<const u8> input, std::vector<u8>& output); | 146 | NvResult UnmapBuffer(std::span<const u8> input, std::span<u8> output); |
| 146 | NvResult FreeSpace(std::span<const u8> input, std::vector<u8>& output); | 147 | NvResult FreeSpace(std::span<const u8> input, std::span<u8> output); |
| 147 | NvResult BindChannel(std::span<const u8> input, std::vector<u8>& output); | 148 | NvResult BindChannel(std::span<const u8> input, std::span<u8> output); |
| 148 | 149 | ||
| 149 | void GetVARegionsImpl(IoctlGetVaRegions& params); | 150 | void GetVARegionsImpl(IoctlGetVaRegions& params); |
| 150 | NvResult GetVARegions(std::span<const u8> input, std::vector<u8>& output); | 151 | NvResult GetVARegions(std::span<const u8> input, std::span<u8> output); |
| 151 | NvResult GetVARegions(std::span<const u8> input, std::vector<u8>& output, | 152 | NvResult GetVARegions(std::span<const u8> input, std::span<u8> output, |
| 152 | std::vector<u8>& inline_output); | 153 | std::span<u8> inline_output); |
| 153 | 154 | ||
| 154 | void FreeMappingLocked(u64 offset); | 155 | void FreeMappingLocked(u64 offset); |
| 155 | 156 | ||
| @@ -212,6 +213,7 @@ private: | |||
| 212 | bool initialised{}; | 213 | bool initialised{}; |
| 213 | } vm; | 214 | } vm; |
| 214 | std::shared_ptr<Tegra::MemoryManager> gmmu; | 215 | std::shared_ptr<Tegra::MemoryManager> gmmu; |
| 216 | Common::ScratchBuffer<IoctlRemapEntry> entries; | ||
| 215 | 217 | ||
| 216 | // s32 channel{}; | 218 | // s32 channel{}; |
| 217 | // u32 big_page_size{VM::DEFAULT_BIG_PAGE_SIZE}; | 219 | // u32 big_page_size{VM::DEFAULT_BIG_PAGE_SIZE}; |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index e12025560..4d55554b4 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | |||
| @@ -35,7 +35,7 @@ nvhost_ctrl::~nvhost_ctrl() { | |||
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 37 | NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 38 | std::vector<u8>& output) { | 38 | std::span<u8> output) { |
| 39 | switch (command.group) { | 39 | switch (command.group) { |
| 40 | case 0x0: | 40 | case 0x0: |
| 41 | switch (command.cmd) { | 41 | switch (command.cmd) { |
| @@ -64,13 +64,13 @@ NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inp | |||
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | NvResult nvhost_ctrl::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 66 | NvResult nvhost_ctrl::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 67 | std::span<const u8> inline_input, std::vector<u8>& output) { | 67 | std::span<const u8> inline_input, std::span<u8> output) { |
| 68 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | 68 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 69 | return NvResult::NotImplemented; | 69 | return NvResult::NotImplemented; |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, | 72 | NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 73 | std::vector<u8>& output, std::vector<u8>& inline_outpu) { | 73 | std::span<u8> output, std::span<u8> inline_outpu) { |
| 74 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | 74 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 75 | return NvResult::NotImplemented; | 75 | return NvResult::NotImplemented; |
| 76 | } | 76 | } |
| @@ -79,7 +79,7 @@ void nvhost_ctrl::OnOpen(DeviceFD fd) {} | |||
| 79 | 79 | ||
| 80 | void nvhost_ctrl::OnClose(DeviceFD fd) {} | 80 | void nvhost_ctrl::OnClose(DeviceFD fd) {} |
| 81 | 81 | ||
| 82 | NvResult nvhost_ctrl::NvOsGetConfigU32(std::span<const u8> input, std::vector<u8>& output) { | 82 | NvResult nvhost_ctrl::NvOsGetConfigU32(std::span<const u8> input, std::span<u8> output) { |
| 83 | IocGetConfigParams params{}; | 83 | IocGetConfigParams params{}; |
| 84 | std::memcpy(¶ms, input.data(), sizeof(params)); | 84 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 85 | LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), | 85 | LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), |
| @@ -87,7 +87,7 @@ NvResult nvhost_ctrl::NvOsGetConfigU32(std::span<const u8> input, std::vector<u8 | |||
| 87 | return NvResult::ConfigVarNotFound; // Returns error on production mode | 87 | return NvResult::ConfigVarNotFound; // Returns error on production mode |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | NvResult nvhost_ctrl::IocCtrlEventWait(std::span<const u8> input, std::vector<u8>& output, | 90 | NvResult nvhost_ctrl::IocCtrlEventWait(std::span<const u8> input, std::span<u8> output, |
| 91 | bool is_allocation) { | 91 | bool is_allocation) { |
| 92 | IocCtrlEventWaitParams params{}; | 92 | IocCtrlEventWaitParams params{}; |
| 93 | std::memcpy(¶ms, input.data(), sizeof(params)); | 93 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| @@ -231,7 +231,7 @@ NvResult nvhost_ctrl::FreeEvent(u32 slot) { | |||
| 231 | return NvResult::Success; | 231 | return NvResult::Success; |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | NvResult nvhost_ctrl::IocCtrlEventRegister(std::span<const u8> input, std::vector<u8>& output) { | 234 | NvResult nvhost_ctrl::IocCtrlEventRegister(std::span<const u8> input, std::span<u8> output) { |
| 235 | IocCtrlEventRegisterParams params{}; | 235 | IocCtrlEventRegisterParams params{}; |
| 236 | std::memcpy(¶ms, input.data(), sizeof(params)); | 236 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 237 | const u32 event_id = params.user_event_id; | 237 | const u32 event_id = params.user_event_id; |
| @@ -252,7 +252,7 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(std::span<const u8> input, std::vecto | |||
| 252 | return NvResult::Success; | 252 | return NvResult::Success; |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span<const u8> input, std::vector<u8>& output) { | 255 | NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span<const u8> input, std::span<u8> output) { |
| 256 | IocCtrlEventUnregisterParams params{}; | 256 | IocCtrlEventUnregisterParams params{}; |
| 257 | std::memcpy(¶ms, input.data(), sizeof(params)); | 257 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 258 | const u32 event_id = params.user_event_id & 0x00FF; | 258 | const u32 event_id = params.user_event_id & 0x00FF; |
| @@ -262,8 +262,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span<const u8> input, std::vec | |||
| 262 | return FreeEvent(event_id); | 262 | return FreeEvent(event_id); |
| 263 | } | 263 | } |
| 264 | 264 | ||
| 265 | NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span<const u8> input, | 265 | NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span<const u8> input, std::span<u8> output) { |
| 266 | std::vector<u8>& output) { | ||
| 267 | IocCtrlEventUnregisterBatchParams params{}; | 266 | IocCtrlEventUnregisterBatchParams params{}; |
| 268 | std::memcpy(¶ms, input.data(), sizeof(params)); | 267 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 269 | u64 event_mask = params.user_events; | 268 | u64 event_mask = params.user_events; |
| @@ -281,7 +280,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span<const u8> input, | |||
| 281 | return NvResult::Success; | 280 | return NvResult::Success; |
| 282 | } | 281 | } |
| 283 | 282 | ||
| 284 | NvResult nvhost_ctrl::IocCtrlClearEventWait(std::span<const u8> input, std::vector<u8>& output) { | 283 | NvResult nvhost_ctrl::IocCtrlClearEventWait(std::span<const u8> input, std::span<u8> output) { |
| 285 | IocCtrlEventClearParams params{}; | 284 | IocCtrlEventClearParams params{}; |
| 286 | std::memcpy(¶ms, input.data(), sizeof(params)); | 285 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 287 | 286 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index dd2e7888a..2efed4862 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | |||
| @@ -26,11 +26,11 @@ public: | |||
| 26 | ~nvhost_ctrl() override; | 26 | ~nvhost_ctrl() override; |
| 27 | 27 | ||
| 28 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 28 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 29 | std::vector<u8>& output) override; | 29 | std::span<u8> output) override; |
| 30 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 30 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 31 | std::span<const u8> inline_input, std::vector<u8>& output) override; | 31 | std::span<const u8> inline_input, std::span<u8> output) override; |
| 32 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, | 32 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, |
| 33 | std::vector<u8>& inline_output) override; | 33 | std::span<u8> inline_output) override; |
| 34 | 34 | ||
| 35 | void OnOpen(DeviceFD fd) override; | 35 | void OnOpen(DeviceFD fd) override; |
| 36 | void OnClose(DeviceFD fd) override; | 36 | void OnClose(DeviceFD fd) override; |
| @@ -186,13 +186,12 @@ private: | |||
| 186 | static_assert(sizeof(IocCtrlEventUnregisterBatchParams) == 8, | 186 | static_assert(sizeof(IocCtrlEventUnregisterBatchParams) == 8, |
| 187 | "IocCtrlEventKill is incorrect size"); | 187 | "IocCtrlEventKill is incorrect size"); |
| 188 | 188 | ||
| 189 | NvResult NvOsGetConfigU32(std::span<const u8> input, std::vector<u8>& output); | 189 | NvResult NvOsGetConfigU32(std::span<const u8> input, std::span<u8> output); |
| 190 | NvResult IocCtrlEventWait(std::span<const u8> input, std::vector<u8>& output, | 190 | NvResult IocCtrlEventWait(std::span<const u8> input, std::span<u8> output, bool is_allocation); |
| 191 | bool is_allocation); | 191 | NvResult IocCtrlEventRegister(std::span<const u8> input, std::span<u8> output); |
| 192 | NvResult IocCtrlEventRegister(std::span<const u8> input, std::vector<u8>& output); | 192 | NvResult IocCtrlEventUnregister(std::span<const u8> input, std::span<u8> output); |
| 193 | NvResult IocCtrlEventUnregister(std::span<const u8> input, std::vector<u8>& output); | 193 | NvResult IocCtrlEventUnregisterBatch(std::span<const u8> input, std::span<u8> output); |
| 194 | NvResult IocCtrlEventUnregisterBatch(std::span<const u8> input, std::vector<u8>& output); | 194 | NvResult IocCtrlClearEventWait(std::span<const u8> input, std::span<u8> output); |
| 195 | NvResult IocCtrlClearEventWait(std::span<const u8> input, std::vector<u8>& output); | ||
| 196 | 195 | ||
| 197 | NvResult FreeEvent(u32 slot); | 196 | NvResult FreeEvent(u32 slot); |
| 198 | 197 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index be3c083db..6081d92e9 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | |||
| @@ -22,7 +22,7 @@ nvhost_ctrl_gpu::~nvhost_ctrl_gpu() { | |||
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 24 | NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 25 | std::vector<u8>& output) { | 25 | std::span<u8> output) { |
| 26 | switch (command.group) { | 26 | switch (command.group) { |
| 27 | case 'G': | 27 | case 'G': |
| 28 | switch (command.cmd) { | 28 | switch (command.cmd) { |
| @@ -54,13 +54,13 @@ NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> | |||
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | NvResult nvhost_ctrl_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 56 | NvResult nvhost_ctrl_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 57 | std::span<const u8> inline_input, std::vector<u8>& output) { | 57 | std::span<const u8> inline_input, std::span<u8> output) { |
| 58 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | 58 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 59 | return NvResult::NotImplemented; | 59 | return NvResult::NotImplemented; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, | 62 | NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 63 | std::vector<u8>& output, std::vector<u8>& inline_output) { | 63 | std::span<u8> output, std::span<u8> inline_output) { |
| 64 | switch (command.group) { | 64 | switch (command.group) { |
| 65 | case 'G': | 65 | case 'G': |
| 66 | switch (command.cmd) { | 66 | switch (command.cmd) { |
| @@ -82,7 +82,7 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> | |||
| 82 | void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {} | 82 | void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {} |
| 83 | void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {} | 83 | void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {} |
| 84 | 84 | ||
| 85 | NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::vector<u8>& output) { | 85 | NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::span<u8> output) { |
| 86 | LOG_DEBUG(Service_NVDRV, "called"); | 86 | LOG_DEBUG(Service_NVDRV, "called"); |
| 87 | IoctlCharacteristics params{}; | 87 | IoctlCharacteristics params{}; |
| 88 | std::memcpy(¶ms, input.data(), input.size()); | 88 | std::memcpy(¶ms, input.data(), input.size()); |
| @@ -127,8 +127,8 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::vec | |||
| 127 | return NvResult::Success; | 127 | return NvResult::Success; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::vector<u8>& output, | 130 | NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::span<u8> output, |
| 131 | std::vector<u8>& inline_output) { | 131 | std::span<u8> inline_output) { |
| 132 | LOG_DEBUG(Service_NVDRV, "called"); | 132 | LOG_DEBUG(Service_NVDRV, "called"); |
| 133 | IoctlCharacteristics params{}; | 133 | IoctlCharacteristics params{}; |
| 134 | std::memcpy(¶ms, input.data(), input.size()); | 134 | std::memcpy(¶ms, input.data(), input.size()); |
| @@ -175,7 +175,7 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::vec | |||
| 175 | return NvResult::Success; | 175 | return NvResult::Success; |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::vector<u8>& output) { | 178 | NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::span<u8> output) { |
| 179 | IoctlGpuGetTpcMasksArgs params{}; | 179 | IoctlGpuGetTpcMasksArgs params{}; |
| 180 | std::memcpy(¶ms, input.data(), input.size()); | 180 | std::memcpy(¶ms, input.data(), input.size()); |
| 181 | LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); | 181 | LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); |
| @@ -186,8 +186,8 @@ NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::vector<u8> | |||
| 186 | return NvResult::Success; | 186 | return NvResult::Success; |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::vector<u8>& output, | 189 | NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::span<u8> output, |
| 190 | std::vector<u8>& inline_output) { | 190 | std::span<u8> inline_output) { |
| 191 | IoctlGpuGetTpcMasksArgs params{}; | 191 | IoctlGpuGetTpcMasksArgs params{}; |
| 192 | std::memcpy(¶ms, input.data(), input.size()); | 192 | std::memcpy(¶ms, input.data(), input.size()); |
| 193 | LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); | 193 | LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); |
| @@ -199,7 +199,7 @@ NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::vector<u8> | |||
| 199 | return NvResult::Success; | 199 | return NvResult::Success; |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | NvResult nvhost_ctrl_gpu::GetActiveSlotMask(std::span<const u8> input, std::vector<u8>& output) { | 202 | NvResult nvhost_ctrl_gpu::GetActiveSlotMask(std::span<const u8> input, std::span<u8> output) { |
| 203 | LOG_DEBUG(Service_NVDRV, "called"); | 203 | LOG_DEBUG(Service_NVDRV, "called"); |
| 204 | 204 | ||
| 205 | IoctlActiveSlotMask params{}; | 205 | IoctlActiveSlotMask params{}; |
| @@ -212,7 +212,7 @@ NvResult nvhost_ctrl_gpu::GetActiveSlotMask(std::span<const u8> input, std::vect | |||
| 212 | return NvResult::Success; | 212 | return NvResult::Success; |
| 213 | } | 213 | } |
| 214 | 214 | ||
| 215 | NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(std::span<const u8> input, std::vector<u8>& output) { | 215 | NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(std::span<const u8> input, std::span<u8> output) { |
| 216 | LOG_DEBUG(Service_NVDRV, "called"); | 216 | LOG_DEBUG(Service_NVDRV, "called"); |
| 217 | 217 | ||
| 218 | IoctlZcullGetCtxSize params{}; | 218 | IoctlZcullGetCtxSize params{}; |
| @@ -224,7 +224,7 @@ NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(std::span<const u8> input, std::vector | |||
| 224 | return NvResult::Success; | 224 | return NvResult::Success; |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span<const u8> input, std::vector<u8>& output) { | 227 | NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span<const u8> input, std::span<u8> output) { |
| 228 | LOG_DEBUG(Service_NVDRV, "called"); | 228 | LOG_DEBUG(Service_NVDRV, "called"); |
| 229 | 229 | ||
| 230 | IoctlNvgpuGpuZcullGetInfoArgs params{}; | 230 | IoctlNvgpuGpuZcullGetInfoArgs params{}; |
| @@ -247,7 +247,7 @@ NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span<const u8> input, std::vector<u8 | |||
| 247 | return NvResult::Success; | 247 | return NvResult::Success; |
| 248 | } | 248 | } |
| 249 | 249 | ||
| 250 | NvResult nvhost_ctrl_gpu::ZBCSetTable(std::span<const u8> input, std::vector<u8>& output) { | 250 | NvResult nvhost_ctrl_gpu::ZBCSetTable(std::span<const u8> input, std::span<u8> output) { |
| 251 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 251 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 252 | 252 | ||
| 253 | IoctlZbcSetTable params{}; | 253 | IoctlZbcSetTable params{}; |
| @@ -263,7 +263,7 @@ NvResult nvhost_ctrl_gpu::ZBCSetTable(std::span<const u8> input, std::vector<u8> | |||
| 263 | return NvResult::Success; | 263 | return NvResult::Success; |
| 264 | } | 264 | } |
| 265 | 265 | ||
| 266 | NvResult nvhost_ctrl_gpu::ZBCQueryTable(std::span<const u8> input, std::vector<u8>& output) { | 266 | NvResult nvhost_ctrl_gpu::ZBCQueryTable(std::span<const u8> input, std::span<u8> output) { |
| 267 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 267 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 268 | 268 | ||
| 269 | IoctlZbcQueryTable params{}; | 269 | IoctlZbcQueryTable params{}; |
| @@ -273,7 +273,7 @@ NvResult nvhost_ctrl_gpu::ZBCQueryTable(std::span<const u8> input, std::vector<u | |||
| 273 | return NvResult::Success; | 273 | return NvResult::Success; |
| 274 | } | 274 | } |
| 275 | 275 | ||
| 276 | NvResult nvhost_ctrl_gpu::FlushL2(std::span<const u8> input, std::vector<u8>& output) { | 276 | NvResult nvhost_ctrl_gpu::FlushL2(std::span<const u8> input, std::span<u8> output) { |
| 277 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 277 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 278 | 278 | ||
| 279 | IoctlFlushL2 params{}; | 279 | IoctlFlushL2 params{}; |
| @@ -283,7 +283,7 @@ NvResult nvhost_ctrl_gpu::FlushL2(std::span<const u8> input, std::vector<u8>& ou | |||
| 283 | return NvResult::Success; | 283 | return NvResult::Success; |
| 284 | } | 284 | } |
| 285 | 285 | ||
| 286 | NvResult nvhost_ctrl_gpu::GetGpuTime(std::span<const u8> input, std::vector<u8>& output) { | 286 | NvResult nvhost_ctrl_gpu::GetGpuTime(std::span<const u8> input, std::span<u8> output) { |
| 287 | LOG_DEBUG(Service_NVDRV, "called"); | 287 | LOG_DEBUG(Service_NVDRV, "called"); |
| 288 | 288 | ||
| 289 | IoctlGetGpuTime params{}; | 289 | IoctlGetGpuTime params{}; |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index b9333d9d3..97995551c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h | |||
| @@ -22,11 +22,11 @@ public: | |||
| 22 | ~nvhost_ctrl_gpu() override; | 22 | ~nvhost_ctrl_gpu() override; |
| 23 | 23 | ||
| 24 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 24 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 25 | std::vector<u8>& output) override; | 25 | std::span<u8> output) override; |
| 26 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 26 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 27 | std::span<const u8> inline_input, std::vector<u8>& output) override; | 27 | std::span<const u8> inline_input, std::span<u8> output) override; |
| 28 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, | 28 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, |
| 29 | std::vector<u8>& inline_output) override; | 29 | std::span<u8> inline_output) override; |
| 30 | 30 | ||
| 31 | void OnOpen(DeviceFD fd) override; | 31 | void OnOpen(DeviceFD fd) override; |
| 32 | void OnClose(DeviceFD fd) override; | 32 | void OnClose(DeviceFD fd) override; |
| @@ -151,21 +151,21 @@ private: | |||
| 151 | }; | 151 | }; |
| 152 | static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); | 152 | static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); |
| 153 | 153 | ||
| 154 | NvResult GetCharacteristics(std::span<const u8> input, std::vector<u8>& output); | 154 | NvResult GetCharacteristics(std::span<const u8> input, std::span<u8> output); |
| 155 | NvResult GetCharacteristics(std::span<const u8> input, std::vector<u8>& output, | 155 | NvResult GetCharacteristics(std::span<const u8> input, std::span<u8> output, |
| 156 | std::vector<u8>& inline_output); | 156 | std::span<u8> inline_output); |
| 157 | 157 | ||
| 158 | NvResult GetTPCMasks(std::span<const u8> input, std::vector<u8>& output); | 158 | NvResult GetTPCMasks(std::span<const u8> input, std::span<u8> output); |
| 159 | NvResult GetTPCMasks(std::span<const u8> input, std::vector<u8>& output, | 159 | NvResult GetTPCMasks(std::span<const u8> input, std::span<u8> output, |
| 160 | std::vector<u8>& inline_output); | 160 | std::span<u8> inline_output); |
| 161 | 161 | ||
| 162 | NvResult GetActiveSlotMask(std::span<const u8> input, std::vector<u8>& output); | 162 | NvResult GetActiveSlotMask(std::span<const u8> input, std::span<u8> output); |
| 163 | NvResult ZCullGetCtxSize(std::span<const u8> input, std::vector<u8>& output); | 163 | NvResult ZCullGetCtxSize(std::span<const u8> input, std::span<u8> output); |
| 164 | NvResult ZCullGetInfo(std::span<const u8> input, std::vector<u8>& output); | 164 | NvResult ZCullGetInfo(std::span<const u8> input, std::span<u8> output); |
| 165 | NvResult ZBCSetTable(std::span<const u8> input, std::vector<u8>& output); | 165 | NvResult ZBCSetTable(std::span<const u8> input, std::span<u8> output); |
| 166 | NvResult ZBCQueryTable(std::span<const u8> input, std::vector<u8>& output); | 166 | NvResult ZBCQueryTable(std::span<const u8> input, std::span<u8> output); |
| 167 | NvResult FlushL2(std::span<const u8> input, std::vector<u8>& output); | 167 | NvResult FlushL2(std::span<const u8> input, std::span<u8> output); |
| 168 | NvResult GetGpuTime(std::span<const u8> input, std::vector<u8>& output); | 168 | NvResult GetGpuTime(std::span<const u8> input, std::span<u8> output); |
| 169 | 169 | ||
| 170 | EventInterface& events_interface; | 170 | EventInterface& events_interface; |
| 171 | 171 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 453a965dc..46a25fcab 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | |||
| @@ -47,7 +47,7 @@ nvhost_gpu::~nvhost_gpu() { | |||
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 49 | NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 50 | std::vector<u8>& output) { | 50 | std::span<u8> output) { |
| 51 | switch (command.group) { | 51 | switch (command.group) { |
| 52 | case 0x0: | 52 | case 0x0: |
| 53 | switch (command.cmd) { | 53 | switch (command.cmd) { |
| @@ -99,7 +99,7 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu | |||
| 99 | }; | 99 | }; |
| 100 | 100 | ||
| 101 | NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 101 | NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 102 | std::span<const u8> inline_input, std::vector<u8>& output) { | 102 | std::span<const u8> inline_input, std::span<u8> output) { |
| 103 | switch (command.group) { | 103 | switch (command.group) { |
| 104 | case 'H': | 104 | case 'H': |
| 105 | switch (command.cmd) { | 105 | switch (command.cmd) { |
| @@ -113,7 +113,7 @@ NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> inpu | |||
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, | 115 | NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 116 | std::vector<u8>& output, std::vector<u8>& inline_output) { | 116 | std::span<u8> output, std::span<u8> inline_output) { |
| 117 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | 117 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 118 | return NvResult::NotImplemented; | 118 | return NvResult::NotImplemented; |
| 119 | } | 119 | } |
| @@ -121,7 +121,7 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu | |||
| 121 | void nvhost_gpu::OnOpen(DeviceFD fd) {} | 121 | void nvhost_gpu::OnOpen(DeviceFD fd) {} |
| 122 | void nvhost_gpu::OnClose(DeviceFD fd) {} | 122 | void nvhost_gpu::OnClose(DeviceFD fd) {} |
| 123 | 123 | ||
| 124 | NvResult nvhost_gpu::SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output) { | 124 | NvResult nvhost_gpu::SetNVMAPfd(std::span<const u8> input, std::span<u8> output) { |
| 125 | IoctlSetNvmapFD params{}; | 125 | IoctlSetNvmapFD params{}; |
| 126 | std::memcpy(¶ms, input.data(), input.size()); | 126 | std::memcpy(¶ms, input.data(), input.size()); |
| 127 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 127 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| @@ -130,7 +130,7 @@ NvResult nvhost_gpu::SetNVMAPfd(std::span<const u8> input, std::vector<u8>& outp | |||
| 130 | return NvResult::Success; | 130 | return NvResult::Success; |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | NvResult nvhost_gpu::SetClientData(std::span<const u8> input, std::vector<u8>& output) { | 133 | NvResult nvhost_gpu::SetClientData(std::span<const u8> input, std::span<u8> output) { |
| 134 | LOG_DEBUG(Service_NVDRV, "called"); | 134 | LOG_DEBUG(Service_NVDRV, "called"); |
| 135 | 135 | ||
| 136 | IoctlClientData params{}; | 136 | IoctlClientData params{}; |
| @@ -139,7 +139,7 @@ NvResult nvhost_gpu::SetClientData(std::span<const u8> input, std::vector<u8>& o | |||
| 139 | return NvResult::Success; | 139 | return NvResult::Success; |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | NvResult nvhost_gpu::GetClientData(std::span<const u8> input, std::vector<u8>& output) { | 142 | NvResult nvhost_gpu::GetClientData(std::span<const u8> input, std::span<u8> output) { |
| 143 | LOG_DEBUG(Service_NVDRV, "called"); | 143 | LOG_DEBUG(Service_NVDRV, "called"); |
| 144 | 144 | ||
| 145 | IoctlClientData params{}; | 145 | IoctlClientData params{}; |
| @@ -149,7 +149,7 @@ NvResult nvhost_gpu::GetClientData(std::span<const u8> input, std::vector<u8>& o | |||
| 149 | return NvResult::Success; | 149 | return NvResult::Success; |
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | NvResult nvhost_gpu::ZCullBind(std::span<const u8> input, std::vector<u8>& output) { | 152 | NvResult nvhost_gpu::ZCullBind(std::span<const u8> input, std::span<u8> output) { |
| 153 | std::memcpy(&zcull_params, input.data(), input.size()); | 153 | std::memcpy(&zcull_params, input.data(), input.size()); |
| 154 | LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, | 154 | LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, |
| 155 | zcull_params.mode); | 155 | zcull_params.mode); |
| @@ -158,7 +158,7 @@ NvResult nvhost_gpu::ZCullBind(std::span<const u8> input, std::vector<u8>& outpu | |||
| 158 | return NvResult::Success; | 158 | return NvResult::Success; |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | NvResult nvhost_gpu::SetErrorNotifier(std::span<const u8> input, std::vector<u8>& output) { | 161 | NvResult nvhost_gpu::SetErrorNotifier(std::span<const u8> input, std::span<u8> output) { |
| 162 | IoctlSetErrorNotifier params{}; | 162 | IoctlSetErrorNotifier params{}; |
| 163 | std::memcpy(¶ms, input.data(), input.size()); | 163 | std::memcpy(¶ms, input.data(), input.size()); |
| 164 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, | 164 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, |
| @@ -168,14 +168,14 @@ NvResult nvhost_gpu::SetErrorNotifier(std::span<const u8> input, std::vector<u8> | |||
| 168 | return NvResult::Success; | 168 | return NvResult::Success; |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | NvResult nvhost_gpu::SetChannelPriority(std::span<const u8> input, std::vector<u8>& output) { | 171 | NvResult nvhost_gpu::SetChannelPriority(std::span<const u8> input, std::span<u8> output) { |
| 172 | std::memcpy(&channel_priority, input.data(), input.size()); | 172 | std::memcpy(&channel_priority, input.data(), input.size()); |
| 173 | LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); | 173 | LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); |
| 174 | 174 | ||
| 175 | return NvResult::Success; | 175 | return NvResult::Success; |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | NvResult nvhost_gpu::AllocGPFIFOEx2(std::span<const u8> input, std::vector<u8>& output) { | 178 | NvResult nvhost_gpu::AllocGPFIFOEx2(std::span<const u8> input, std::span<u8> output) { |
| 179 | IoctlAllocGpfifoEx2 params{}; | 179 | IoctlAllocGpfifoEx2 params{}; |
| 180 | std::memcpy(¶ms, input.data(), input.size()); | 180 | std::memcpy(¶ms, input.data(), input.size()); |
| 181 | LOG_WARNING(Service_NVDRV, | 181 | LOG_WARNING(Service_NVDRV, |
| @@ -197,7 +197,7 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(std::span<const u8> input, std::vector<u8>& | |||
| 197 | return NvResult::Success; | 197 | return NvResult::Success; |
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | NvResult nvhost_gpu::AllocateObjectContext(std::span<const u8> input, std::vector<u8>& output) { | 200 | NvResult nvhost_gpu::AllocateObjectContext(std::span<const u8> input, std::span<u8> output) { |
| 201 | IoctlAllocObjCtx params{}; | 201 | IoctlAllocObjCtx params{}; |
| 202 | std::memcpy(¶ms, input.data(), input.size()); | 202 | std::memcpy(¶ms, input.data(), input.size()); |
| 203 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, | 203 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, |
| @@ -208,7 +208,8 @@ NvResult nvhost_gpu::AllocateObjectContext(std::span<const u8> input, std::vecto | |||
| 208 | return NvResult::Success; | 208 | return NvResult::Success; |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | static std::vector<Tegra::CommandHeader> BuildWaitCommandList(NvFence fence) { | 211 | static boost::container::small_vector<Tegra::CommandHeader, 512> BuildWaitCommandList( |
| 212 | NvFence fence) { | ||
| 212 | return { | 213 | return { |
| 213 | Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointPayload, 1, | 214 | Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointPayload, 1, |
| 214 | Tegra::SubmissionMode::Increasing), | 215 | Tegra::SubmissionMode::Increasing), |
| @@ -219,35 +220,35 @@ static std::vector<Tegra::CommandHeader> BuildWaitCommandList(NvFence fence) { | |||
| 219 | }; | 220 | }; |
| 220 | } | 221 | } |
| 221 | 222 | ||
| 222 | static std::vector<Tegra::CommandHeader> BuildIncrementCommandList(NvFence fence) { | 223 | static boost::container::small_vector<Tegra::CommandHeader, 512> BuildIncrementCommandList( |
| 223 | std::vector<Tegra::CommandHeader> result{ | 224 | NvFence fence) { |
| 225 | boost::container::small_vector<Tegra::CommandHeader, 512> result{ | ||
| 224 | Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointPayload, 1, | 226 | Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointPayload, 1, |
| 225 | Tegra::SubmissionMode::Increasing), | 227 | Tegra::SubmissionMode::Increasing), |
| 226 | {}}; | 228 | {}}; |
| 227 | 229 | ||
| 228 | for (u32 count = 0; count < 2; ++count) { | 230 | for (u32 count = 0; count < 2; ++count) { |
| 229 | result.emplace_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointOperation, 1, | 231 | result.push_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointOperation, 1, |
| 230 | Tegra::SubmissionMode::Increasing)); | 232 | Tegra::SubmissionMode::Increasing)); |
| 231 | result.emplace_back( | 233 | result.push_back( |
| 232 | BuildFenceAction(Tegra::Engines::Puller::FenceOperation::Increment, fence.id)); | 234 | BuildFenceAction(Tegra::Engines::Puller::FenceOperation::Increment, fence.id)); |
| 233 | } | 235 | } |
| 234 | 236 | ||
| 235 | return result; | 237 | return result; |
| 236 | } | 238 | } |
| 237 | 239 | ||
| 238 | static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(NvFence fence) { | 240 | static boost::container::small_vector<Tegra::CommandHeader, 512> BuildIncrementWithWfiCommandList( |
| 239 | std::vector<Tegra::CommandHeader> result{ | 241 | NvFence fence) { |
| 242 | boost::container::small_vector<Tegra::CommandHeader, 512> result{ | ||
| 240 | Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForIdle, 1, | 243 | Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForIdle, 1, |
| 241 | Tegra::SubmissionMode::Increasing), | 244 | Tegra::SubmissionMode::Increasing), |
| 242 | {}}; | 245 | {}}; |
| 243 | const std::vector<Tegra::CommandHeader> increment{BuildIncrementCommandList(fence)}; | 246 | auto increment_list{BuildIncrementCommandList(fence)}; |
| 244 | 247 | result.insert(result.end(), increment_list.begin(), increment_list.end()); | |
| 245 | result.insert(result.end(), increment.begin(), increment.end()); | ||
| 246 | |||
| 247 | return result; | 248 | return result; |
| 248 | } | 249 | } |
| 249 | 250 | ||
| 250 | NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, | 251 | NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span<u8> output, |
| 251 | Tegra::CommandList&& entries) { | 252 | Tegra::CommandList&& entries) { |
| 252 | LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, | 253 | LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, |
| 253 | params.num_entries, params.flags.raw); | 254 | params.num_entries, params.flags.raw); |
| @@ -293,7 +294,7 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8> | |||
| 293 | return NvResult::Success; | 294 | return NvResult::Success; |
| 294 | } | 295 | } |
| 295 | 296 | ||
| 296 | NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::vector<u8>& output, | 297 | NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<u8> output, |
| 297 | bool kickoff) { | 298 | bool kickoff) { |
| 298 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | 299 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { |
| 299 | UNIMPLEMENTED(); | 300 | UNIMPLEMENTED(); |
| @@ -315,7 +316,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::vector<u8> | |||
| 315 | } | 316 | } |
| 316 | 317 | ||
| 317 | NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline, | 318 | NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline, |
| 318 | std::vector<u8>& output) { | 319 | std::span<u8> output) { |
| 319 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | 320 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { |
| 320 | UNIMPLEMENTED(); | 321 | UNIMPLEMENTED(); |
| 321 | return NvResult::InvalidSize; | 322 | return NvResult::InvalidSize; |
| @@ -327,7 +328,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<const | |||
| 327 | return SubmitGPFIFOImpl(params, output, std::move(entries)); | 328 | return SubmitGPFIFOImpl(params, output, std::move(entries)); |
| 328 | } | 329 | } |
| 329 | 330 | ||
| 330 | NvResult nvhost_gpu::GetWaitbase(std::span<const u8> input, std::vector<u8>& output) { | 331 | NvResult nvhost_gpu::GetWaitbase(std::span<const u8> input, std::span<u8> output) { |
| 331 | IoctlGetWaitbase params{}; | 332 | IoctlGetWaitbase params{}; |
| 332 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); | 333 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); |
| 333 | LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); | 334 | LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); |
| @@ -337,7 +338,7 @@ NvResult nvhost_gpu::GetWaitbase(std::span<const u8> input, std::vector<u8>& out | |||
| 337 | return NvResult::Success; | 338 | return NvResult::Success; |
| 338 | } | 339 | } |
| 339 | 340 | ||
| 340 | NvResult nvhost_gpu::ChannelSetTimeout(std::span<const u8> input, std::vector<u8>& output) { | 341 | NvResult nvhost_gpu::ChannelSetTimeout(std::span<const u8> input, std::span<u8> output) { |
| 341 | IoctlChannelSetTimeout params{}; | 342 | IoctlChannelSetTimeout params{}; |
| 342 | std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); | 343 | std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); |
| 343 | LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); | 344 | LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); |
| @@ -345,7 +346,7 @@ NvResult nvhost_gpu::ChannelSetTimeout(std::span<const u8> input, std::vector<u8 | |||
| 345 | return NvResult::Success; | 346 | return NvResult::Success; |
| 346 | } | 347 | } |
| 347 | 348 | ||
| 348 | NvResult nvhost_gpu::ChannelSetTimeslice(std::span<const u8> input, std::vector<u8>& output) { | 349 | NvResult nvhost_gpu::ChannelSetTimeslice(std::span<const u8> input, std::span<u8> output) { |
| 349 | IoctlSetTimeslice params{}; | 350 | IoctlSetTimeslice params{}; |
| 350 | std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice)); | 351 | std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice)); |
| 351 | LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); | 352 | LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 3ca58202d..529c20526 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h | |||
| @@ -41,11 +41,11 @@ public: | |||
| 41 | ~nvhost_gpu() override; | 41 | ~nvhost_gpu() override; |
| 42 | 42 | ||
| 43 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 43 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 44 | std::vector<u8>& output) override; | 44 | std::span<u8> output) override; |
| 45 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 45 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 46 | std::span<const u8> inline_input, std::vector<u8>& output) override; | 46 | std::span<const u8> inline_input, std::span<u8> output) override; |
| 47 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, | 47 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, |
| 48 | std::vector<u8>& inline_output) override; | 48 | std::span<u8> inline_output) override; |
| 49 | 49 | ||
| 50 | void OnOpen(DeviceFD fd) override; | 50 | void OnOpen(DeviceFD fd) override; |
| 51 | void OnClose(DeviceFD fd) override; | 51 | void OnClose(DeviceFD fd) override; |
| @@ -186,23 +186,23 @@ private: | |||
| 186 | u32_le channel_priority{}; | 186 | u32_le channel_priority{}; |
| 187 | u32_le channel_timeslice{}; | 187 | u32_le channel_timeslice{}; |
| 188 | 188 | ||
| 189 | NvResult SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output); | 189 | NvResult SetNVMAPfd(std::span<const u8> input, std::span<u8> output); |
| 190 | NvResult SetClientData(std::span<const u8> input, std::vector<u8>& output); | 190 | NvResult SetClientData(std::span<const u8> input, std::span<u8> output); |
| 191 | NvResult GetClientData(std::span<const u8> input, std::vector<u8>& output); | 191 | NvResult GetClientData(std::span<const u8> input, std::span<u8> output); |
| 192 | NvResult ZCullBind(std::span<const u8> input, std::vector<u8>& output); | 192 | NvResult ZCullBind(std::span<const u8> input, std::span<u8> output); |
| 193 | NvResult SetErrorNotifier(std::span<const u8> input, std::vector<u8>& output); | 193 | NvResult SetErrorNotifier(std::span<const u8> input, std::span<u8> output); |
| 194 | NvResult SetChannelPriority(std::span<const u8> input, std::vector<u8>& output); | 194 | NvResult SetChannelPriority(std::span<const u8> input, std::span<u8> output); |
| 195 | NvResult AllocGPFIFOEx2(std::span<const u8> input, std::vector<u8>& output); | 195 | NvResult AllocGPFIFOEx2(std::span<const u8> input, std::span<u8> output); |
| 196 | NvResult AllocateObjectContext(std::span<const u8> input, std::vector<u8>& output); | 196 | NvResult AllocateObjectContext(std::span<const u8> input, std::span<u8> output); |
| 197 | NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, | 197 | NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span<u8> output, |
| 198 | Tegra::CommandList&& entries); | 198 | Tegra::CommandList&& entries); |
| 199 | NvResult SubmitGPFIFOBase(std::span<const u8> input, std::vector<u8>& output, | 199 | NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<u8> output, |
| 200 | bool kickoff = false); | 200 | bool kickoff = false); |
| 201 | NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline, | 201 | NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline, |
| 202 | std::vector<u8>& output); | 202 | std::span<u8> output); |
| 203 | NvResult GetWaitbase(std::span<const u8> input, std::vector<u8>& output); | 203 | NvResult GetWaitbase(std::span<const u8> input, std::span<u8> output); |
| 204 | NvResult ChannelSetTimeout(std::span<const u8> input, std::vector<u8>& output); | 204 | NvResult ChannelSetTimeout(std::span<const u8> input, std::span<u8> output); |
| 205 | NvResult ChannelSetTimeslice(std::span<const u8> input, std::vector<u8>& output); | 205 | NvResult ChannelSetTimeslice(std::span<const u8> input, std::span<u8> output); |
| 206 | 206 | ||
| 207 | EventInterface& events_interface; | 207 | EventInterface& events_interface; |
| 208 | NvCore::Container& core; | 208 | NvCore::Container& core; |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index dc45169ad..a174442a6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp | |||
| @@ -16,7 +16,7 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core_) | |||
| 16 | nvhost_nvdec::~nvhost_nvdec() = default; | 16 | nvhost_nvdec::~nvhost_nvdec() = default; |
| 17 | 17 | ||
| 18 | NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 18 | NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 19 | std::vector<u8>& output) { | 19 | std::span<u8> output) { |
| 20 | switch (command.group) { | 20 | switch (command.group) { |
| 21 | case 0x0: | 21 | case 0x0: |
| 22 | switch (command.cmd) { | 22 | switch (command.cmd) { |
| @@ -56,13 +56,13 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in | |||
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | NvResult nvhost_nvdec::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 58 | NvResult nvhost_nvdec::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 59 | std::span<const u8> inline_input, std::vector<u8>& output) { | 59 | std::span<const u8> inline_input, std::span<u8> output) { |
| 60 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | 60 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 61 | return NvResult::NotImplemented; | 61 | return NvResult::NotImplemented; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, | 64 | NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 65 | std::vector<u8>& output, std::vector<u8>& inline_output) { | 65 | std::span<u8> output, std::span<u8> inline_output) { |
| 66 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | 66 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 67 | return NvResult::NotImplemented; | 67 | return NvResult::NotImplemented; |
| 68 | } | 68 | } |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 0d615bbcb..ad2233c49 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | |||
| @@ -14,11 +14,11 @@ public: | |||
| 14 | ~nvhost_nvdec() override; | 14 | ~nvhost_nvdec() override; |
| 15 | 15 | ||
| 16 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 16 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 17 | std::vector<u8>& output) override; | 17 | std::span<u8> output) override; |
| 18 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 18 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 19 | std::span<const u8> inline_input, std::vector<u8>& output) override; | 19 | std::span<const u8> inline_input, std::span<u8> output) override; |
| 20 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, | 20 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, |
| 21 | std::vector<u8>& inline_output) override; | 21 | std::span<u8> inline_output) override; |
| 22 | 22 | ||
| 23 | void OnOpen(DeviceFD fd) override; | 23 | void OnOpen(DeviceFD fd) override; |
| 24 | void OnClose(DeviceFD fd) override; | 24 | void OnClose(DeviceFD fd) override; |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index 1ab51f10b..61649aa4a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp | |||
| @@ -36,7 +36,7 @@ std::size_t SliceVectors(std::span<const u8> input, std::vector<T>& dst, std::si | |||
| 36 | // Writes the data in src to an offset into the dst vector. The offset is specified in bytes | 36 | // Writes the data in src to an offset into the dst vector. The offset is specified in bytes |
| 37 | // Returns the number of bytes written into dst. | 37 | // Returns the number of bytes written into dst. |
| 38 | template <typename T> | 38 | template <typename T> |
| 39 | std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::size_t offset) { | 39 | std::size_t WriteVectors(std::span<u8> dst, const std::vector<T>& src, std::size_t offset) { |
| 40 | if (src.empty()) { | 40 | if (src.empty()) { |
| 41 | return 0; | 41 | return 0; |
| 42 | } | 42 | } |
| @@ -72,8 +72,7 @@ NvResult nvhost_nvdec_common::SetNVMAPfd(std::span<const u8> input) { | |||
| 72 | return NvResult::Success; | 72 | return NvResult::Success; |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, | 75 | NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, std::span<u8> output) { |
| 76 | std::vector<u8>& output) { | ||
| 77 | IoctlSubmit params{}; | 76 | IoctlSubmit params{}; |
| 78 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit)); | 77 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit)); |
| 79 | LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count); | 78 | LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count); |
| @@ -121,7 +120,7 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, | |||
| 121 | return NvResult::Success; | 120 | return NvResult::Success; |
| 122 | } | 121 | } |
| 123 | 122 | ||
| 124 | NvResult nvhost_nvdec_common::GetSyncpoint(std::span<const u8> input, std::vector<u8>& output) { | 123 | NvResult nvhost_nvdec_common::GetSyncpoint(std::span<const u8> input, std::span<u8> output) { |
| 125 | IoctlGetSyncpoint params{}; | 124 | IoctlGetSyncpoint params{}; |
| 126 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint)); | 125 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint)); |
| 127 | LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param); | 126 | LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param); |
| @@ -133,7 +132,7 @@ NvResult nvhost_nvdec_common::GetSyncpoint(std::span<const u8> input, std::vecto | |||
| 133 | return NvResult::Success; | 132 | return NvResult::Success; |
| 134 | } | 133 | } |
| 135 | 134 | ||
| 136 | NvResult nvhost_nvdec_common::GetWaitbase(std::span<const u8> input, std::vector<u8>& output) { | 135 | NvResult nvhost_nvdec_common::GetWaitbase(std::span<const u8> input, std::span<u8> output) { |
| 137 | IoctlGetWaitbase params{}; | 136 | IoctlGetWaitbase params{}; |
| 138 | LOG_CRITICAL(Service_NVDRV, "called WAITBASE"); | 137 | LOG_CRITICAL(Service_NVDRV, "called WAITBASE"); |
| 139 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); | 138 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); |
| @@ -142,7 +141,7 @@ NvResult nvhost_nvdec_common::GetWaitbase(std::span<const u8> input, std::vector | |||
| 142 | return NvResult::Success; | 141 | return NvResult::Success; |
| 143 | } | 142 | } |
| 144 | 143 | ||
| 145 | NvResult nvhost_nvdec_common::MapBuffer(std::span<const u8> input, std::vector<u8>& output) { | 144 | NvResult nvhost_nvdec_common::MapBuffer(std::span<const u8> input, std::span<u8> output) { |
| 146 | IoctlMapBuffer params{}; | 145 | IoctlMapBuffer params{}; |
| 147 | std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); | 146 | std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); |
| 148 | std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); | 147 | std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); |
| @@ -159,7 +158,7 @@ NvResult nvhost_nvdec_common::MapBuffer(std::span<const u8> input, std::vector<u | |||
| 159 | return NvResult::Success; | 158 | return NvResult::Success; |
| 160 | } | 159 | } |
| 161 | 160 | ||
| 162 | NvResult nvhost_nvdec_common::UnmapBuffer(std::span<const u8> input, std::vector<u8>& output) { | 161 | NvResult nvhost_nvdec_common::UnmapBuffer(std::span<const u8> input, std::span<u8> output) { |
| 163 | IoctlMapBuffer params{}; | 162 | IoctlMapBuffer params{}; |
| 164 | std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); | 163 | std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); |
| 165 | std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); | 164 | std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); |
| @@ -173,7 +172,7 @@ NvResult nvhost_nvdec_common::UnmapBuffer(std::span<const u8> input, std::vector | |||
| 173 | return NvResult::Success; | 172 | return NvResult::Success; |
| 174 | } | 173 | } |
| 175 | 174 | ||
| 176 | NvResult nvhost_nvdec_common::SetSubmitTimeout(std::span<const u8> input, std::vector<u8>& output) { | 175 | NvResult nvhost_nvdec_common::SetSubmitTimeout(std::span<const u8> input, std::span<u8> output) { |
| 177 | std::memcpy(&submit_timeout, input.data(), input.size()); | 176 | std::memcpy(&submit_timeout, input.data(), input.size()); |
| 178 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 177 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 179 | return NvResult::Success; | 178 | return NvResult::Success; |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index 5af26a26f..9bb573bfe 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h | |||
| @@ -108,12 +108,12 @@ protected: | |||
| 108 | 108 | ||
| 109 | /// Ioctl command implementations | 109 | /// Ioctl command implementations |
| 110 | NvResult SetNVMAPfd(std::span<const u8> input); | 110 | NvResult SetNVMAPfd(std::span<const u8> input); |
| 111 | NvResult Submit(DeviceFD fd, std::span<const u8> input, std::vector<u8>& output); | 111 | NvResult Submit(DeviceFD fd, std::span<const u8> input, std::span<u8> output); |
| 112 | NvResult GetSyncpoint(std::span<const u8> input, std::vector<u8>& output); | 112 | NvResult GetSyncpoint(std::span<const u8> input, std::span<u8> output); |
| 113 | NvResult GetWaitbase(std::span<const u8> input, std::vector<u8>& output); | 113 | NvResult GetWaitbase(std::span<const u8> input, std::span<u8> output); |
| 114 | NvResult MapBuffer(std::span<const u8> input, std::vector<u8>& output); | 114 | NvResult MapBuffer(std::span<const u8> input, std::span<u8> output); |
| 115 | NvResult UnmapBuffer(std::span<const u8> input, std::vector<u8>& output); | 115 | NvResult UnmapBuffer(std::span<const u8> input, std::span<u8> output); |
| 116 | NvResult SetSubmitTimeout(std::span<const u8> input, std::vector<u8>& output); | 116 | NvResult SetSubmitTimeout(std::span<const u8> input, std::span<u8> output); |
| 117 | 117 | ||
| 118 | Kernel::KEvent* QueryEvent(u32 event_id) override; | 118 | Kernel::KEvent* QueryEvent(u32 event_id) override; |
| 119 | 119 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index 39f30e7c8..a05c8cdae 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp | |||
| @@ -13,7 +13,7 @@ nvhost_nvjpg::nvhost_nvjpg(Core::System& system_) : nvdevice{system_} {} | |||
| 13 | nvhost_nvjpg::~nvhost_nvjpg() = default; | 13 | nvhost_nvjpg::~nvhost_nvjpg() = default; |
| 14 | 14 | ||
| 15 | NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 15 | NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 16 | std::vector<u8>& output) { | 16 | std::span<u8> output) { |
| 17 | switch (command.group) { | 17 | switch (command.group) { |
| 18 | case 'H': | 18 | case 'H': |
| 19 | switch (command.cmd) { | 19 | switch (command.cmd) { |
| @@ -32,13 +32,13 @@ NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in | |||
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | NvResult nvhost_nvjpg::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 34 | NvResult nvhost_nvjpg::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 35 | std::span<const u8> inline_input, std::vector<u8>& output) { | 35 | std::span<const u8> inline_input, std::span<u8> output) { |
| 36 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | 36 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 37 | return NvResult::NotImplemented; | 37 | return NvResult::NotImplemented; |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, | 40 | NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 41 | std::vector<u8>& output, std::vector<u8>& inline_output) { | 41 | std::span<u8> output, std::span<u8> inline_output) { |
| 42 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | 42 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 43 | return NvResult::NotImplemented; | 43 | return NvResult::NotImplemented; |
| 44 | } | 44 | } |
| @@ -46,7 +46,7 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in | |||
| 46 | void nvhost_nvjpg::OnOpen(DeviceFD fd) {} | 46 | void nvhost_nvjpg::OnOpen(DeviceFD fd) {} |
| 47 | void nvhost_nvjpg::OnClose(DeviceFD fd) {} | 47 | void nvhost_nvjpg::OnClose(DeviceFD fd) {} |
| 48 | 48 | ||
| 49 | NvResult nvhost_nvjpg::SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output) { | 49 | NvResult nvhost_nvjpg::SetNVMAPfd(std::span<const u8> input, std::span<u8> output) { |
| 50 | IoctlSetNvmapFD params{}; | 50 | IoctlSetNvmapFD params{}; |
| 51 | std::memcpy(¶ms, input.data(), input.size()); | 51 | std::memcpy(¶ms, input.data(), input.size()); |
| 52 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 52 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 41b57e872..5623e0d47 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h | |||
| @@ -16,11 +16,11 @@ public: | |||
| 16 | ~nvhost_nvjpg() override; | 16 | ~nvhost_nvjpg() override; |
| 17 | 17 | ||
| 18 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 18 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 19 | std::vector<u8>& output) override; | 19 | std::span<u8> output) override; |
| 20 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 20 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 21 | std::span<const u8> inline_input, std::vector<u8>& output) override; | 21 | std::span<const u8> inline_input, std::span<u8> output) override; |
| 22 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, | 22 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, |
| 23 | std::vector<u8>& inline_output) override; | 23 | std::span<u8> inline_output) override; |
| 24 | 24 | ||
| 25 | void OnOpen(DeviceFD fd) override; | 25 | void OnOpen(DeviceFD fd) override; |
| 26 | void OnClose(DeviceFD fd) override; | 26 | void OnClose(DeviceFD fd) override; |
| @@ -33,7 +33,7 @@ private: | |||
| 33 | 33 | ||
| 34 | s32_le nvmap_fd{}; | 34 | s32_le nvmap_fd{}; |
| 35 | 35 | ||
| 36 | NvResult SetNVMAPfd(std::span<const u8> input, std::vector<u8>& output); | 36 | NvResult SetNVMAPfd(std::span<const u8> input, std::span<u8> output); |
| 37 | }; | 37 | }; |
| 38 | 38 | ||
| 39 | } // namespace Service::Nvidia::Devices | 39 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index b0ea402a7..c0b8684c3 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | |||
| @@ -16,7 +16,7 @@ nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core_) | |||
| 16 | nvhost_vic::~nvhost_vic() = default; | 16 | nvhost_vic::~nvhost_vic() = default; |
| 17 | 17 | ||
| 18 | NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 18 | NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 19 | std::vector<u8>& output) { | 19 | std::span<u8> output) { |
| 20 | switch (command.group) { | 20 | switch (command.group) { |
| 21 | case 0x0: | 21 | case 0x0: |
| 22 | switch (command.cmd) { | 22 | switch (command.cmd) { |
| @@ -56,13 +56,13 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu | |||
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | NvResult nvhost_vic::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 58 | NvResult nvhost_vic::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 59 | std::span<const u8> inline_input, std::vector<u8>& output) { | 59 | std::span<const u8> inline_input, std::span<u8> output) { |
| 60 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | 60 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 61 | return NvResult::NotImplemented; | 61 | return NvResult::NotImplemented; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, | 64 | NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 65 | std::vector<u8>& output, std::vector<u8>& inline_output) { | 65 | std::span<u8> output, std::span<u8> inline_output) { |
| 66 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | 66 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 67 | return NvResult::NotImplemented; | 67 | return NvResult::NotImplemented; |
| 68 | } | 68 | } |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index b5e350a83..cadbcb0a5 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h | |||
| @@ -13,11 +13,11 @@ public: | |||
| 13 | ~nvhost_vic(); | 13 | ~nvhost_vic(); |
| 14 | 14 | ||
| 15 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 15 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 16 | std::vector<u8>& output) override; | 16 | std::span<u8> output) override; |
| 17 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 17 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 18 | std::span<const u8> inline_input, std::vector<u8>& output) override; | 18 | std::span<const u8> inline_input, std::span<u8> output) override; |
| 19 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, | 19 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, |
| 20 | std::vector<u8>& inline_output) override; | 20 | std::span<u8> inline_output) override; |
| 21 | 21 | ||
| 22 | void OnOpen(DeviceFD fd) override; | 22 | void OnOpen(DeviceFD fd) override; |
| 23 | void OnClose(DeviceFD fd) override; | 23 | void OnClose(DeviceFD fd) override; |
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 07417f045..e7f7e273b 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp | |||
| @@ -26,7 +26,7 @@ nvmap::nvmap(Core::System& system_, NvCore::Container& container_) | |||
| 26 | nvmap::~nvmap() = default; | 26 | nvmap::~nvmap() = default; |
| 27 | 27 | ||
| 28 | NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 28 | NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 29 | std::vector<u8>& output) { | 29 | std::span<u8> output) { |
| 30 | switch (command.group) { | 30 | switch (command.group) { |
| 31 | case 0x1: | 31 | case 0x1: |
| 32 | switch (command.cmd) { | 32 | switch (command.cmd) { |
| @@ -55,13 +55,13 @@ NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | |||
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | NvResult nvmap::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 57 | NvResult nvmap::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 58 | std::span<const u8> inline_input, std::vector<u8>& output) { | 58 | std::span<const u8> inline_input, std::span<u8> output) { |
| 59 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | 59 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 60 | return NvResult::NotImplemented; | 60 | return NvResult::NotImplemented; |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, | 63 | NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, |
| 64 | std::vector<u8>& output, std::vector<u8>& inline_output) { | 64 | std::span<u8> inline_output) { |
| 65 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | 65 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 66 | return NvResult::NotImplemented; | 66 | return NvResult::NotImplemented; |
| 67 | } | 67 | } |
| @@ -69,7 +69,7 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, | |||
| 69 | void nvmap::OnOpen(DeviceFD fd) {} | 69 | void nvmap::OnOpen(DeviceFD fd) {} |
| 70 | void nvmap::OnClose(DeviceFD fd) {} | 70 | void nvmap::OnClose(DeviceFD fd) {} |
| 71 | 71 | ||
| 72 | NvResult nvmap::IocCreate(std::span<const u8> input, std::vector<u8>& output) { | 72 | NvResult nvmap::IocCreate(std::span<const u8> input, std::span<u8> output) { |
| 73 | IocCreateParams params; | 73 | IocCreateParams params; |
| 74 | std::memcpy(¶ms, input.data(), sizeof(params)); | 74 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 75 | LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size); | 75 | LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size); |
| @@ -89,7 +89,7 @@ NvResult nvmap::IocCreate(std::span<const u8> input, std::vector<u8>& output) { | |||
| 89 | return NvResult::Success; | 89 | return NvResult::Success; |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | NvResult nvmap::IocAlloc(std::span<const u8> input, std::vector<u8>& output) { | 92 | NvResult nvmap::IocAlloc(std::span<const u8> input, std::span<u8> output) { |
| 93 | IocAllocParams params; | 93 | IocAllocParams params; |
| 94 | std::memcpy(¶ms, input.data(), sizeof(params)); | 94 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 95 | LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address); | 95 | LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address); |
| @@ -137,7 +137,7 @@ NvResult nvmap::IocAlloc(std::span<const u8> input, std::vector<u8>& output) { | |||
| 137 | return result; | 137 | return result; |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | NvResult nvmap::IocGetId(std::span<const u8> input, std::vector<u8>& output) { | 140 | NvResult nvmap::IocGetId(std::span<const u8> input, std::span<u8> output) { |
| 141 | IocGetIdParams params; | 141 | IocGetIdParams params; |
| 142 | std::memcpy(¶ms, input.data(), sizeof(params)); | 142 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 143 | 143 | ||
| @@ -161,7 +161,7 @@ NvResult nvmap::IocGetId(std::span<const u8> input, std::vector<u8>& output) { | |||
| 161 | return NvResult::Success; | 161 | return NvResult::Success; |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | NvResult nvmap::IocFromId(std::span<const u8> input, std::vector<u8>& output) { | 164 | NvResult nvmap::IocFromId(std::span<const u8> input, std::span<u8> output) { |
| 165 | IocFromIdParams params; | 165 | IocFromIdParams params; |
| 166 | std::memcpy(¶ms, input.data(), sizeof(params)); | 166 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 167 | 167 | ||
| @@ -192,7 +192,7 @@ NvResult nvmap::IocFromId(std::span<const u8> input, std::vector<u8>& output) { | |||
| 192 | return NvResult::Success; | 192 | return NvResult::Success; |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | NvResult nvmap::IocParam(std::span<const u8> input, std::vector<u8>& output) { | 195 | NvResult nvmap::IocParam(std::span<const u8> input, std::span<u8> output) { |
| 196 | enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 }; | 196 | enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 }; |
| 197 | 197 | ||
| 198 | IocParamParams params; | 198 | IocParamParams params; |
| @@ -241,7 +241,7 @@ NvResult nvmap::IocParam(std::span<const u8> input, std::vector<u8>& output) { | |||
| 241 | return NvResult::Success; | 241 | return NvResult::Success; |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | NvResult nvmap::IocFree(std::span<const u8> input, std::vector<u8>& output) { | 244 | NvResult nvmap::IocFree(std::span<const u8> input, std::span<u8> output) { |
| 245 | IocFreeParams params; | 245 | IocFreeParams params; |
| 246 | std::memcpy(¶ms, input.data(), sizeof(params)); | 246 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 247 | 247 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 82bd3b118..40c65b430 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h | |||
| @@ -27,11 +27,11 @@ public: | |||
| 27 | nvmap& operator=(const nvmap&) = delete; | 27 | nvmap& operator=(const nvmap&) = delete; |
| 28 | 28 | ||
| 29 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 29 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 30 | std::vector<u8>& output) override; | 30 | std::span<u8> output) override; |
| 31 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 31 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 32 | std::span<const u8> inline_input, std::vector<u8>& output) override; | 32 | std::span<const u8> inline_input, std::span<u8> output) override; |
| 33 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, | 33 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, |
| 34 | std::vector<u8>& inline_output) override; | 34 | std::span<u8> inline_output) override; |
| 35 | 35 | ||
| 36 | void OnOpen(DeviceFD fd) override; | 36 | void OnOpen(DeviceFD fd) override; |
| 37 | void OnClose(DeviceFD fd) override; | 37 | void OnClose(DeviceFD fd) override; |
| @@ -106,12 +106,12 @@ private: | |||
| 106 | }; | 106 | }; |
| 107 | static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); | 107 | static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); |
| 108 | 108 | ||
| 109 | NvResult IocCreate(std::span<const u8> input, std::vector<u8>& output); | 109 | NvResult IocCreate(std::span<const u8> input, std::span<u8> output); |
| 110 | NvResult IocAlloc(std::span<const u8> input, std::vector<u8>& output); | 110 | NvResult IocAlloc(std::span<const u8> input, std::span<u8> output); |
| 111 | NvResult IocGetId(std::span<const u8> input, std::vector<u8>& output); | 111 | NvResult IocGetId(std::span<const u8> input, std::span<u8> output); |
| 112 | NvResult IocFromId(std::span<const u8> input, std::vector<u8>& output); | 112 | NvResult IocFromId(std::span<const u8> input, std::span<u8> output); |
| 113 | NvResult IocParam(std::span<const u8> input, std::vector<u8>& output); | 113 | NvResult IocParam(std::span<const u8> input, std::span<u8> output); |
| 114 | NvResult IocFree(std::span<const u8> input, std::vector<u8>& output); | 114 | NvResult IocFree(std::span<const u8> input, std::span<u8> output); |
| 115 | 115 | ||
| 116 | NvCore::Container& container; | 116 | NvCore::Container& container; |
| 117 | NvCore::NvMap& file; | 117 | NvCore::NvMap& file; |
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 3d774eec4..9e46ee8dd 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp | |||
| @@ -130,7 +130,7 @@ DeviceFD Module::Open(const std::string& device_name) { | |||
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | 132 | NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 133 | std::vector<u8>& output) { | 133 | std::span<u8> output) { |
| 134 | if (fd < 0) { | 134 | if (fd < 0) { |
| 135 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); | 135 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); |
| 136 | return NvResult::InvalidState; | 136 | return NvResult::InvalidState; |
| @@ -147,7 +147,7 @@ NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, | |||
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 149 | NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 150 | std::span<const u8> inline_input, std::vector<u8>& output) { | 150 | std::span<const u8> inline_input, std::span<u8> output) { |
| 151 | if (fd < 0) { | 151 | if (fd < 0) { |
| 152 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); | 152 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); |
| 153 | return NvResult::InvalidState; | 153 | return NvResult::InvalidState; |
| @@ -163,8 +163,8 @@ NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | |||
| 163 | return itr->second->Ioctl2(fd, command, input, inline_input, output); | 163 | return itr->second->Ioctl2(fd, command, input, inline_input, output); |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, | 166 | NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, |
| 167 | std::vector<u8>& output, std::vector<u8>& inline_output) { | 167 | std::span<u8> inline_output) { |
| 168 | if (fd < 0) { | 168 | if (fd < 0) { |
| 169 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); | 169 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); |
| 170 | return NvResult::InvalidState; | 170 | return NvResult::InvalidState; |
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 668be742b..d8622b3ca 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h | |||
| @@ -80,13 +80,13 @@ public: | |||
| 80 | DeviceFD Open(const std::string& device_name); | 80 | DeviceFD Open(const std::string& device_name); |
| 81 | 81 | ||
| 82 | /// Sends an ioctl command to the specified file descriptor. | 82 | /// Sends an ioctl command to the specified file descriptor. |
| 83 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output); | 83 | NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output); |
| 84 | 84 | ||
| 85 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, | 85 | NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, |
| 86 | std::span<const u8> inline_input, std::vector<u8>& output); | 86 | std::span<const u8> inline_input, std::span<u8> output); |
| 87 | 87 | ||
| 88 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::vector<u8>& output, | 88 | NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, |
| 89 | std::vector<u8>& inline_output); | 89 | std::span<u8> inline_output); |
| 90 | 90 | ||
| 91 | /// Closes a device file descriptor and returns operation success. | 91 | /// Closes a device file descriptor and returns operation success. |
| 92 | NvResult Close(DeviceFD fd); | 92 | NvResult Close(DeviceFD fd); |
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp index d010a1e03..348207e25 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp | |||
| @@ -63,12 +63,12 @@ void NVDRV::Ioctl1(HLERequestContext& ctx) { | |||
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | // Check device | 65 | // Check device |
| 66 | std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); | 66 | tmp_output.resize_destructive(ctx.GetWriteBufferSize(0)); |
| 67 | const auto input_buffer = ctx.ReadBuffer(0); | 67 | const auto input_buffer = ctx.ReadBuffer(0); |
| 68 | 68 | ||
| 69 | const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer); | 69 | const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, tmp_output); |
| 70 | if (command.is_out != 0) { | 70 | if (command.is_out != 0) { |
| 71 | ctx.WriteBuffer(output_buffer); | 71 | ctx.WriteBuffer(tmp_output); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | IPC::ResponseBuilder rb{ctx, 3}; | 74 | IPC::ResponseBuilder rb{ctx, 3}; |
| @@ -90,12 +90,12 @@ void NVDRV::Ioctl2(HLERequestContext& ctx) { | |||
| 90 | 90 | ||
| 91 | const auto input_buffer = ctx.ReadBuffer(0); | 91 | const auto input_buffer = ctx.ReadBuffer(0); |
| 92 | const auto input_inlined_buffer = ctx.ReadBuffer(1); | 92 | const auto input_inlined_buffer = ctx.ReadBuffer(1); |
| 93 | std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); | 93 | tmp_output.resize_destructive(ctx.GetWriteBufferSize(0)); |
| 94 | 94 | ||
| 95 | const auto nv_result = | 95 | const auto nv_result = |
| 96 | nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer); | 96 | nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, tmp_output); |
| 97 | if (command.is_out != 0) { | 97 | if (command.is_out != 0) { |
| 98 | ctx.WriteBuffer(output_buffer); | 98 | ctx.WriteBuffer(tmp_output); |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | IPC::ResponseBuilder rb{ctx, 3}; | 101 | IPC::ResponseBuilder rb{ctx, 3}; |
| @@ -116,14 +116,12 @@ void NVDRV::Ioctl3(HLERequestContext& ctx) { | |||
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | const auto input_buffer = ctx.ReadBuffer(0); | 118 | const auto input_buffer = ctx.ReadBuffer(0); |
| 119 | std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); | 119 | tmp_output.resize_destructive(ctx.GetWriteBufferSize(0)); |
| 120 | std::vector<u8> output_buffer_inline(ctx.GetWriteBufferSize(1)); | 120 | tmp_output_inline.resize_destructive(ctx.GetWriteBufferSize(1)); |
| 121 | 121 | const auto nv_result = nvdrv->Ioctl3(fd, command, input_buffer, tmp_output, tmp_output_inline); | |
| 122 | const auto nv_result = | ||
| 123 | nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline); | ||
| 124 | if (command.is_out != 0) { | 122 | if (command.is_out != 0) { |
| 125 | ctx.WriteBuffer(output_buffer, 0); | 123 | ctx.WriteBuffer(tmp_output, 0); |
| 126 | ctx.WriteBuffer(output_buffer_inline, 1); | 124 | ctx.WriteBuffer(tmp_output_inline, 1); |
| 127 | } | 125 | } |
| 128 | 126 | ||
| 129 | IPC::ResponseBuilder rb{ctx, 3}; | 127 | IPC::ResponseBuilder rb{ctx, 3}; |
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.h b/src/core/hle/service/nvdrv/nvdrv_interface.h index 881ea1a6b..4b593ff90 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.h +++ b/src/core/hle/service/nvdrv/nvdrv_interface.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include "common/scratch_buffer.h" | ||
| 7 | #include "core/hle/service/nvdrv/nvdrv.h" | 8 | #include "core/hle/service/nvdrv/nvdrv.h" |
| 8 | #include "core/hle/service/service.h" | 9 | #include "core/hle/service/service.h" |
| 9 | 10 | ||
| @@ -33,6 +34,8 @@ private: | |||
| 33 | 34 | ||
| 34 | u64 pid{}; | 35 | u64 pid{}; |
| 35 | bool is_initialized{}; | 36 | bool is_initialized{}; |
| 37 | Common::ScratchBuffer<u8> tmp_output; | ||
| 38 | Common::ScratchBuffer<u8> tmp_output_inline; | ||
| 36 | }; | 39 | }; |
| 37 | 40 | ||
| 38 | } // namespace Service::Nvidia | 41 | } // namespace Service::Nvidia |
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index da2d5890f..5f55cd31e 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp | |||
| @@ -43,14 +43,10 @@ void Nvnflinger::SplitVSync(std::stop_token stop_token) { | |||
| 43 | Common::SetCurrentThreadPriority(Common::ThreadPriority::High); | 43 | Common::SetCurrentThreadPriority(Common::ThreadPriority::High); |
| 44 | 44 | ||
| 45 | while (!stop_token.stop_requested()) { | 45 | while (!stop_token.stop_requested()) { |
| 46 | vsync_signal.wait(false); | 46 | vsync_signal.Wait(); |
| 47 | vsync_signal.store(false); | ||
| 48 | |||
| 49 | guard->lock(); | ||
| 50 | 47 | ||
| 48 | const auto lock_guard = Lock(); | ||
| 51 | Compose(); | 49 | Compose(); |
| 52 | |||
| 53 | guard->unlock(); | ||
| 54 | } | 50 | } |
| 55 | } | 51 | } |
| 56 | 52 | ||
| @@ -69,8 +65,8 @@ Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_ | |||
| 69 | "ScreenComposition", | 65 | "ScreenComposition", |
| 70 | [this](std::uintptr_t, s64 time, | 66 | [this](std::uintptr_t, s64 time, |
| 71 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { | 67 | std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { |
| 72 | vsync_signal.store(true); | 68 | { const auto lock_guard = Lock(); } |
| 73 | vsync_signal.notify_all(); | 69 | vsync_signal.Set(); |
| 74 | return std::chrono::nanoseconds(GetNextTicks()); | 70 | return std::chrono::nanoseconds(GetNextTicks()); |
| 75 | }); | 71 | }); |
| 76 | 72 | ||
| @@ -96,8 +92,7 @@ Nvnflinger::~Nvnflinger() { | |||
| 96 | if (system.IsMulticore()) { | 92 | if (system.IsMulticore()) { |
| 97 | system.CoreTiming().UnscheduleEvent(multi_composition_event, {}); | 93 | system.CoreTiming().UnscheduleEvent(multi_composition_event, {}); |
| 98 | vsync_thread.request_stop(); | 94 | vsync_thread.request_stop(); |
| 99 | vsync_signal.store(true); | 95 | vsync_signal.Set(); |
| 100 | vsync_signal.notify_all(); | ||
| 101 | } else { | 96 | } else { |
| 102 | system.CoreTiming().UnscheduleEvent(single_composition_event, {}); | 97 | system.CoreTiming().UnscheduleEvent(single_composition_event, {}); |
| 103 | } | 98 | } |
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h index a043cceb2..ef236303a 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.h +++ b/src/core/hle/service/nvnflinger/nvnflinger.h | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | 12 | ||
| 13 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "common/polyfill_thread.h" | 14 | #include "common/polyfill_thread.h" |
| 15 | #include "common/thread.h" | ||
| 15 | #include "core/hle/result.h" | 16 | #include "core/hle/result.h" |
| 16 | #include "core/hle/service/kernel_helpers.h" | 17 | #include "core/hle/service/kernel_helpers.h" |
| 17 | 18 | ||
| @@ -143,7 +144,7 @@ private: | |||
| 143 | 144 | ||
| 144 | Core::System& system; | 145 | Core::System& system; |
| 145 | 146 | ||
| 146 | std::atomic<bool> vsync_signal; | 147 | Common::Event vsync_signal; |
| 147 | 148 | ||
| 148 | std::jthread vsync_thread; | 149 | std::jthread vsync_thread; |
| 149 | 150 | ||
diff --git a/src/core/hle/service/nvnflinger/parcel.h b/src/core/hle/service/nvnflinger/parcel.h index fb56d75d7..23ba315a0 100644 --- a/src/core/hle/service/nvnflinger/parcel.h +++ b/src/core/hle/service/nvnflinger/parcel.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include <span> | 7 | #include <span> |
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | #include <boost/container/small_vector.hpp> | ||
| 9 | 10 | ||
| 10 | #include "common/alignment.h" | 11 | #include "common/alignment.h" |
| 11 | #include "common/assert.h" | 12 | #include "common/assert.h" |
| @@ -167,7 +168,7 @@ public: | |||
| 167 | private: | 168 | private: |
| 168 | template <typename T> | 169 | template <typename T> |
| 169 | requires(std::is_trivially_copyable_v<T>) | 170 | requires(std::is_trivially_copyable_v<T>) |
| 170 | void WriteImpl(const T& val, std::vector<u8>& buffer) { | 171 | void WriteImpl(const T& val, boost::container::small_vector<u8, 0x200>& buffer) { |
| 171 | const size_t aligned_size = Common::AlignUp(sizeof(T), 4); | 172 | const size_t aligned_size = Common::AlignUp(sizeof(T), 4); |
| 172 | const size_t old_size = buffer.size(); | 173 | const size_t old_size = buffer.size(); |
| 173 | buffer.resize(old_size + aligned_size); | 174 | buffer.resize(old_size + aligned_size); |
| @@ -176,8 +177,8 @@ private: | |||
| 176 | } | 177 | } |
| 177 | 178 | ||
| 178 | private: | 179 | private: |
| 179 | std::vector<u8> m_data_buffer; | 180 | boost::container::small_vector<u8, 0x200> m_data_buffer; |
| 180 | std::vector<u8> m_object_buffer; | 181 | boost::container::small_vector<u8, 0x200> m_object_buffer; |
| 181 | }; | 182 | }; |
| 182 | 183 | ||
| 183 | } // namespace Service::android | 184 | } // namespace Service::android |
diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp index 156bc27d8..d1e99b184 100644 --- a/src/core/hle/service/server_manager.cpp +++ b/src/core/hle/service/server_manager.cpp | |||
| @@ -44,7 +44,7 @@ ServerManager::~ServerManager() { | |||
| 44 | m_event->Signal(); | 44 | m_event->Signal(); |
| 45 | 45 | ||
| 46 | // Wait for processing to stop. | 46 | // Wait for processing to stop. |
| 47 | m_stopped.wait(false); | 47 | m_stopped.Wait(); |
| 48 | m_threads.clear(); | 48 | m_threads.clear(); |
| 49 | 49 | ||
| 50 | // Clean up ports. | 50 | // Clean up ports. |
| @@ -182,10 +182,7 @@ void ServerManager::StartAdditionalHostThreads(const char* name, size_t num_thre | |||
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | Result ServerManager::LoopProcess() { | 184 | Result ServerManager::LoopProcess() { |
| 185 | SCOPE_EXIT({ | 185 | SCOPE_EXIT({ m_stopped.Set(); }); |
| 186 | m_stopped.store(true); | ||
| 187 | m_stopped.notify_all(); | ||
| 188 | }); | ||
| 189 | 186 | ||
| 190 | R_RETURN(this->LoopProcessImpl()); | 187 | R_RETURN(this->LoopProcessImpl()); |
| 191 | } | 188 | } |
diff --git a/src/core/hle/service/server_manager.h b/src/core/hle/service/server_manager.h index fdb8af2ff..58b0a0832 100644 --- a/src/core/hle/service/server_manager.h +++ b/src/core/hle/service/server_manager.h | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <atomic> | ||
| 7 | #include <functional> | 6 | #include <functional> |
| 8 | #include <list> | 7 | #include <list> |
| 9 | #include <map> | 8 | #include <map> |
| @@ -12,6 +11,7 @@ | |||
| 12 | #include <vector> | 11 | #include <vector> |
| 13 | 12 | ||
| 14 | #include "common/polyfill_thread.h" | 13 | #include "common/polyfill_thread.h" |
| 14 | #include "common/thread.h" | ||
| 15 | #include "core/hle/result.h" | 15 | #include "core/hle/result.h" |
| 16 | #include "core/hle/service/mutex.h" | 16 | #include "core/hle/service/mutex.h" |
| 17 | 17 | ||
| @@ -82,7 +82,7 @@ private: | |||
| 82 | std::list<RequestState> m_deferrals{}; | 82 | std::list<RequestState> m_deferrals{}; |
| 83 | 83 | ||
| 84 | // Host state tracking | 84 | // Host state tracking |
| 85 | std::atomic<bool> m_stopped{}; | 85 | Common::Event m_stopped{}; |
| 86 | std::vector<std::jthread> m_threads{}; | 86 | std::vector<std::jthread> m_threads{}; |
| 87 | std::stop_source m_stop_source{}; | 87 | std::stop_source m_stop_source{}; |
| 88 | }; | 88 | }; |
diff --git a/src/core/hle/service/time/clock_types.h b/src/core/hle/service/time/clock_types.h index e6293ffb9..9fc01ea90 100644 --- a/src/core/hle/service/time/clock_types.h +++ b/src/core/hle/service/time/clock_types.h | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <ratio> | ||
| 7 | |||
| 6 | #include "common/common_funcs.h" | 8 | #include "common/common_funcs.h" |
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 8 | #include "common/uuid.h" | 10 | #include "common/uuid.h" |
| @@ -74,18 +76,19 @@ static_assert(std::is_trivially_copyable_v<ContinuousAdjustmentTimePoint>, | |||
| 74 | /// https://switchbrew.org/wiki/Glue_services#TimeSpanType | 76 | /// https://switchbrew.org/wiki/Glue_services#TimeSpanType |
| 75 | struct TimeSpanType { | 77 | struct TimeSpanType { |
| 76 | s64 nanoseconds{}; | 78 | s64 nanoseconds{}; |
| 77 | static constexpr s64 ns_per_second{1000000000ULL}; | ||
| 78 | 79 | ||
| 79 | s64 ToSeconds() const { | 80 | s64 ToSeconds() const { |
| 80 | return nanoseconds / ns_per_second; | 81 | return nanoseconds / std::nano::den; |
| 81 | } | 82 | } |
| 82 | 83 | ||
| 83 | static TimeSpanType FromSeconds(s64 seconds) { | 84 | static TimeSpanType FromSeconds(s64 seconds) { |
| 84 | return {seconds * ns_per_second}; | 85 | return {seconds * std::nano::den}; |
| 85 | } | 86 | } |
| 86 | 87 | ||
| 87 | static TimeSpanType FromTicks(u64 ticks, u64 frequency) { | 88 | template <u64 Frequency> |
| 88 | return FromSeconds(static_cast<s64>(ticks) / static_cast<s64>(frequency)); | 89 | static TimeSpanType FromTicks(u64 ticks) { |
| 90 | using TicksToNSRatio = std::ratio<std::nano::den, Frequency>; | ||
| 91 | return {static_cast<s64>(ticks * TicksToNSRatio::num / TicksToNSRatio::den)}; | ||
| 89 | } | 92 | } |
| 90 | }; | 93 | }; |
| 91 | static_assert(sizeof(TimeSpanType) == 8, "TimeSpanType is incorrect size"); | 94 | static_assert(sizeof(TimeSpanType) == 8, "TimeSpanType is incorrect size"); |
diff --git a/src/core/hle/service/time/standard_steady_clock_core.cpp b/src/core/hle/service/time/standard_steady_clock_core.cpp index 3dbbb9850..5627b7003 100644 --- a/src/core/hle/service/time/standard_steady_clock_core.cpp +++ b/src/core/hle/service/time/standard_steady_clock_core.cpp | |||
| @@ -10,7 +10,7 @@ namespace Service::Time::Clock { | |||
| 10 | 10 | ||
| 11 | TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) { | 11 | TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) { |
| 12 | const TimeSpanType ticks_time_span{ | 12 | const TimeSpanType ticks_time_span{ |
| 13 | TimeSpanType::FromTicks(system.CoreTiming().GetClockTicks(), Core::Hardware::CNTFREQ)}; | 13 | TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(system.CoreTiming().GetClockTicks())}; |
| 14 | TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds}; | 14 | TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds}; |
| 15 | 15 | ||
| 16 | if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) { | 16 | if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) { |
diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.cpp b/src/core/hle/service/time/tick_based_steady_clock_core.cpp index 27600413e..0d9fb3143 100644 --- a/src/core/hle/service/time/tick_based_steady_clock_core.cpp +++ b/src/core/hle/service/time/tick_based_steady_clock_core.cpp | |||
| @@ -10,7 +10,7 @@ namespace Service::Time::Clock { | |||
| 10 | 10 | ||
| 11 | SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) { | 11 | SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) { |
| 12 | const TimeSpanType ticks_time_span{ | 12 | const TimeSpanType ticks_time_span{ |
| 13 | TimeSpanType::FromTicks(system.CoreTiming().GetClockTicks(), Core::Hardware::CNTFREQ)}; | 13 | TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(system.CoreTiming().GetClockTicks())}; |
| 14 | 14 | ||
| 15 | return {ticks_time_span.ToSeconds(), GetClockSourceId()}; | 15 | return {ticks_time_span.ToSeconds(), GetClockSourceId()}; |
| 16 | } | 16 | } |
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 868be60c5..7197ca30f 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp | |||
| @@ -240,8 +240,8 @@ void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(HLERequestCon | |||
| 240 | const auto current_time_point{steady_clock_core.GetCurrentTimePoint(system)}; | 240 | const auto current_time_point{steady_clock_core.GetCurrentTimePoint(system)}; |
| 241 | 241 | ||
| 242 | if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) { | 242 | if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) { |
| 243 | const auto ticks{Clock::TimeSpanType::FromTicks(system.CoreTiming().GetClockTicks(), | 243 | const auto ticks{Clock::TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>( |
| 244 | Core::Hardware::CNTFREQ)}; | 244 | system.CoreTiming().GetClockTicks())}; |
| 245 | const s64 base_time_point{context.offset + current_time_point.time_point - | 245 | const s64 base_time_point{context.offset + current_time_point.time_point - |
| 246 | ticks.ToSeconds()}; | 246 | ticks.ToSeconds()}; |
| 247 | IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2}; | 247 | IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2}; |
diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp index ce1c85bcc..a00676669 100644 --- a/src/core/hle/service/time/time_sharedmemory.cpp +++ b/src/core/hle/service/time/time_sharedmemory.cpp | |||
| @@ -21,8 +21,9 @@ SharedMemory::~SharedMemory() = default; | |||
| 21 | 21 | ||
| 22 | void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id, | 22 | void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id, |
| 23 | Clock::TimeSpanType current_time_point) { | 23 | Clock::TimeSpanType current_time_point) { |
| 24 | const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks( | 24 | const Clock::TimeSpanType ticks_time_span{ |
| 25 | system.CoreTiming().GetClockTicks(), Core::Hardware::CNTFREQ)}; | 25 | Clock::TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>( |
| 26 | system.CoreTiming().GetClockTicks())}; | ||
| 26 | const Clock::SteadyClockContext context{ | 27 | const Clock::SteadyClockContext context{ |
| 27 | static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds), | 28 | static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds), |
| 28 | clock_source_id}; | 29 | clock_source_id}; |
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index 63aacd19f..205371a26 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp | |||
| @@ -911,9 +911,13 @@ static Result ToCalendarTimeInternal(const TimeZoneRule& rules, s64 time, | |||
| 911 | 911 | ||
| 912 | calendar_additional_info.is_dst = rules.ttis[tti_index].is_dst; | 912 | calendar_additional_info.is_dst = rules.ttis[tti_index].is_dst; |
| 913 | const char* time_zone{&rules.chars[rules.ttis[tti_index].abbreviation_list_index]}; | 913 | const char* time_zone{&rules.chars[rules.ttis[tti_index].abbreviation_list_index]}; |
| 914 | for (int index{}; time_zone[index] != '\0'; ++index) { | 914 | u32 index; |
| 915 | for (index = 0; time_zone[index] != '\0' && time_zone[index] != ',' && | ||
| 916 | index < calendar_additional_info.timezone_name.size() - 1; | ||
| 917 | ++index) { | ||
| 915 | calendar_additional_info.timezone_name[index] = time_zone[index]; | 918 | calendar_additional_info.timezone_name[index] = time_zone[index]; |
| 916 | } | 919 | } |
| 920 | calendar_additional_info.timezone_name[index] = '\0'; | ||
| 917 | return ResultSuccess; | 921 | return ResultSuccess; |
| 918 | } | 922 | } |
| 919 | 923 | ||
diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index b2b5677c8..0aca5a3a3 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp | |||
| @@ -102,12 +102,12 @@ bool Joycons::IsDeviceNew(SDL_hid_device_info* device_info) const { | |||
| 102 | Joycon::SerialNumber serial_number{}; | 102 | Joycon::SerialNumber serial_number{}; |
| 103 | 103 | ||
| 104 | const auto result = Joycon::JoyconDriver::GetDeviceType(device_info, type); | 104 | const auto result = Joycon::JoyconDriver::GetDeviceType(device_info, type); |
| 105 | if (result != Joycon::DriverResult::Success) { | 105 | if (result != Common::Input::DriverResult::Success) { |
| 106 | return false; | 106 | return false; |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | const auto result2 = Joycon::JoyconDriver::GetSerialNumber(device_info, serial_number); | 109 | const auto result2 = Joycon::JoyconDriver::GetSerialNumber(device_info, serial_number); |
| 110 | if (result2 != Joycon::DriverResult::Success) { | 110 | if (result2 != Common::Input::DriverResult::Success) { |
| 111 | return false; | 111 | return false; |
| 112 | } | 112 | } |
| 113 | 113 | ||
| @@ -171,10 +171,10 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) { | |||
| 171 | LOG_WARNING(Input, "No free handles available"); | 171 | LOG_WARNING(Input, "No free handles available"); |
| 172 | return; | 172 | return; |
| 173 | } | 173 | } |
| 174 | if (result == Joycon::DriverResult::Success) { | 174 | if (result == Common::Input::DriverResult::Success) { |
| 175 | result = handle->RequestDeviceAccess(device_info); | 175 | result = handle->RequestDeviceAccess(device_info); |
| 176 | } | 176 | } |
| 177 | if (result == Joycon::DriverResult::Success) { | 177 | if (result == Common::Input::DriverResult::Success) { |
| 178 | LOG_WARNING(Input, "Initialize device"); | 178 | LOG_WARNING(Input, "Initialize device"); |
| 179 | 179 | ||
| 180 | const std::size_t port = handle->GetDevicePort(); | 180 | const std::size_t port = handle->GetDevicePort(); |
| @@ -195,8 +195,8 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) { | |||
| 195 | OnMotionUpdate(port, type, id, value); | 195 | OnMotionUpdate(port, type, id, value); |
| 196 | }}, | 196 | }}, |
| 197 | .on_ring_data = {[this](f32 ring_data) { OnRingConUpdate(ring_data); }}, | 197 | .on_ring_data = {[this](f32 ring_data) { OnRingConUpdate(ring_data); }}, |
| 198 | .on_amiibo_data = {[this, port, type](const std::vector<u8>& amiibo_data) { | 198 | .on_amiibo_data = {[this, port, type](const Joycon::TagInfo& tag_info) { |
| 199 | OnAmiiboUpdate(port, type, amiibo_data); | 199 | OnAmiiboUpdate(port, type, tag_info); |
| 200 | }}, | 200 | }}, |
| 201 | .on_camera_data = {[this, port](const std::vector<u8>& camera_data, | 201 | .on_camera_data = {[this, port](const std::vector<u8>& camera_data, |
| 202 | Joycon::IrsResolution format) { | 202 | Joycon::IrsResolution format) { |
| @@ -273,8 +273,7 @@ Common::Input::DriverResult Joycons::SetLeds(const PadIdentifier& identifier, | |||
| 273 | led_config += led_status.led_3 ? 4 : 0; | 273 | led_config += led_status.led_3 ? 4 : 0; |
| 274 | led_config += led_status.led_4 ? 8 : 0; | 274 | led_config += led_status.led_4 ? 8 : 0; |
| 275 | 275 | ||
| 276 | return static_cast<Common::Input::DriverResult>( | 276 | return handle->SetLedConfig(static_cast<u8>(led_config)); |
| 277 | handle->SetLedConfig(static_cast<u8>(led_config))); | ||
| 278 | } | 277 | } |
| 279 | 278 | ||
| 280 | Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier, | 279 | Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier, |
| @@ -283,21 +282,113 @@ Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identi | |||
| 283 | if (handle == nullptr) { | 282 | if (handle == nullptr) { |
| 284 | return Common::Input::DriverResult::InvalidHandle; | 283 | return Common::Input::DriverResult::InvalidHandle; |
| 285 | } | 284 | } |
| 286 | return static_cast<Common::Input::DriverResult>(handle->SetIrsConfig( | 285 | return handle->SetIrsConfig(Joycon::IrsMode::ImageTransfer, |
| 287 | Joycon::IrsMode::ImageTransfer, static_cast<Joycon::IrsResolution>(camera_format))); | 286 | static_cast<Joycon::IrsResolution>(camera_format)); |
| 288 | }; | 287 | }; |
| 289 | 288 | ||
| 290 | Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) const { | 289 | Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) const { |
| 291 | return Common::Input::NfcState::Success; | 290 | return Common::Input::NfcState::Success; |
| 292 | }; | 291 | }; |
| 293 | 292 | ||
| 293 | Common::Input::NfcState Joycons::StartNfcPolling(const PadIdentifier& identifier) { | ||
| 294 | auto handle = GetHandle(identifier); | ||
| 295 | if (handle == nullptr) { | ||
| 296 | return Common::Input::NfcState::Unknown; | ||
| 297 | } | ||
| 298 | return TranslateDriverResult(handle->StartNfcPolling()); | ||
| 299 | }; | ||
| 300 | |||
| 301 | Common::Input::NfcState Joycons::StopNfcPolling(const PadIdentifier& identifier) { | ||
| 302 | auto handle = GetHandle(identifier); | ||
| 303 | if (handle == nullptr) { | ||
| 304 | return Common::Input::NfcState::Unknown; | ||
| 305 | } | ||
| 306 | return TranslateDriverResult(handle->StopNfcPolling()); | ||
| 307 | }; | ||
| 308 | |||
| 309 | Common::Input::NfcState Joycons::ReadAmiiboData(const PadIdentifier& identifier, | ||
| 310 | std::vector<u8>& out_data) { | ||
| 311 | auto handle = GetHandle(identifier); | ||
| 312 | if (handle == nullptr) { | ||
| 313 | return Common::Input::NfcState::Unknown; | ||
| 314 | } | ||
| 315 | return TranslateDriverResult(handle->ReadAmiiboData(out_data)); | ||
| 316 | } | ||
| 317 | |||
| 294 | Common::Input::NfcState Joycons::WriteNfcData(const PadIdentifier& identifier, | 318 | Common::Input::NfcState Joycons::WriteNfcData(const PadIdentifier& identifier, |
| 295 | const std::vector<u8>& data) { | 319 | const std::vector<u8>& data) { |
| 296 | auto handle = GetHandle(identifier); | 320 | auto handle = GetHandle(identifier); |
| 297 | if (handle->WriteNfcData(data) != Joycon::DriverResult::Success) { | 321 | if (handle == nullptr) { |
| 298 | return Common::Input::NfcState::WriteFailed; | 322 | return Common::Input::NfcState::Unknown; |
| 299 | } | 323 | } |
| 300 | return Common::Input::NfcState::Success; | 324 | return TranslateDriverResult(handle->WriteNfcData(data)); |
| 325 | }; | ||
| 326 | |||
| 327 | Common::Input::NfcState Joycons::ReadMifareData(const PadIdentifier& identifier, | ||
| 328 | const Common::Input::MifareRequest& request, | ||
| 329 | Common::Input::MifareRequest& data) { | ||
| 330 | auto handle = GetHandle(identifier); | ||
| 331 | if (handle == nullptr) { | ||
| 332 | return Common::Input::NfcState::Unknown; | ||
| 333 | } | ||
| 334 | |||
| 335 | const auto command = static_cast<Joycon::MifareCmd>(request.data[0].command); | ||
| 336 | std::vector<Joycon::MifareReadChunk> read_request{}; | ||
| 337 | for (const auto& request_data : request.data) { | ||
| 338 | if (request_data.command == 0) { | ||
| 339 | continue; | ||
| 340 | } | ||
| 341 | Joycon::MifareReadChunk chunk = { | ||
| 342 | .command = command, | ||
| 343 | .sector_key = {}, | ||
| 344 | .sector = request_data.sector, | ||
| 345 | }; | ||
| 346 | memcpy(chunk.sector_key.data(), request_data.key.data(), | ||
| 347 | sizeof(Joycon::MifareReadChunk::sector_key)); | ||
| 348 | read_request.emplace_back(chunk); | ||
| 349 | } | ||
| 350 | |||
| 351 | std::vector<Joycon::MifareReadData> read_data(read_request.size()); | ||
| 352 | const auto result = handle->ReadMifareData(read_request, read_data); | ||
| 353 | if (result == Common::Input::DriverResult::Success) { | ||
| 354 | for (std::size_t i = 0; i < read_request.size(); i++) { | ||
| 355 | data.data[i] = { | ||
| 356 | .command = static_cast<u8>(command), | ||
| 357 | .sector = read_data[i].sector, | ||
| 358 | .key = {}, | ||
| 359 | .data = read_data[i].data, | ||
| 360 | }; | ||
| 361 | } | ||
| 362 | } | ||
| 363 | return TranslateDriverResult(result); | ||
| 364 | }; | ||
| 365 | |||
| 366 | Common::Input::NfcState Joycons::WriteMifareData(const PadIdentifier& identifier, | ||
| 367 | const Common::Input::MifareRequest& request) { | ||
| 368 | auto handle = GetHandle(identifier); | ||
| 369 | if (handle == nullptr) { | ||
| 370 | return Common::Input::NfcState::Unknown; | ||
| 371 | } | ||
| 372 | |||
| 373 | const auto command = static_cast<Joycon::MifareCmd>(request.data[0].command); | ||
| 374 | std::vector<Joycon::MifareWriteChunk> write_request{}; | ||
| 375 | for (const auto& request_data : request.data) { | ||
| 376 | if (request_data.command == 0) { | ||
| 377 | continue; | ||
| 378 | } | ||
| 379 | Joycon::MifareWriteChunk chunk = { | ||
| 380 | .command = command, | ||
| 381 | .sector_key = {}, | ||
| 382 | .sector = request_data.sector, | ||
| 383 | .data = {}, | ||
| 384 | }; | ||
| 385 | memcpy(chunk.sector_key.data(), request_data.key.data(), | ||
| 386 | sizeof(Joycon::MifareReadChunk::sector_key)); | ||
| 387 | memcpy(chunk.data.data(), request_data.data.data(), sizeof(Joycon::MifareWriteChunk::data)); | ||
| 388 | write_request.emplace_back(chunk); | ||
| 389 | } | ||
| 390 | |||
| 391 | return TranslateDriverResult(handle->WriteMifareData(write_request)); | ||
| 301 | }; | 392 | }; |
| 302 | 393 | ||
| 303 | Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identifier, | 394 | Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identifier, |
| @@ -310,15 +401,15 @@ Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identif | |||
| 310 | 401 | ||
| 311 | switch (polling_mode) { | 402 | switch (polling_mode) { |
| 312 | case Common::Input::PollingMode::Active: | 403 | case Common::Input::PollingMode::Active: |
| 313 | return static_cast<Common::Input::DriverResult>(handle->SetActiveMode()); | 404 | return handle->SetActiveMode(); |
| 314 | case Common::Input::PollingMode::Passive: | 405 | case Common::Input::PollingMode::Passive: |
| 315 | return static_cast<Common::Input::DriverResult>(handle->SetPassiveMode()); | 406 | return handle->SetPassiveMode(); |
| 316 | case Common::Input::PollingMode::IR: | 407 | case Common::Input::PollingMode::IR: |
| 317 | return static_cast<Common::Input::DriverResult>(handle->SetIrMode()); | 408 | return handle->SetIrMode(); |
| 318 | case Common::Input::PollingMode::NFC: | 409 | case Common::Input::PollingMode::NFC: |
| 319 | return static_cast<Common::Input::DriverResult>(handle->SetNfcMode()); | 410 | return handle->SetNfcMode(); |
| 320 | case Common::Input::PollingMode::Ring: | 411 | case Common::Input::PollingMode::Ring: |
| 321 | return static_cast<Common::Input::DriverResult>(handle->SetRingConMode()); | 412 | return handle->SetRingConMode(); |
| 322 | default: | 413 | default: |
| 323 | return Common::Input::DriverResult::NotSupported; | 414 | return Common::Input::DriverResult::NotSupported; |
| 324 | } | 415 | } |
| @@ -403,11 +494,20 @@ void Joycons::OnRingConUpdate(f32 ring_data) { | |||
| 403 | } | 494 | } |
| 404 | 495 | ||
| 405 | void Joycons::OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, | 496 | void Joycons::OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, |
| 406 | const std::vector<u8>& amiibo_data) { | 497 | const Joycon::TagInfo& tag_info) { |
| 407 | const auto identifier = GetIdentifier(port, type); | 498 | const auto identifier = GetIdentifier(port, type); |
| 408 | const auto nfc_state = amiibo_data.empty() ? Common::Input::NfcState::AmiiboRemoved | 499 | const auto nfc_state = tag_info.uuid_length == 0 ? Common::Input::NfcState::AmiiboRemoved |
| 409 | : Common::Input::NfcState::NewAmiibo; | 500 | : Common::Input::NfcState::NewAmiibo; |
| 410 | SetNfc(identifier, {nfc_state, amiibo_data}); | 501 | |
| 502 | const Common::Input::NfcStatus nfc_status{ | ||
| 503 | .state = nfc_state, | ||
| 504 | .uuid_length = tag_info.uuid_length, | ||
| 505 | .protocol = tag_info.protocol, | ||
| 506 | .tag_type = tag_info.tag_type, | ||
| 507 | .uuid = tag_info.uuid, | ||
| 508 | }; | ||
| 509 | |||
| 510 | SetNfc(identifier, nfc_status); | ||
| 411 | } | 511 | } |
| 412 | 512 | ||
| 413 | void Joycons::OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, | 513 | void Joycons::OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, |
| @@ -726,4 +826,18 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const { | |||
| 726 | return "Unknown Switch Controller"; | 826 | return "Unknown Switch Controller"; |
| 727 | } | 827 | } |
| 728 | } | 828 | } |
| 829 | |||
| 830 | Common::Input::NfcState Joycons::TranslateDriverResult(Common::Input::DriverResult result) const { | ||
| 831 | switch (result) { | ||
| 832 | case Common::Input::DriverResult::Success: | ||
| 833 | return Common::Input::NfcState::Success; | ||
| 834 | case Common::Input::DriverResult::Disabled: | ||
| 835 | return Common::Input::NfcState::WrongDeviceState; | ||
| 836 | case Common::Input::DriverResult::NotSupported: | ||
| 837 | return Common::Input::NfcState::NotSupported; | ||
| 838 | default: | ||
| 839 | return Common::Input::NfcState::Unknown; | ||
| 840 | } | ||
| 841 | } | ||
| 842 | |||
| 729 | } // namespace InputCommon | 843 | } // namespace InputCommon |
diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h index e3f0ad78f..112e970e1 100644 --- a/src/input_common/drivers/joycon.h +++ b/src/input_common/drivers/joycon.h | |||
| @@ -15,8 +15,8 @@ using SerialNumber = std::array<u8, 15>; | |||
| 15 | struct Battery; | 15 | struct Battery; |
| 16 | struct Color; | 16 | struct Color; |
| 17 | struct MotionData; | 17 | struct MotionData; |
| 18 | struct TagInfo; | ||
| 18 | enum class ControllerType : u8; | 19 | enum class ControllerType : u8; |
| 19 | enum class DriverResult; | ||
| 20 | enum class IrsResolution; | 20 | enum class IrsResolution; |
| 21 | class JoyconDriver; | 21 | class JoyconDriver; |
| 22 | } // namespace InputCommon::Joycon | 22 | } // namespace InputCommon::Joycon |
| @@ -39,9 +39,18 @@ public: | |||
| 39 | Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier, | 39 | Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier, |
| 40 | Common::Input::CameraFormat camera_format) override; | 40 | Common::Input::CameraFormat camera_format) override; |
| 41 | 41 | ||
| 42 | Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; | 42 | Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier) const override; |
| 43 | Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_, | 43 | Common::Input::NfcState StartNfcPolling(const PadIdentifier& identifier) override; |
| 44 | Common::Input::NfcState StopNfcPolling(const PadIdentifier& identifier) override; | ||
| 45 | Common::Input::NfcState ReadAmiiboData(const PadIdentifier& identifier, | ||
| 46 | std::vector<u8>& out_data) override; | ||
| 47 | Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier, | ||
| 44 | const std::vector<u8>& data) override; | 48 | const std::vector<u8>& data) override; |
| 49 | Common::Input::NfcState ReadMifareData(const PadIdentifier& identifier, | ||
| 50 | const Common::Input::MifareRequest& request, | ||
| 51 | Common::Input::MifareRequest& out_data) override; | ||
| 52 | Common::Input::NfcState WriteMifareData(const PadIdentifier& identifier, | ||
| 53 | const Common::Input::MifareRequest& request) override; | ||
| 45 | 54 | ||
| 46 | Common::Input::DriverResult SetPollingMode( | 55 | Common::Input::DriverResult SetPollingMode( |
| 47 | const PadIdentifier& identifier, const Common::Input::PollingMode polling_mode) override; | 56 | const PadIdentifier& identifier, const Common::Input::PollingMode polling_mode) override; |
| @@ -82,7 +91,7 @@ private: | |||
| 82 | const Joycon::MotionData& value); | 91 | const Joycon::MotionData& value); |
| 83 | void OnRingConUpdate(f32 ring_data); | 92 | void OnRingConUpdate(f32 ring_data); |
| 84 | void OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, | 93 | void OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, |
| 85 | const std::vector<u8>& amiibo_data); | 94 | const Joycon::TagInfo& amiibo_data); |
| 86 | void OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, | 95 | void OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, |
| 87 | Joycon::IrsResolution format); | 96 | Joycon::IrsResolution format); |
| 88 | 97 | ||
| @@ -102,6 +111,8 @@ private: | |||
| 102 | /// Returns the name of the device in text format | 111 | /// Returns the name of the device in text format |
| 103 | std::string JoyconName(Joycon::ControllerType type) const; | 112 | std::string JoyconName(Joycon::ControllerType type) const; |
| 104 | 113 | ||
| 114 | Common::Input::NfcState TranslateDriverResult(Common::Input::DriverResult result) const; | ||
| 115 | |||
| 105 | std::jthread scan_thread; | 116 | std::jthread scan_thread; |
| 106 | 117 | ||
| 107 | // Joycon types are split by type to ease supporting dualjoycon configurations | 118 | // Joycon types are split by type to ease supporting dualjoycon configurations |
diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 0c9f642bb..f07cf8a0e 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp | |||
| @@ -76,9 +76,6 @@ void Mouse::UpdateThread(std::stop_token stop_token) { | |||
| 76 | UpdateStickInput(); | 76 | UpdateStickInput(); |
| 77 | UpdateMotionInput(); | 77 | UpdateMotionInput(); |
| 78 | 78 | ||
| 79 | if (mouse_panning_timeout++ > 20) { | ||
| 80 | StopPanning(); | ||
| 81 | } | ||
| 82 | std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); | 79 | std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); |
| 83 | } | 80 | } |
| 84 | } | 81 | } |
| @@ -88,18 +85,45 @@ void Mouse::UpdateStickInput() { | |||
| 88 | return; | 85 | return; |
| 89 | } | 86 | } |
| 90 | 87 | ||
| 91 | const float sensitivity = | 88 | const float length = last_mouse_change.Length(); |
| 92 | Settings::values.mouse_panning_sensitivity.GetValue() * default_stick_sensitivity; | ||
| 93 | 89 | ||
| 94 | // Slow movement by 4% | 90 | // Prevent input from exceeding the max range (1.0f) too much, |
| 95 | last_mouse_change *= 0.96f; | 91 | // but allow some room to make it easier to sustain |
| 96 | SetAxis(identifier, mouse_axis_x, last_mouse_change.x * sensitivity); | 92 | if (length > 1.2f) { |
| 97 | SetAxis(identifier, mouse_axis_y, -last_mouse_change.y * sensitivity); | 93 | last_mouse_change /= length; |
| 94 | last_mouse_change *= 1.2f; | ||
| 95 | } | ||
| 96 | |||
| 97 | auto mouse_change = last_mouse_change; | ||
| 98 | |||
| 99 | // Bind the mouse change to [0 <= deadzone_counterweight <= 1,1] | ||
| 100 | if (length < 1.0f) { | ||
| 101 | const float deadzone_h_counterweight = | ||
| 102 | Settings::values.mouse_panning_deadzone_x_counterweight.GetValue(); | ||
| 103 | const float deadzone_v_counterweight = | ||
| 104 | Settings::values.mouse_panning_deadzone_y_counterweight.GetValue(); | ||
| 105 | mouse_change /= length; | ||
| 106 | mouse_change.x *= length + (1 - length) * deadzone_h_counterweight * 0.01f; | ||
| 107 | mouse_change.y *= length + (1 - length) * deadzone_v_counterweight * 0.01f; | ||
| 108 | } | ||
| 109 | |||
| 110 | SetAxis(identifier, mouse_axis_x, mouse_change.x); | ||
| 111 | SetAxis(identifier, mouse_axis_y, -mouse_change.y); | ||
| 112 | |||
| 113 | // Decay input over time | ||
| 114 | const float clamped_length = std::min(1.0f, length); | ||
| 115 | const float decay_strength = Settings::values.mouse_panning_decay_strength.GetValue(); | ||
| 116 | const float decay = 1 - clamped_length * clamped_length * decay_strength * 0.01f; | ||
| 117 | const float min_decay = Settings::values.mouse_panning_min_decay.GetValue(); | ||
| 118 | const float clamped_decay = std::min(1 - min_decay / 100.0f, decay); | ||
| 119 | last_mouse_change *= clamped_decay; | ||
| 98 | } | 120 | } |
| 99 | 121 | ||
| 100 | void Mouse::UpdateMotionInput() { | 122 | void Mouse::UpdateMotionInput() { |
| 101 | const float sensitivity = | 123 | // This may need its own sensitivity instead of using the average |
| 102 | Settings::values.mouse_panning_sensitivity.GetValue() * default_motion_sensitivity; | 124 | const float sensitivity = (Settings::values.mouse_panning_x_sensitivity.GetValue() + |
| 125 | Settings::values.mouse_panning_y_sensitivity.GetValue()) / | ||
| 126 | 2.0f * default_motion_sensitivity; | ||
| 103 | 127 | ||
| 104 | const float rotation_velocity = std::sqrt(last_motion_change.x * last_motion_change.x + | 128 | const float rotation_velocity = std::sqrt(last_motion_change.x * last_motion_change.x + |
| 105 | last_motion_change.y * last_motion_change.y); | 129 | last_motion_change.y * last_motion_change.y); |
| @@ -131,49 +155,28 @@ void Mouse::UpdateMotionInput() { | |||
| 131 | 155 | ||
| 132 | void Mouse::Move(int x, int y, int center_x, int center_y) { | 156 | void Mouse::Move(int x, int y, int center_x, int center_y) { |
| 133 | if (Settings::values.mouse_panning) { | 157 | if (Settings::values.mouse_panning) { |
| 134 | mouse_panning_timeout = 0; | 158 | const auto mouse_change = |
| 135 | |||
| 136 | auto mouse_change = | ||
| 137 | (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>(); | 159 | (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>(); |
| 138 | last_motion_change += {-mouse_change.y, -mouse_change.x, 0}; | 160 | const float x_sensitivity = |
| 139 | 161 | Settings::values.mouse_panning_x_sensitivity.GetValue() * default_stick_sensitivity; | |
| 140 | const auto move_distance = mouse_change.Length(); | 162 | const float y_sensitivity = |
| 141 | if (move_distance == 0) { | 163 | Settings::values.mouse_panning_y_sensitivity.GetValue() * default_stick_sensitivity; |
| 142 | return; | ||
| 143 | } | ||
| 144 | 164 | ||
| 145 | // Make slow movements at least 3 units on length | 165 | last_motion_change += {-mouse_change.y, -mouse_change.x, 0}; |
| 146 | if (move_distance < 3.0f) { | 166 | last_mouse_change.x += mouse_change.x * x_sensitivity * 0.09f; |
| 147 | // Normalize value | 167 | last_mouse_change.y += mouse_change.y * y_sensitivity * 0.09f; |
| 148 | mouse_change /= move_distance; | ||
| 149 | mouse_change *= 3.0f; | ||
| 150 | } | ||
| 151 | |||
| 152 | // Average mouse movements | ||
| 153 | last_mouse_change = (last_mouse_change * 0.91f) + (mouse_change * 0.09f); | ||
| 154 | |||
| 155 | const auto last_move_distance = last_mouse_change.Length(); | ||
| 156 | |||
| 157 | // Make fast movements clamp to 8 units on length | ||
| 158 | if (last_move_distance > 8.0f) { | ||
| 159 | // Normalize value | ||
| 160 | last_mouse_change /= last_move_distance; | ||
| 161 | last_mouse_change *= 8.0f; | ||
| 162 | } | ||
| 163 | |||
| 164 | // Ignore average if it's less than 1 unit and use current movement value | ||
| 165 | if (last_move_distance < 1.0f) { | ||
| 166 | last_mouse_change = mouse_change / mouse_change.Length(); | ||
| 167 | } | ||
| 168 | 168 | ||
| 169 | return; | 169 | return; |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | if (button_pressed) { | 172 | if (button_pressed) { |
| 173 | const auto mouse_move = Common::MakeVec<int>(x, y) - mouse_origin; | 173 | const auto mouse_move = Common::MakeVec<int>(x, y) - mouse_origin; |
| 174 | const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.0012f; | 174 | const float x_sensitivity = Settings::values.mouse_panning_x_sensitivity.GetValue(); |
| 175 | SetAxis(identifier, mouse_axis_x, static_cast<float>(mouse_move.x) * sensitivity); | 175 | const float y_sensitivity = Settings::values.mouse_panning_y_sensitivity.GetValue(); |
| 176 | SetAxis(identifier, mouse_axis_y, static_cast<float>(-mouse_move.y) * sensitivity); | 176 | SetAxis(identifier, mouse_axis_x, |
| 177 | static_cast<float>(mouse_move.x) * x_sensitivity * 0.0012f); | ||
| 178 | SetAxis(identifier, mouse_axis_y, | ||
| 179 | static_cast<float>(-mouse_move.y) * y_sensitivity * 0.0012f); | ||
| 177 | 180 | ||
| 178 | last_motion_change = { | 181 | last_motion_change = { |
| 179 | static_cast<float>(-mouse_move.y) / 50.0f, | 182 | static_cast<float>(-mouse_move.y) / 50.0f, |
| @@ -241,10 +244,6 @@ void Mouse::ReleaseAllButtons() { | |||
| 241 | button_pressed = false; | 244 | button_pressed = false; |
| 242 | } | 245 | } |
| 243 | 246 | ||
| 244 | void Mouse::StopPanning() { | ||
| 245 | last_mouse_change = {}; | ||
| 246 | } | ||
| 247 | |||
| 248 | std::vector<Common::ParamPackage> Mouse::GetInputDevices() const { | 247 | std::vector<Common::ParamPackage> Mouse::GetInputDevices() const { |
| 249 | std::vector<Common::ParamPackage> devices; | 248 | std::vector<Common::ParamPackage> devices; |
| 250 | devices.emplace_back(Common::ParamPackage{ | 249 | devices.emplace_back(Common::ParamPackage{ |
diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index b872c7a0f..0e8edcce1 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h | |||
| @@ -98,7 +98,6 @@ private: | |||
| 98 | void UpdateThread(std::stop_token stop_token); | 98 | void UpdateThread(std::stop_token stop_token); |
| 99 | void UpdateStickInput(); | 99 | void UpdateStickInput(); |
| 100 | void UpdateMotionInput(); | 100 | void UpdateMotionInput(); |
| 101 | void StopPanning(); | ||
| 102 | 101 | ||
| 103 | Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const; | 102 | Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const; |
| 104 | 103 | ||
| @@ -108,7 +107,6 @@ private: | |||
| 108 | Common::Vec3<float> last_motion_change; | 107 | Common::Vec3<float> last_motion_change; |
| 109 | Common::Vec2<int> wheel_position; | 108 | Common::Vec2<int> wheel_position; |
| 110 | bool button_pressed; | 109 | bool button_pressed; |
| 111 | int mouse_panning_timeout{}; | ||
| 112 | std::jthread update_thread; | 110 | std::jthread update_thread; |
| 113 | }; | 111 | }; |
| 114 | 112 | ||
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 9a0439bb5..9f26392b1 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp | |||
| @@ -150,6 +150,8 @@ public: | |||
| 150 | if (sdl_controller) { | 150 | if (sdl_controller) { |
| 151 | const auto type = SDL_GameControllerGetType(sdl_controller.get()); | 151 | const auto type = SDL_GameControllerGetType(sdl_controller.get()); |
| 152 | return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) || | 152 | return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) || |
| 153 | (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT) || | ||
| 154 | (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) || | ||
| 153 | (type == SDL_CONTROLLER_TYPE_PS5); | 155 | (type == SDL_CONTROLLER_TYPE_PS5); |
| 154 | } | 156 | } |
| 155 | return false; | 157 | return false; |
| @@ -228,9 +230,8 @@ public: | |||
| 228 | return false; | 230 | return false; |
| 229 | } | 231 | } |
| 230 | 232 | ||
| 231 | Common::Input::BatteryLevel GetBatteryLevel() { | 233 | Common::Input::BatteryLevel GetBatteryLevel(SDL_JoystickPowerLevel battery_level) { |
| 232 | const auto level = SDL_JoystickCurrentPowerLevel(sdl_joystick.get()); | 234 | switch (battery_level) { |
| 233 | switch (level) { | ||
| 234 | case SDL_JOYSTICK_POWER_EMPTY: | 235 | case SDL_JOYSTICK_POWER_EMPTY: |
| 235 | return Common::Input::BatteryLevel::Empty; | 236 | return Common::Input::BatteryLevel::Empty; |
| 236 | case SDL_JOYSTICK_POWER_LOW: | 237 | case SDL_JOYSTICK_POWER_LOW: |
| @@ -378,7 +379,6 @@ void SDLDriver::InitJoystick(int joystick_index) { | |||
| 378 | if (joystick_map.find(guid) == joystick_map.end()) { | 379 | if (joystick_map.find(guid) == joystick_map.end()) { |
| 379 | auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller); | 380 | auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller); |
| 380 | PreSetController(joystick->GetPadIdentifier()); | 381 | PreSetController(joystick->GetPadIdentifier()); |
| 381 | SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); | ||
| 382 | joystick->EnableMotion(); | 382 | joystick->EnableMotion(); |
| 383 | joystick_map[guid].emplace_back(std::move(joystick)); | 383 | joystick_map[guid].emplace_back(std::move(joystick)); |
| 384 | return; | 384 | return; |
| @@ -398,7 +398,6 @@ void SDLDriver::InitJoystick(int joystick_index) { | |||
| 398 | const int port = static_cast<int>(joystick_guid_list.size()); | 398 | const int port = static_cast<int>(joystick_guid_list.size()); |
| 399 | auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller); | 399 | auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller); |
| 400 | PreSetController(joystick->GetPadIdentifier()); | 400 | PreSetController(joystick->GetPadIdentifier()); |
| 401 | SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); | ||
| 402 | joystick->EnableMotion(); | 401 | joystick->EnableMotion(); |
| 403 | joystick_guid_list.emplace_back(std::move(joystick)); | 402 | joystick_guid_list.emplace_back(std::move(joystick)); |
| 404 | } | 403 | } |
| @@ -438,8 +437,6 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { | |||
| 438 | if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { | 437 | if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { |
| 439 | const PadIdentifier identifier = joystick->GetPadIdentifier(); | 438 | const PadIdentifier identifier = joystick->GetPadIdentifier(); |
| 440 | SetButton(identifier, event.jbutton.button, true); | 439 | SetButton(identifier, event.jbutton.button, true); |
| 441 | // Battery doesn't trigger an event so just update every button press | ||
| 442 | SetBattery(identifier, joystick->GetBatteryLevel()); | ||
| 443 | } | 440 | } |
| 444 | break; | 441 | break; |
| 445 | } | 442 | } |
| @@ -466,6 +463,13 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { | |||
| 466 | } | 463 | } |
| 467 | break; | 464 | break; |
| 468 | } | 465 | } |
| 466 | case SDL_JOYBATTERYUPDATED: { | ||
| 467 | if (auto joystick = GetSDLJoystickBySDLID(event.jbattery.which)) { | ||
| 468 | const PadIdentifier identifier = joystick->GetPadIdentifier(); | ||
| 469 | SetBattery(identifier, joystick->GetBatteryLevel(event.jbattery.level)); | ||
| 470 | } | ||
| 471 | break; | ||
| 472 | } | ||
| 469 | case SDL_JOYDEVICEREMOVED: | 473 | case SDL_JOYDEVICEREMOVED: |
| 470 | LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); | 474 | LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); |
| 471 | CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); | 475 | CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); |
| @@ -483,6 +487,10 @@ void SDLDriver::CloseJoysticks() { | |||
| 483 | } | 487 | } |
| 484 | 488 | ||
| 485 | SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) { | 489 | SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) { |
| 490 | // Set our application name. Currently passed to DBus by SDL and visible to the user through | ||
| 491 | // their desktop environment. | ||
| 492 | SDL_SetHint(SDL_HINT_APP_NAME, "yuzu"); | ||
| 493 | |||
| 486 | if (!Settings::values.enable_raw_input) { | 494 | if (!Settings::values.enable_raw_input) { |
| 487 | // Disable raw input. When enabled this setting causes SDL to die when a web applet opens | 495 | // Disable raw input. When enabled this setting causes SDL to die when a web applet opens |
| 488 | SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); | 496 | SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); |
| @@ -501,6 +509,9 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en | |||
| 501 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "0"); | 509 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "0"); |
| 502 | } else { | 510 | } else { |
| 503 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); | 511 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); |
| 512 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOYCON_HOME_LED, "0"); | ||
| 513 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "0"); | ||
| 514 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS, "1"); | ||
| 504 | } | 515 | } |
| 505 | 516 | ||
| 506 | // Disable hidapi drivers for pro controllers when the custom joycon driver is enabled | 517 | // Disable hidapi drivers for pro controllers when the custom joycon driver is enabled |
| @@ -508,8 +519,11 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en | |||
| 508 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "0"); | 519 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "0"); |
| 509 | } else { | 520 | } else { |
| 510 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1"); | 521 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1"); |
| 522 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0"); | ||
| 511 | } | 523 | } |
| 512 | 524 | ||
| 525 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, "1"); | ||
| 526 | |||
| 513 | // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native | 527 | // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native |
| 514 | // driver on Linux. | 528 | // driver on Linux. |
| 515 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0"); | 529 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0"); |
| @@ -789,7 +803,9 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p | |||
| 789 | // This list also excludes Screenshot since there's not really a mapping for that | 803 | // This list also excludes Screenshot since there's not really a mapping for that |
| 790 | ButtonBindings switch_to_sdl_button; | 804 | ButtonBindings switch_to_sdl_button; |
| 791 | 805 | ||
| 792 | if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) { | 806 | if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO || |
| 807 | SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT || | ||
| 808 | SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) { | ||
| 793 | switch_to_sdl_button = GetNintendoButtonBinding(joystick); | 809 | switch_to_sdl_button = GetNintendoButtonBinding(joystick); |
| 794 | } else { | 810 | } else { |
| 795 | switch_to_sdl_button = GetDefaultButtonBinding(); | 811 | switch_to_sdl_button = GetDefaultButtonBinding(); |
diff --git a/src/input_common/drivers/virtual_amiibo.cpp b/src/input_common/drivers/virtual_amiibo.cpp index 6435b8af8..180eb53ef 100644 --- a/src/input_common/drivers/virtual_amiibo.cpp +++ b/src/input_common/drivers/virtual_amiibo.cpp | |||
| @@ -29,14 +29,13 @@ Common::Input::DriverResult VirtualAmiibo::SetPollingMode( | |||
| 29 | 29 | ||
| 30 | switch (polling_mode) { | 30 | switch (polling_mode) { |
| 31 | case Common::Input::PollingMode::NFC: | 31 | case Common::Input::PollingMode::NFC: |
| 32 | if (state == State::Initialized) { | 32 | state = State::Initialized; |
| 33 | state = State::WaitingForAmiibo; | ||
| 34 | } | ||
| 35 | return Common::Input::DriverResult::Success; | 33 | return Common::Input::DriverResult::Success; |
| 36 | default: | 34 | default: |
| 37 | if (state == State::AmiiboIsOpen) { | 35 | if (state == State::TagNearby) { |
| 38 | CloseAmiibo(); | 36 | CloseAmiibo(); |
| 39 | } | 37 | } |
| 38 | state = State::Disabled; | ||
| 40 | return Common::Input::DriverResult::NotSupported; | 39 | return Common::Input::DriverResult::NotSupported; |
| 41 | } | 40 | } |
| 42 | } | 41 | } |
| @@ -45,6 +44,39 @@ Common::Input::NfcState VirtualAmiibo::SupportsNfc( | |||
| 45 | [[maybe_unused]] const PadIdentifier& identifier_) const { | 44 | [[maybe_unused]] const PadIdentifier& identifier_) const { |
| 46 | return Common::Input::NfcState::Success; | 45 | return Common::Input::NfcState::Success; |
| 47 | } | 46 | } |
| 47 | Common::Input::NfcState VirtualAmiibo::StartNfcPolling(const PadIdentifier& identifier_) { | ||
| 48 | if (state != State::Initialized) { | ||
| 49 | return Common::Input::NfcState::WrongDeviceState; | ||
| 50 | } | ||
| 51 | state = State::WaitingForAmiibo; | ||
| 52 | return Common::Input::NfcState::Success; | ||
| 53 | } | ||
| 54 | |||
| 55 | Common::Input::NfcState VirtualAmiibo::StopNfcPolling(const PadIdentifier& identifier_) { | ||
| 56 | if (state == State::Disabled) { | ||
| 57 | return Common::Input::NfcState::WrongDeviceState; | ||
| 58 | } | ||
| 59 | if (state == State::TagNearby) { | ||
| 60 | CloseAmiibo(); | ||
| 61 | } | ||
| 62 | state = State::Initialized; | ||
| 63 | return Common::Input::NfcState::Success; | ||
| 64 | } | ||
| 65 | |||
| 66 | Common::Input::NfcState VirtualAmiibo::ReadAmiiboData(const PadIdentifier& identifier_, | ||
| 67 | std::vector<u8>& out_data) { | ||
| 68 | if (state != State::TagNearby) { | ||
| 69 | return Common::Input::NfcState::WrongDeviceState; | ||
| 70 | } | ||
| 71 | |||
| 72 | if (status.tag_type != 1U << 1) { | ||
| 73 | return Common::Input::NfcState::InvalidTagType; | ||
| 74 | } | ||
| 75 | |||
| 76 | out_data.resize(nfc_data.size()); | ||
| 77 | memcpy(out_data.data(), nfc_data.data(), nfc_data.size()); | ||
| 78 | return Common::Input::NfcState::Success; | ||
| 79 | } | ||
| 48 | 80 | ||
| 49 | Common::Input::NfcState VirtualAmiibo::WriteNfcData( | 81 | Common::Input::NfcState VirtualAmiibo::WriteNfcData( |
| 50 | [[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) { | 82 | [[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) { |
| @@ -66,6 +98,69 @@ Common::Input::NfcState VirtualAmiibo::WriteNfcData( | |||
| 66 | return Common::Input::NfcState::Success; | 98 | return Common::Input::NfcState::Success; |
| 67 | } | 99 | } |
| 68 | 100 | ||
| 101 | Common::Input::NfcState VirtualAmiibo::ReadMifareData(const PadIdentifier& identifier_, | ||
| 102 | const Common::Input::MifareRequest& request, | ||
| 103 | Common::Input::MifareRequest& out_data) { | ||
| 104 | if (state != State::TagNearby) { | ||
| 105 | return Common::Input::NfcState::WrongDeviceState; | ||
| 106 | } | ||
| 107 | |||
| 108 | if (status.tag_type != 1U << 6) { | ||
| 109 | return Common::Input::NfcState::InvalidTagType; | ||
| 110 | } | ||
| 111 | |||
| 112 | for (std::size_t i = 0; i < request.data.size(); i++) { | ||
| 113 | if (request.data[i].command == 0) { | ||
| 114 | continue; | ||
| 115 | } | ||
| 116 | out_data.data[i].command = request.data[i].command; | ||
| 117 | out_data.data[i].sector = request.data[i].sector; | ||
| 118 | |||
| 119 | const std::size_t sector_index = | ||
| 120 | request.data[i].sector * sizeof(Common::Input::MifareData::data); | ||
| 121 | |||
| 122 | if (nfc_data.size() < sector_index + sizeof(Common::Input::MifareData::data)) { | ||
| 123 | return Common::Input::NfcState::WriteFailed; | ||
| 124 | } | ||
| 125 | |||
| 126 | // Ignore the sector key as we don't support it | ||
| 127 | memcpy(out_data.data[i].data.data(), nfc_data.data() + sector_index, | ||
| 128 | sizeof(Common::Input::MifareData::data)); | ||
| 129 | } | ||
| 130 | |||
| 131 | return Common::Input::NfcState::Success; | ||
| 132 | } | ||
| 133 | |||
| 134 | Common::Input::NfcState VirtualAmiibo::WriteMifareData( | ||
| 135 | const PadIdentifier& identifier_, const Common::Input::MifareRequest& request) { | ||
| 136 | if (state != State::TagNearby) { | ||
| 137 | return Common::Input::NfcState::WrongDeviceState; | ||
| 138 | } | ||
| 139 | |||
| 140 | if (status.tag_type != 1U << 6) { | ||
| 141 | return Common::Input::NfcState::InvalidTagType; | ||
| 142 | } | ||
| 143 | |||
| 144 | for (std::size_t i = 0; i < request.data.size(); i++) { | ||
| 145 | if (request.data[i].command == 0) { | ||
| 146 | continue; | ||
| 147 | } | ||
| 148 | |||
| 149 | const std::size_t sector_index = | ||
| 150 | request.data[i].sector * sizeof(Common::Input::MifareData::data); | ||
| 151 | |||
| 152 | if (nfc_data.size() < sector_index + sizeof(Common::Input::MifareData::data)) { | ||
| 153 | return Common::Input::NfcState::WriteFailed; | ||
| 154 | } | ||
| 155 | |||
| 156 | // Ignore the sector key as we don't support it | ||
| 157 | memcpy(nfc_data.data() + sector_index, request.data[i].data.data(), | ||
| 158 | sizeof(Common::Input::MifareData::data)); | ||
| 159 | } | ||
| 160 | |||
| 161 | return Common::Input::NfcState::Success; | ||
| 162 | } | ||
| 163 | |||
| 69 | VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const { | 164 | VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const { |
| 70 | return state; | 165 | return state; |
| 71 | } | 166 | } |
| @@ -112,23 +207,31 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(std::span<u8> data) { | |||
| 112 | case AmiiboSizeWithoutPassword: | 207 | case AmiiboSizeWithoutPassword: |
| 113 | case AmiiboSizeWithSignature: | 208 | case AmiiboSizeWithSignature: |
| 114 | nfc_data.resize(AmiiboSize); | 209 | nfc_data.resize(AmiiboSize); |
| 210 | status.tag_type = 1U << 1; | ||
| 211 | status.uuid_length = 7; | ||
| 115 | break; | 212 | break; |
| 116 | case MifareSize: | 213 | case MifareSize: |
| 117 | nfc_data.resize(MifareSize); | 214 | nfc_data.resize(MifareSize); |
| 215 | status.tag_type = 1U << 6; | ||
| 216 | status.uuid_length = 4; | ||
| 118 | break; | 217 | break; |
| 119 | default: | 218 | default: |
| 120 | return Info::NotAnAmiibo; | 219 | return Info::NotAnAmiibo; |
| 121 | } | 220 | } |
| 122 | 221 | ||
| 123 | state = State::AmiiboIsOpen; | 222 | status.uuid = {}; |
| 223 | status.protocol = 1; | ||
| 224 | state = State::TagNearby; | ||
| 225 | status.state = Common::Input::NfcState::NewAmiibo, | ||
| 124 | memcpy(nfc_data.data(), data.data(), data.size_bytes()); | 226 | memcpy(nfc_data.data(), data.data(), data.size_bytes()); |
| 125 | SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); | 227 | memcpy(status.uuid.data(), nfc_data.data(), status.uuid_length); |
| 228 | SetNfc(identifier, status); | ||
| 126 | return Info::Success; | 229 | return Info::Success; |
| 127 | } | 230 | } |
| 128 | 231 | ||
| 129 | VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { | 232 | VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { |
| 130 | if (state == State::AmiiboIsOpen) { | 233 | if (state == State::TagNearby) { |
| 131 | SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); | 234 | SetNfc(identifier, status); |
| 132 | return Info::Success; | 235 | return Info::Success; |
| 133 | } | 236 | } |
| 134 | 237 | ||
| @@ -136,9 +239,14 @@ VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { | |||
| 136 | } | 239 | } |
| 137 | 240 | ||
| 138 | VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() { | 241 | VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() { |
| 139 | state = polling_mode == Common::Input::PollingMode::NFC ? State::WaitingForAmiibo | 242 | if (state != State::TagNearby) { |
| 140 | : State::Initialized; | 243 | return Info::Success; |
| 141 | SetNfc(identifier, {Common::Input::NfcState::AmiiboRemoved, {}}); | 244 | } |
| 245 | |||
| 246 | state = State::WaitingForAmiibo; | ||
| 247 | status.state = Common::Input::NfcState::AmiiboRemoved; | ||
| 248 | SetNfc(identifier, status); | ||
| 249 | status.tag_type = 0; | ||
| 142 | return Info::Success; | 250 | return Info::Success; |
| 143 | } | 251 | } |
| 144 | 252 | ||
diff --git a/src/input_common/drivers/virtual_amiibo.h b/src/input_common/drivers/virtual_amiibo.h index 09ca09e68..490f38e05 100644 --- a/src/input_common/drivers/virtual_amiibo.h +++ b/src/input_common/drivers/virtual_amiibo.h | |||
| @@ -20,9 +20,10 @@ namespace InputCommon { | |||
| 20 | class VirtualAmiibo final : public InputEngine { | 20 | class VirtualAmiibo final : public InputEngine { |
| 21 | public: | 21 | public: |
| 22 | enum class State { | 22 | enum class State { |
| 23 | Disabled, | ||
| 23 | Initialized, | 24 | Initialized, |
| 24 | WaitingForAmiibo, | 25 | WaitingForAmiibo, |
| 25 | AmiiboIsOpen, | 26 | TagNearby, |
| 26 | }; | 27 | }; |
| 27 | 28 | ||
| 28 | enum class Info { | 29 | enum class Info { |
| @@ -41,9 +42,17 @@ public: | |||
| 41 | const PadIdentifier& identifier_, const Common::Input::PollingMode polling_mode_) override; | 42 | const PadIdentifier& identifier_, const Common::Input::PollingMode polling_mode_) override; |
| 42 | 43 | ||
| 43 | Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; | 44 | Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; |
| 44 | 45 | Common::Input::NfcState StartNfcPolling(const PadIdentifier& identifier_) override; | |
| 46 | Common::Input::NfcState StopNfcPolling(const PadIdentifier& identifier_) override; | ||
| 47 | Common::Input::NfcState ReadAmiiboData(const PadIdentifier& identifier_, | ||
| 48 | std::vector<u8>& out_data) override; | ||
| 45 | Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_, | 49 | Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_, |
| 46 | const std::vector<u8>& data) override; | 50 | const std::vector<u8>& data) override; |
| 51 | Common::Input::NfcState ReadMifareData(const PadIdentifier& identifier_, | ||
| 52 | const Common::Input::MifareRequest& data, | ||
| 53 | Common::Input::MifareRequest& out_data) override; | ||
| 54 | Common::Input::NfcState WriteMifareData(const PadIdentifier& identifier_, | ||
| 55 | const Common::Input::MifareRequest& data) override; | ||
| 47 | 56 | ||
| 48 | State GetCurrentState() const; | 57 | State GetCurrentState() const; |
| 49 | 58 | ||
| @@ -61,8 +70,9 @@ private: | |||
| 61 | static constexpr std::size_t MifareSize = 0x400; | 70 | static constexpr std::size_t MifareSize = 0x400; |
| 62 | 71 | ||
| 63 | std::string file_path{}; | 72 | std::string file_path{}; |
| 64 | State state{State::Initialized}; | 73 | State state{State::Disabled}; |
| 65 | std::vector<u8> nfc_data; | 74 | std::vector<u8> nfc_data; |
| 75 | Common::Input::NfcStatus status; | ||
| 66 | Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Passive}; | 76 | Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Passive}; |
| 67 | }; | 77 | }; |
| 68 | } // namespace InputCommon | 78 | } // namespace InputCommon |
diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 95106f16d..cf51f3481 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp | |||
| @@ -1,7 +1,9 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2022 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/input.h" | ||
| 4 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 6 | #include "common/scope_exit.h" | ||
| 5 | #include "common/swap.h" | 7 | #include "common/swap.h" |
| 6 | #include "common/thread.h" | 8 | #include "common/thread.h" |
| 7 | #include "input_common/helpers/joycon_driver.h" | 9 | #include "input_common/helpers/joycon_driver.h" |
| @@ -27,13 +29,13 @@ void JoyconDriver::Stop() { | |||
| 27 | input_thread = {}; | 29 | input_thread = {}; |
| 28 | } | 30 | } |
| 29 | 31 | ||
| 30 | DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) { | 32 | Common::Input::DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) { |
| 31 | std::scoped_lock lock{mutex}; | 33 | std::scoped_lock lock{mutex}; |
| 32 | 34 | ||
| 33 | handle_device_type = ControllerType::None; | 35 | handle_device_type = ControllerType::None; |
| 34 | GetDeviceType(device_info, handle_device_type); | 36 | GetDeviceType(device_info, handle_device_type); |
| 35 | if (handle_device_type == ControllerType::None) { | 37 | if (handle_device_type == ControllerType::None) { |
| 36 | return DriverResult::UnsupportedControllerType; | 38 | return Common::Input::DriverResult::UnsupportedControllerType; |
| 37 | } | 39 | } |
| 38 | 40 | ||
| 39 | hidapi_handle->handle = | 41 | hidapi_handle->handle = |
| @@ -42,15 +44,15 @@ DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) | |||
| 42 | if (!hidapi_handle->handle) { | 44 | if (!hidapi_handle->handle) { |
| 43 | LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", | 45 | LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", |
| 44 | device_info->vendor_id, device_info->product_id); | 46 | device_info->vendor_id, device_info->product_id); |
| 45 | return DriverResult::HandleInUse; | 47 | return Common::Input::DriverResult::HandleInUse; |
| 46 | } | 48 | } |
| 47 | SDL_hid_set_nonblocking(hidapi_handle->handle, 1); | 49 | SDL_hid_set_nonblocking(hidapi_handle->handle, 1); |
| 48 | return DriverResult::Success; | 50 | return Common::Input::DriverResult::Success; |
| 49 | } | 51 | } |
| 50 | 52 | ||
| 51 | DriverResult JoyconDriver::InitializeDevice() { | 53 | Common::Input::DriverResult JoyconDriver::InitializeDevice() { |
| 52 | if (!hidapi_handle->handle) { | 54 | if (!hidapi_handle->handle) { |
| 53 | return DriverResult::InvalidHandle; | 55 | return Common::Input::DriverResult::InvalidHandle; |
| 54 | } | 56 | } |
| 55 | std::scoped_lock lock{mutex}; | 57 | std::scoped_lock lock{mutex}; |
| 56 | disable_input_thread = true; | 58 | disable_input_thread = true; |
| @@ -71,6 +73,7 @@ DriverResult JoyconDriver::InitializeDevice() { | |||
| 71 | nfc_enabled = false; | 73 | nfc_enabled = false; |
| 72 | passive_enabled = false; | 74 | passive_enabled = false; |
| 73 | irs_enabled = false; | 75 | irs_enabled = false; |
| 76 | input_only_device = false; | ||
| 74 | gyro_sensitivity = Joycon::GyroSensitivity::DPS2000; | 77 | gyro_sensitivity = Joycon::GyroSensitivity::DPS2000; |
| 75 | gyro_performance = Joycon::GyroPerformance::HZ833; | 78 | gyro_performance = Joycon::GyroPerformance::HZ833; |
| 76 | accelerometer_sensitivity = Joycon::AccelerometerSensitivity::G8; | 79 | accelerometer_sensitivity = Joycon::AccelerometerSensitivity::G8; |
| @@ -85,16 +88,23 @@ DriverResult JoyconDriver::InitializeDevice() { | |||
| 85 | rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle); | 88 | rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle); |
| 86 | 89 | ||
| 87 | // Get fixed joycon info | 90 | // Get fixed joycon info |
| 88 | generic_protocol->GetVersionNumber(version); | 91 | if (generic_protocol->GetVersionNumber(version) != Common::Input::DriverResult::Success) { |
| 89 | generic_protocol->SetLowPowerMode(false); | 92 | // If this command fails the device doesn't accept configuration commands |
| 90 | generic_protocol->GetColor(color); | 93 | input_only_device = true; |
| 91 | if (handle_device_type == ControllerType::Pro) { | 94 | } |
| 92 | // Some 3rd party controllers aren't pro controllers | 95 | |
| 93 | generic_protocol->GetControllerType(device_type); | 96 | if (!input_only_device) { |
| 94 | } else { | 97 | generic_protocol->SetLowPowerMode(false); |
| 95 | device_type = handle_device_type; | 98 | generic_protocol->GetColor(color); |
| 99 | if (handle_device_type == ControllerType::Pro) { | ||
| 100 | // Some 3rd party controllers aren't pro controllers | ||
| 101 | generic_protocol->GetControllerType(device_type); | ||
| 102 | } else { | ||
| 103 | device_type = handle_device_type; | ||
| 104 | } | ||
| 105 | generic_protocol->GetSerialNumber(serial_number); | ||
| 96 | } | 106 | } |
| 97 | generic_protocol->GetSerialNumber(serial_number); | 107 | |
| 98 | supported_features = GetSupportedFeatures(); | 108 | supported_features = GetSupportedFeatures(); |
| 99 | 109 | ||
| 100 | // Get Calibration data | 110 | // Get Calibration data |
| @@ -112,7 +122,7 @@ DriverResult JoyconDriver::InitializeDevice() { | |||
| 112 | joycon_poller = std::make_unique<JoyconPoller>(device_type, left_stick_calibration, | 122 | joycon_poller = std::make_unique<JoyconPoller>(device_type, left_stick_calibration, |
| 113 | right_stick_calibration, motion_calibration); | 123 | right_stick_calibration, motion_calibration); |
| 114 | 124 | ||
| 115 | // Start pooling for data | 125 | // Start polling for data |
| 116 | is_connected = true; | 126 | is_connected = true; |
| 117 | if (!input_thread_running) { | 127 | if (!input_thread_running) { |
| 118 | input_thread = | 128 | input_thread = |
| @@ -120,7 +130,7 @@ DriverResult JoyconDriver::InitializeDevice() { | |||
| 120 | } | 130 | } |
| 121 | 131 | ||
| 122 | disable_input_thread = false; | 132 | disable_input_thread = false; |
| 123 | return DriverResult::Success; | 133 | return Common::Input::DriverResult::Success; |
| 124 | } | 134 | } |
| 125 | 135 | ||
| 126 | void JoyconDriver::InputThread(std::stop_token stop_token) { | 136 | void JoyconDriver::InputThread(std::stop_token stop_token) { |
| @@ -208,7 +218,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { | |||
| 208 | joycon_poller->UpdateCamera(irs_protocol->GetImage(), irs_protocol->GetIrsFormat()); | 218 | joycon_poller->UpdateCamera(irs_protocol->GetImage(), irs_protocol->GetIrsFormat()); |
| 209 | } | 219 | } |
| 210 | 220 | ||
| 211 | if (nfc_protocol->IsEnabled()) { | 221 | if (nfc_protocol->IsPolling()) { |
| 212 | if (amiibo_detected) { | 222 | if (amiibo_detected) { |
| 213 | if (!nfc_protocol->HasAmiibo()) { | 223 | if (!nfc_protocol->HasAmiibo()) { |
| 214 | joycon_poller->UpdateAmiibo({}); | 224 | joycon_poller->UpdateAmiibo({}); |
| @@ -218,10 +228,10 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { | |||
| 218 | } | 228 | } |
| 219 | 229 | ||
| 220 | if (!amiibo_detected) { | 230 | if (!amiibo_detected) { |
| 221 | std::vector<u8> data(0x21C); | 231 | Joycon::TagInfo tag_info; |
| 222 | const auto result = nfc_protocol->ScanAmiibo(data); | 232 | const auto result = nfc_protocol->GetTagInfo(tag_info); |
| 223 | if (result == DriverResult::Success) { | 233 | if (result == Common::Input::DriverResult::Success) { |
| 224 | joycon_poller->UpdateAmiibo(data); | 234 | joycon_poller->UpdateAmiibo(tag_info); |
| 225 | amiibo_detected = true; | 235 | amiibo_detected = true; |
| 226 | } | 236 | } |
| 227 | } | 237 | } |
| @@ -246,7 +256,8 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { | |||
| 246 | } | 256 | } |
| 247 | } | 257 | } |
| 248 | 258 | ||
| 249 | DriverResult JoyconDriver::SetPollingMode() { | 259 | Common::Input::DriverResult JoyconDriver::SetPollingMode() { |
| 260 | SCOPE_EXIT({ disable_input_thread = false; }); | ||
| 250 | disable_input_thread = true; | 261 | disable_input_thread = true; |
| 251 | 262 | ||
| 252 | rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); | 263 | rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); |
| @@ -259,6 +270,10 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 259 | generic_protocol->EnableImu(false); | 270 | generic_protocol->EnableImu(false); |
| 260 | } | 271 | } |
| 261 | 272 | ||
| 273 | if (input_only_device) { | ||
| 274 | return Common::Input::DriverResult::NotSupported; | ||
| 275 | } | ||
| 276 | |||
| 262 | if (irs_protocol->IsEnabled()) { | 277 | if (irs_protocol->IsEnabled()) { |
| 263 | irs_protocol->DisableIrs(); | 278 | irs_protocol->DisableIrs(); |
| 264 | } | 279 | } |
| @@ -275,46 +290,42 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 275 | 290 | ||
| 276 | if (irs_enabled && supported_features.irs) { | 291 | if (irs_enabled && supported_features.irs) { |
| 277 | auto result = irs_protocol->EnableIrs(); | 292 | auto result = irs_protocol->EnableIrs(); |
| 278 | if (result == DriverResult::Success) { | 293 | if (result == Common::Input::DriverResult::Success) { |
| 279 | disable_input_thread = false; | ||
| 280 | return result; | 294 | return result; |
| 281 | } | 295 | } |
| 282 | irs_protocol->DisableIrs(); | 296 | irs_protocol->DisableIrs(); |
| 283 | LOG_ERROR(Input, "Error enabling IRS"); | 297 | LOG_ERROR(Input, "Error enabling IRS"); |
| 298 | return result; | ||
| 284 | } | 299 | } |
| 285 | 300 | ||
| 286 | if (nfc_enabled && supported_features.nfc) { | 301 | if (nfc_enabled && supported_features.nfc) { |
| 287 | auto result = nfc_protocol->EnableNfc(); | 302 | auto result = nfc_protocol->EnableNfc(); |
| 288 | if (result == DriverResult::Success) { | 303 | if (result == Common::Input::DriverResult::Success) { |
| 289 | result = nfc_protocol->StartNFCPollingMode(); | ||
| 290 | } | ||
| 291 | if (result == DriverResult::Success) { | ||
| 292 | disable_input_thread = false; | ||
| 293 | return result; | 304 | return result; |
| 294 | } | 305 | } |
| 295 | nfc_protocol->DisableNfc(); | 306 | nfc_protocol->DisableNfc(); |
| 296 | LOG_ERROR(Input, "Error enabling NFC"); | 307 | LOG_ERROR(Input, "Error enabling NFC"); |
| 308 | return result; | ||
| 297 | } | 309 | } |
| 298 | 310 | ||
| 299 | if (hidbus_enabled && supported_features.hidbus) { | 311 | if (hidbus_enabled && supported_features.hidbus) { |
| 300 | auto result = ring_protocol->EnableRingCon(); | 312 | auto result = ring_protocol->EnableRingCon(); |
| 301 | if (result == DriverResult::Success) { | 313 | if (result == Common::Input::DriverResult::Success) { |
| 302 | result = ring_protocol->StartRingconPolling(); | 314 | result = ring_protocol->StartRingconPolling(); |
| 303 | } | 315 | } |
| 304 | if (result == DriverResult::Success) { | 316 | if (result == Common::Input::DriverResult::Success) { |
| 305 | ring_connected = true; | 317 | ring_connected = true; |
| 306 | disable_input_thread = false; | ||
| 307 | return result; | 318 | return result; |
| 308 | } | 319 | } |
| 309 | ring_connected = false; | 320 | ring_connected = false; |
| 310 | ring_protocol->DisableRingCon(); | 321 | ring_protocol->DisableRingCon(); |
| 311 | LOG_ERROR(Input, "Error enabling Ringcon"); | 322 | LOG_ERROR(Input, "Error enabling Ringcon"); |
| 323 | return result; | ||
| 312 | } | 324 | } |
| 313 | 325 | ||
| 314 | if (passive_enabled && supported_features.passive) { | 326 | if (passive_enabled && supported_features.passive) { |
| 315 | const auto result = generic_protocol->EnablePassiveMode(); | 327 | const auto result = generic_protocol->EnablePassiveMode(); |
| 316 | if (result == DriverResult::Success) { | 328 | if (result == Common::Input::DriverResult::Success) { |
| 317 | disable_input_thread = false; | ||
| 318 | return result; | 329 | return result; |
| 319 | } | 330 | } |
| 320 | LOG_ERROR(Input, "Error enabling passive mode"); | 331 | LOG_ERROR(Input, "Error enabling passive mode"); |
| @@ -322,13 +333,12 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 322 | 333 | ||
| 323 | // Default Mode | 334 | // Default Mode |
| 324 | const auto result = generic_protocol->EnableActiveMode(); | 335 | const auto result = generic_protocol->EnableActiveMode(); |
| 325 | if (result != DriverResult::Success) { | 336 | if (result != Common::Input::DriverResult::Success) { |
| 326 | LOG_ERROR(Input, "Error enabling active mode"); | 337 | LOG_ERROR(Input, "Error enabling active mode"); |
| 327 | } | 338 | } |
| 328 | // Switch calls this function after enabling active mode | 339 | // Switch calls this function after enabling active mode |
| 329 | generic_protocol->TriggersElapsed(); | 340 | generic_protocol->TriggersElapsed(); |
| 330 | 341 | ||
| 331 | disable_input_thread = false; | ||
| 332 | return result; | 342 | return result; |
| 333 | } | 343 | } |
| 334 | 344 | ||
| @@ -339,6 +349,10 @@ JoyconDriver::SupportedFeatures JoyconDriver::GetSupportedFeatures() { | |||
| 339 | .vibration = true, | 349 | .vibration = true, |
| 340 | }; | 350 | }; |
| 341 | 351 | ||
| 352 | if (input_only_device) { | ||
| 353 | return features; | ||
| 354 | } | ||
| 355 | |||
| 342 | if (device_type == ControllerType::Right) { | 356 | if (device_type == ControllerType::Right) { |
| 343 | features.nfc = true; | 357 | features.nfc = true; |
| 344 | features.irs = true; | 358 | features.irs = true; |
| @@ -383,26 +397,26 @@ bool JoyconDriver::IsPayloadCorrect(int status, std::span<const u8> buffer) { | |||
| 383 | return true; | 397 | return true; |
| 384 | } | 398 | } |
| 385 | 399 | ||
| 386 | DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) { | 400 | Common::Input::DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) { |
| 387 | std::scoped_lock lock{mutex}; | 401 | std::scoped_lock lock{mutex}; |
| 388 | if (disable_input_thread) { | 402 | if (disable_input_thread) { |
| 389 | return DriverResult::HandleInUse; | 403 | return Common::Input::DriverResult::HandleInUse; |
| 390 | } | 404 | } |
| 391 | return rumble_protocol->SendVibration(vibration); | 405 | return rumble_protocol->SendVibration(vibration); |
| 392 | } | 406 | } |
| 393 | 407 | ||
| 394 | DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) { | 408 | Common::Input::DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) { |
| 395 | std::scoped_lock lock{mutex}; | 409 | std::scoped_lock lock{mutex}; |
| 396 | if (disable_input_thread) { | 410 | if (disable_input_thread) { |
| 397 | return DriverResult::HandleInUse; | 411 | return Common::Input::DriverResult::HandleInUse; |
| 398 | } | 412 | } |
| 399 | return generic_protocol->SetLedPattern(led_pattern); | 413 | return generic_protocol->SetLedPattern(led_pattern); |
| 400 | } | 414 | } |
| 401 | 415 | ||
| 402 | DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) { | 416 | Common::Input::DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) { |
| 403 | std::scoped_lock lock{mutex}; | 417 | std::scoped_lock lock{mutex}; |
| 404 | if (disable_input_thread) { | 418 | if (disable_input_thread) { |
| 405 | return DriverResult::HandleInUse; | 419 | return Common::Input::DriverResult::HandleInUse; |
| 406 | } | 420 | } |
| 407 | disable_input_thread = true; | 421 | disable_input_thread = true; |
| 408 | const auto result = irs_protocol->SetIrsConfig(mode_, format_); | 422 | const auto result = irs_protocol->SetIrsConfig(mode_, format_); |
| @@ -410,7 +424,7 @@ DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) { | |||
| 410 | return result; | 424 | return result; |
| 411 | } | 425 | } |
| 412 | 426 | ||
| 413 | DriverResult JoyconDriver::SetPassiveMode() { | 427 | Common::Input::DriverResult JoyconDriver::SetPassiveMode() { |
| 414 | std::scoped_lock lock{mutex}; | 428 | std::scoped_lock lock{mutex}; |
| 415 | motion_enabled = false; | 429 | motion_enabled = false; |
| 416 | hidbus_enabled = false; | 430 | hidbus_enabled = false; |
| @@ -420,7 +434,7 @@ DriverResult JoyconDriver::SetPassiveMode() { | |||
| 420 | return SetPollingMode(); | 434 | return SetPollingMode(); |
| 421 | } | 435 | } |
| 422 | 436 | ||
| 423 | DriverResult JoyconDriver::SetActiveMode() { | 437 | Common::Input::DriverResult JoyconDriver::SetActiveMode() { |
| 424 | if (is_ring_disabled_by_irs) { | 438 | if (is_ring_disabled_by_irs) { |
| 425 | is_ring_disabled_by_irs = false; | 439 | is_ring_disabled_by_irs = false; |
| 426 | SetActiveMode(); | 440 | SetActiveMode(); |
| @@ -436,11 +450,11 @@ DriverResult JoyconDriver::SetActiveMode() { | |||
| 436 | return SetPollingMode(); | 450 | return SetPollingMode(); |
| 437 | } | 451 | } |
| 438 | 452 | ||
| 439 | DriverResult JoyconDriver::SetIrMode() { | 453 | Common::Input::DriverResult JoyconDriver::SetIrMode() { |
| 440 | std::scoped_lock lock{mutex}; | 454 | std::scoped_lock lock{mutex}; |
| 441 | 455 | ||
| 442 | if (!supported_features.irs) { | 456 | if (!supported_features.irs) { |
| 443 | return DriverResult::NotSupported; | 457 | return Common::Input::DriverResult::NotSupported; |
| 444 | } | 458 | } |
| 445 | 459 | ||
| 446 | if (ring_connected) { | 460 | if (ring_connected) { |
| @@ -455,11 +469,11 @@ DriverResult JoyconDriver::SetIrMode() { | |||
| 455 | return SetPollingMode(); | 469 | return SetPollingMode(); |
| 456 | } | 470 | } |
| 457 | 471 | ||
| 458 | DriverResult JoyconDriver::SetNfcMode() { | 472 | Common::Input::DriverResult JoyconDriver::SetNfcMode() { |
| 459 | std::scoped_lock lock{mutex}; | 473 | std::scoped_lock lock{mutex}; |
| 460 | 474 | ||
| 461 | if (!supported_features.nfc) { | 475 | if (!supported_features.nfc) { |
| 462 | return DriverResult::NotSupported; | 476 | return Common::Input::DriverResult::NotSupported; |
| 463 | } | 477 | } |
| 464 | 478 | ||
| 465 | motion_enabled = true; | 479 | motion_enabled = true; |
| @@ -470,11 +484,11 @@ DriverResult JoyconDriver::SetNfcMode() { | |||
| 470 | return SetPollingMode(); | 484 | return SetPollingMode(); |
| 471 | } | 485 | } |
| 472 | 486 | ||
| 473 | DriverResult JoyconDriver::SetRingConMode() { | 487 | Common::Input::DriverResult JoyconDriver::SetRingConMode() { |
| 474 | std::scoped_lock lock{mutex}; | 488 | std::scoped_lock lock{mutex}; |
| 475 | 489 | ||
| 476 | if (!supported_features.hidbus) { | 490 | if (!supported_features.hidbus) { |
| 477 | return DriverResult::NotSupported; | 491 | return Common::Input::DriverResult::NotSupported; |
| 478 | } | 492 | } |
| 479 | 493 | ||
| 480 | motion_enabled = true; | 494 | motion_enabled = true; |
| @@ -486,29 +500,130 @@ DriverResult JoyconDriver::SetRingConMode() { | |||
| 486 | const auto result = SetPollingMode(); | 500 | const auto result = SetPollingMode(); |
| 487 | 501 | ||
| 488 | if (!ring_connected) { | 502 | if (!ring_connected) { |
| 489 | return DriverResult::NoDeviceDetected; | 503 | return Common::Input::DriverResult::NoDeviceDetected; |
| 504 | } | ||
| 505 | |||
| 506 | return result; | ||
| 507 | } | ||
| 508 | |||
| 509 | Common::Input::DriverResult JoyconDriver::StartNfcPolling() { | ||
| 510 | std::scoped_lock lock{mutex}; | ||
| 511 | |||
| 512 | if (!supported_features.nfc) { | ||
| 513 | return Common::Input::DriverResult::NotSupported; | ||
| 514 | } | ||
| 515 | if (!nfc_protocol->IsEnabled()) { | ||
| 516 | return Common::Input::DriverResult::Disabled; | ||
| 490 | } | 517 | } |
| 491 | 518 | ||
| 519 | disable_input_thread = true; | ||
| 520 | const auto result = nfc_protocol->StartNFCPollingMode(); | ||
| 521 | disable_input_thread = false; | ||
| 522 | |||
| 492 | return result; | 523 | return result; |
| 493 | } | 524 | } |
| 494 | 525 | ||
| 495 | DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) { | 526 | Common::Input::DriverResult JoyconDriver::StopNfcPolling() { |
| 496 | std::scoped_lock lock{mutex}; | 527 | std::scoped_lock lock{mutex}; |
| 528 | |||
| 529 | if (!supported_features.nfc) { | ||
| 530 | return Common::Input::DriverResult::NotSupported; | ||
| 531 | } | ||
| 532 | if (!nfc_protocol->IsEnabled()) { | ||
| 533 | return Common::Input::DriverResult::Disabled; | ||
| 534 | } | ||
| 535 | |||
| 497 | disable_input_thread = true; | 536 | disable_input_thread = true; |
| 537 | const auto result = nfc_protocol->StopNFCPollingMode(); | ||
| 538 | disable_input_thread = false; | ||
| 539 | |||
| 540 | if (amiibo_detected) { | ||
| 541 | amiibo_detected = false; | ||
| 542 | joycon_poller->UpdateAmiibo({}); | ||
| 543 | } | ||
| 544 | |||
| 545 | return result; | ||
| 546 | } | ||
| 547 | |||
| 548 | Common::Input::DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) { | ||
| 549 | std::scoped_lock lock{mutex}; | ||
| 498 | 550 | ||
| 499 | if (!supported_features.nfc) { | 551 | if (!supported_features.nfc) { |
| 500 | return DriverResult::NotSupported; | 552 | return Common::Input::DriverResult::NotSupported; |
| 501 | } | 553 | } |
| 502 | if (!nfc_protocol->IsEnabled()) { | 554 | if (!nfc_protocol->IsEnabled()) { |
| 503 | return DriverResult::Disabled; | 555 | return Common::Input::DriverResult::Disabled; |
| 504 | } | 556 | } |
| 505 | if (!amiibo_detected) { | 557 | if (!amiibo_detected) { |
| 506 | return DriverResult::ErrorWritingData; | 558 | return Common::Input::DriverResult::ErrorWritingData; |
| 507 | } | 559 | } |
| 508 | 560 | ||
| 561 | out_data.resize(0x21C); | ||
| 562 | disable_input_thread = true; | ||
| 563 | const auto result = nfc_protocol->ReadAmiibo(out_data); | ||
| 564 | disable_input_thread = false; | ||
| 565 | |||
| 566 | return result; | ||
| 567 | } | ||
| 568 | |||
| 569 | Common::Input::DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) { | ||
| 570 | std::scoped_lock lock{mutex}; | ||
| 571 | |||
| 572 | if (!supported_features.nfc) { | ||
| 573 | return Common::Input::DriverResult::NotSupported; | ||
| 574 | } | ||
| 575 | if (!nfc_protocol->IsEnabled()) { | ||
| 576 | return Common::Input::DriverResult::Disabled; | ||
| 577 | } | ||
| 578 | if (!amiibo_detected) { | ||
| 579 | return Common::Input::DriverResult::ErrorWritingData; | ||
| 580 | } | ||
| 581 | |||
| 582 | disable_input_thread = true; | ||
| 509 | const auto result = nfc_protocol->WriteAmiibo(data); | 583 | const auto result = nfc_protocol->WriteAmiibo(data); |
| 584 | disable_input_thread = false; | ||
| 585 | |||
| 586 | return result; | ||
| 587 | } | ||
| 510 | 588 | ||
| 589 | Common::Input::DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data, | ||
| 590 | std::span<MifareReadData> out_data) { | ||
| 591 | std::scoped_lock lock{mutex}; | ||
| 592 | |||
| 593 | if (!supported_features.nfc) { | ||
| 594 | return Common::Input::DriverResult::NotSupported; | ||
| 595 | } | ||
| 596 | if (!nfc_protocol->IsEnabled()) { | ||
| 597 | return Common::Input::DriverResult::Disabled; | ||
| 598 | } | ||
| 599 | if (!amiibo_detected) { | ||
| 600 | return Common::Input::DriverResult::ErrorWritingData; | ||
| 601 | } | ||
| 602 | |||
| 603 | disable_input_thread = true; | ||
| 604 | const auto result = nfc_protocol->ReadMifare(data, out_data); | ||
| 511 | disable_input_thread = false; | 605 | disable_input_thread = false; |
| 606 | |||
| 607 | return result; | ||
| 608 | } | ||
| 609 | |||
| 610 | Common::Input::DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) { | ||
| 611 | std::scoped_lock lock{mutex}; | ||
| 612 | |||
| 613 | if (!supported_features.nfc) { | ||
| 614 | return Common::Input::DriverResult::NotSupported; | ||
| 615 | } | ||
| 616 | if (!nfc_protocol->IsEnabled()) { | ||
| 617 | return Common::Input::DriverResult::Disabled; | ||
| 618 | } | ||
| 619 | if (!amiibo_detected) { | ||
| 620 | return Common::Input::DriverResult::ErrorWritingData; | ||
| 621 | } | ||
| 622 | |||
| 623 | disable_input_thread = true; | ||
| 624 | const auto result = nfc_protocol->WriteMifare(data); | ||
| 625 | disable_input_thread = false; | ||
| 626 | |||
| 512 | return result; | 627 | return result; |
| 513 | } | 628 | } |
| 514 | 629 | ||
| @@ -561,8 +676,8 @@ void JoyconDriver::SetCallbacks(const JoyconCallbacks& callbacks) { | |||
| 561 | joycon_poller->SetCallbacks(callbacks); | 676 | joycon_poller->SetCallbacks(callbacks); |
| 562 | } | 677 | } |
| 563 | 678 | ||
| 564 | DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, | 679 | Common::Input::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, |
| 565 | ControllerType& controller_type) { | 680 | ControllerType& controller_type) { |
| 566 | static constexpr std::array<std::pair<u32, ControllerType>, 6> supported_devices{ | 681 | static constexpr std::array<std::pair<u32, ControllerType>, 6> supported_devices{ |
| 567 | std::pair<u32, ControllerType>{0x2006, ControllerType::Left}, | 682 | std::pair<u32, ControllerType>{0x2006, ControllerType::Left}, |
| 568 | {0x2007, ControllerType::Right}, | 683 | {0x2007, ControllerType::Right}, |
| @@ -572,25 +687,25 @@ DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, | |||
| 572 | 687 | ||
| 573 | controller_type = ControllerType::None; | 688 | controller_type = ControllerType::None; |
| 574 | if (device_info->vendor_id != nintendo_vendor_id) { | 689 | if (device_info->vendor_id != nintendo_vendor_id) { |
| 575 | return DriverResult::UnsupportedControllerType; | 690 | return Common::Input::DriverResult::UnsupportedControllerType; |
| 576 | } | 691 | } |
| 577 | 692 | ||
| 578 | for (const auto& [product_id, type] : supported_devices) { | 693 | for (const auto& [product_id, type] : supported_devices) { |
| 579 | if (device_info->product_id == static_cast<u16>(product_id)) { | 694 | if (device_info->product_id == static_cast<u16>(product_id)) { |
| 580 | controller_type = type; | 695 | controller_type = type; |
| 581 | return Joycon::DriverResult::Success; | 696 | return Common::Input::DriverResult::Success; |
| 582 | } | 697 | } |
| 583 | } | 698 | } |
| 584 | return Joycon::DriverResult::UnsupportedControllerType; | 699 | return Common::Input::DriverResult::UnsupportedControllerType; |
| 585 | } | 700 | } |
| 586 | 701 | ||
| 587 | DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info, | 702 | Common::Input::DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info, |
| 588 | SerialNumber& serial_number) { | 703 | SerialNumber& serial_number) { |
| 589 | if (device_info->serial_number == nullptr) { | 704 | if (device_info->serial_number == nullptr) { |
| 590 | return DriverResult::Unknown; | 705 | return Common::Input::DriverResult::Unknown; |
| 591 | } | 706 | } |
| 592 | std::memcpy(&serial_number, device_info->serial_number, 15); | 707 | std::memcpy(&serial_number, device_info->serial_number, 15); |
| 593 | return Joycon::DriverResult::Success; | 708 | return Common::Input::DriverResult::Success; |
| 594 | } | 709 | } |
| 595 | 710 | ||
| 596 | } // namespace InputCommon::Joycon | 711 | } // namespace InputCommon::Joycon |
diff --git a/src/input_common/helpers/joycon_driver.h b/src/input_common/helpers/joycon_driver.h index e9b2fccbb..335e12cc3 100644 --- a/src/input_common/helpers/joycon_driver.h +++ b/src/input_common/helpers/joycon_driver.h | |||
| @@ -11,6 +11,10 @@ | |||
| 11 | 11 | ||
| 12 | #include "input_common/helpers/joycon_protocol/joycon_types.h" | 12 | #include "input_common/helpers/joycon_protocol/joycon_types.h" |
| 13 | 13 | ||
| 14 | namespace Common::Input { | ||
| 15 | enum class DriverResult; | ||
| 16 | } | ||
| 17 | |||
| 14 | namespace InputCommon::Joycon { | 18 | namespace InputCommon::Joycon { |
| 15 | class CalibrationProtocol; | 19 | class CalibrationProtocol; |
| 16 | class GenericProtocol; | 20 | class GenericProtocol; |
| @@ -26,8 +30,8 @@ public: | |||
| 26 | 30 | ||
| 27 | ~JoyconDriver(); | 31 | ~JoyconDriver(); |
| 28 | 32 | ||
| 29 | DriverResult RequestDeviceAccess(SDL_hid_device_info* device_info); | 33 | Common::Input::DriverResult RequestDeviceAccess(SDL_hid_device_info* device_info); |
| 30 | DriverResult InitializeDevice(); | 34 | Common::Input::DriverResult InitializeDevice(); |
| 31 | void Stop(); | 35 | void Stop(); |
| 32 | 36 | ||
| 33 | bool IsConnected() const; | 37 | bool IsConnected() const; |
| @@ -41,25 +45,31 @@ public: | |||
| 41 | SerialNumber GetSerialNumber() const; | 45 | SerialNumber GetSerialNumber() const; |
| 42 | SerialNumber GetHandleSerialNumber() const; | 46 | SerialNumber GetHandleSerialNumber() const; |
| 43 | 47 | ||
| 44 | DriverResult SetVibration(const VibrationValue& vibration); | 48 | Common::Input::DriverResult SetVibration(const VibrationValue& vibration); |
| 45 | DriverResult SetLedConfig(u8 led_pattern); | 49 | Common::Input::DriverResult SetLedConfig(u8 led_pattern); |
| 46 | DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_); | 50 | Common::Input::DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_); |
| 47 | DriverResult SetPassiveMode(); | 51 | Common::Input::DriverResult SetPassiveMode(); |
| 48 | DriverResult SetActiveMode(); | 52 | Common::Input::DriverResult SetActiveMode(); |
| 49 | DriverResult SetIrMode(); | 53 | Common::Input::DriverResult SetIrMode(); |
| 50 | DriverResult SetNfcMode(); | 54 | Common::Input::DriverResult SetNfcMode(); |
| 51 | DriverResult SetRingConMode(); | 55 | Common::Input::DriverResult SetRingConMode(); |
| 52 | DriverResult WriteNfcData(std::span<const u8> data); | 56 | Common::Input::DriverResult StartNfcPolling(); |
| 57 | Common::Input::DriverResult StopNfcPolling(); | ||
| 58 | Common::Input::DriverResult ReadAmiiboData(std::vector<u8>& out_data); | ||
| 59 | Common::Input::DriverResult WriteNfcData(std::span<const u8> data); | ||
| 60 | Common::Input::DriverResult ReadMifareData(std::span<const MifareReadChunk> request, | ||
| 61 | std::span<MifareReadData> out_data); | ||
| 62 | Common::Input::DriverResult WriteMifareData(std::span<const MifareWriteChunk> request); | ||
| 53 | 63 | ||
| 54 | void SetCallbacks(const JoyconCallbacks& callbacks); | 64 | void SetCallbacks(const JoyconCallbacks& callbacks); |
| 55 | 65 | ||
| 56 | // Returns device type from hidapi handle | 66 | // Returns device type from hidapi handle |
| 57 | static DriverResult GetDeviceType(SDL_hid_device_info* device_info, | 67 | static Common::Input::DriverResult GetDeviceType(SDL_hid_device_info* device_info, |
| 58 | ControllerType& controller_type); | 68 | ControllerType& controller_type); |
| 59 | 69 | ||
| 60 | // Returns serial number from hidapi handle | 70 | // Returns serial number from hidapi handle |
| 61 | static DriverResult GetSerialNumber(SDL_hid_device_info* device_info, | 71 | static Common::Input::DriverResult GetSerialNumber(SDL_hid_device_info* device_info, |
| 62 | SerialNumber& serial_number); | 72 | SerialNumber& serial_number); |
| 63 | 73 | ||
| 64 | private: | 74 | private: |
| 65 | struct SupportedFeatures { | 75 | struct SupportedFeatures { |
| @@ -78,7 +88,7 @@ private: | |||
| 78 | void OnNewData(std::span<u8> buffer); | 88 | void OnNewData(std::span<u8> buffer); |
| 79 | 89 | ||
| 80 | /// Updates device configuration to enable or disable features | 90 | /// Updates device configuration to enable or disable features |
| 81 | DriverResult SetPollingMode(); | 91 | Common::Input::DriverResult SetPollingMode(); |
| 82 | 92 | ||
| 83 | /// Returns true if input thread is valid and doesn't need to be stopped | 93 | /// Returns true if input thread is valid and doesn't need to be stopped |
| 84 | bool IsInputThreadValid() const; | 94 | bool IsInputThreadValid() const; |
| @@ -114,6 +124,7 @@ private: | |||
| 114 | // Hardware configuration | 124 | // Hardware configuration |
| 115 | u8 leds{}; | 125 | u8 leds{}; |
| 116 | ReportMode mode{}; | 126 | ReportMode mode{}; |
| 127 | bool input_only_device{}; | ||
| 117 | bool passive_enabled{}; // Low power mode, Ideal for multiple controllers at the same time | 128 | bool passive_enabled{}; // Low power mode, Ideal for multiple controllers at the same time |
| 118 | bool hidbus_enabled{}; // External device support | 129 | bool hidbus_enabled{}; // External device support |
| 119 | bool irs_enabled{}; // Infrared camera input | 130 | bool irs_enabled{}; // Infrared camera input |
diff --git a/src/input_common/helpers/joycon_protocol/calibration.cpp b/src/input_common/helpers/joycon_protocol/calibration.cpp index d8f040f75..1300ecaf5 100644 --- a/src/input_common/helpers/joycon_protocol/calibration.cpp +++ b/src/input_common/helpers/joycon_protocol/calibration.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include <cstring> | 4 | #include <cstring> |
| 5 | 5 | ||
| 6 | #include "common/input.h" | ||
| 6 | #include "input_common/helpers/joycon_protocol/calibration.h" | 7 | #include "input_common/helpers/joycon_protocol/calibration.h" |
| 7 | #include "input_common/helpers/joycon_protocol/joycon_types.h" | 8 | #include "input_common/helpers/joycon_protocol/joycon_types.h" |
| 8 | 9 | ||
| @@ -11,28 +12,29 @@ namespace InputCommon::Joycon { | |||
| 11 | CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle) | 12 | CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle) |
| 12 | : JoyconCommonProtocol(std::move(handle)) {} | 13 | : JoyconCommonProtocol(std::move(handle)) {} |
| 13 | 14 | ||
| 14 | DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) { | 15 | Common::Input::DriverResult CalibrationProtocol::GetLeftJoyStickCalibration( |
| 16 | JoyStickCalibration& calibration) { | ||
| 15 | ScopedSetBlocking sb(this); | 17 | ScopedSetBlocking sb(this); |
| 16 | DriverResult result{DriverResult::Success}; | 18 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; |
| 17 | JoystickLeftSpiCalibration spi_calibration{}; | 19 | JoystickLeftSpiCalibration spi_calibration{}; |
| 18 | bool has_user_calibration = false; | 20 | bool has_user_calibration = false; |
| 19 | calibration = {}; | 21 | calibration = {}; |
| 20 | 22 | ||
| 21 | if (result == DriverResult::Success) { | 23 | if (result == Common::Input::DriverResult::Success) { |
| 22 | result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration); | 24 | result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration); |
| 23 | } | 25 | } |
| 24 | 26 | ||
| 25 | // Read User defined calibration | 27 | // Read User defined calibration |
| 26 | if (result == DriverResult::Success && has_user_calibration) { | 28 | if (result == Common::Input::DriverResult::Success && has_user_calibration) { |
| 27 | result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration); | 29 | result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration); |
| 28 | } | 30 | } |
| 29 | 31 | ||
| 30 | // Read Factory calibration | 32 | // Read Factory calibration |
| 31 | if (result == DriverResult::Success && !has_user_calibration) { | 33 | if (result == Common::Input::DriverResult::Success && !has_user_calibration) { |
| 32 | result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration); | 34 | result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration); |
| 33 | } | 35 | } |
| 34 | 36 | ||
| 35 | if (result == DriverResult::Success) { | 37 | if (result == Common::Input::DriverResult::Success) { |
| 36 | calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center); | 38 | calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center); |
| 37 | calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center); | 39 | calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center); |
| 38 | calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min); | 40 | calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min); |
| @@ -47,28 +49,29 @@ DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration | |||
| 47 | return result; | 49 | return result; |
| 48 | } | 50 | } |
| 49 | 51 | ||
| 50 | DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibration& calibration) { | 52 | Common::Input::DriverResult CalibrationProtocol::GetRightJoyStickCalibration( |
| 53 | JoyStickCalibration& calibration) { | ||
| 51 | ScopedSetBlocking sb(this); | 54 | ScopedSetBlocking sb(this); |
| 52 | DriverResult result{DriverResult::Success}; | 55 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; |
| 53 | JoystickRightSpiCalibration spi_calibration{}; | 56 | JoystickRightSpiCalibration spi_calibration{}; |
| 54 | bool has_user_calibration = false; | 57 | bool has_user_calibration = false; |
| 55 | calibration = {}; | 58 | calibration = {}; |
| 56 | 59 | ||
| 57 | if (result == DriverResult::Success) { | 60 | if (result == Common::Input::DriverResult::Success) { |
| 58 | result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration); | 61 | result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration); |
| 59 | } | 62 | } |
| 60 | 63 | ||
| 61 | // Read User defined calibration | 64 | // Read User defined calibration |
| 62 | if (result == DriverResult::Success && has_user_calibration) { | 65 | if (result == Common::Input::DriverResult::Success && has_user_calibration) { |
| 63 | result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration); | 66 | result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration); |
| 64 | } | 67 | } |
| 65 | 68 | ||
| 66 | // Read Factory calibration | 69 | // Read Factory calibration |
| 67 | if (result == DriverResult::Success && !has_user_calibration) { | 70 | if (result == Common::Input::DriverResult::Success && !has_user_calibration) { |
| 68 | result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration); | 71 | result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration); |
| 69 | } | 72 | } |
| 70 | 73 | ||
| 71 | if (result == DriverResult::Success) { | 74 | if (result == Common::Input::DriverResult::Success) { |
| 72 | calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center); | 75 | calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center); |
| 73 | calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center); | 76 | calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center); |
| 74 | calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min); | 77 | calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min); |
| @@ -83,28 +86,28 @@ DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibratio | |||
| 83 | return result; | 86 | return result; |
| 84 | } | 87 | } |
| 85 | 88 | ||
| 86 | DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) { | 89 | Common::Input::DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) { |
| 87 | ScopedSetBlocking sb(this); | 90 | ScopedSetBlocking sb(this); |
| 88 | DriverResult result{DriverResult::Success}; | 91 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; |
| 89 | ImuSpiCalibration spi_calibration{}; | 92 | ImuSpiCalibration spi_calibration{}; |
| 90 | bool has_user_calibration = false; | 93 | bool has_user_calibration = false; |
| 91 | calibration = {}; | 94 | calibration = {}; |
| 92 | 95 | ||
| 93 | if (result == DriverResult::Success) { | 96 | if (result == Common::Input::DriverResult::Success) { |
| 94 | result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration); | 97 | result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration); |
| 95 | } | 98 | } |
| 96 | 99 | ||
| 97 | // Read User defined calibration | 100 | // Read User defined calibration |
| 98 | if (result == DriverResult::Success && has_user_calibration) { | 101 | if (result == Common::Input::DriverResult::Success && has_user_calibration) { |
| 99 | result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration); | 102 | result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration); |
| 100 | } | 103 | } |
| 101 | 104 | ||
| 102 | // Read Factory calibration | 105 | // Read Factory calibration |
| 103 | if (result == DriverResult::Success && !has_user_calibration) { | 106 | if (result == Common::Input::DriverResult::Success && !has_user_calibration) { |
| 104 | result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration); | 107 | result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration); |
| 105 | } | 108 | } |
| 106 | 109 | ||
| 107 | if (result == DriverResult::Success) { | 110 | if (result == Common::Input::DriverResult::Success) { |
| 108 | calibration.accelerometer[0].offset = spi_calibration.accelerometer_offset[0]; | 111 | calibration.accelerometer[0].offset = spi_calibration.accelerometer_offset[0]; |
| 109 | calibration.accelerometer[1].offset = spi_calibration.accelerometer_offset[1]; | 112 | calibration.accelerometer[1].offset = spi_calibration.accelerometer_offset[1]; |
| 110 | calibration.accelerometer[2].offset = spi_calibration.accelerometer_offset[2]; | 113 | calibration.accelerometer[2].offset = spi_calibration.accelerometer_offset[2]; |
| @@ -127,8 +130,8 @@ DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibrati | |||
| 127 | return result; | 130 | return result; |
| 128 | } | 131 | } |
| 129 | 132 | ||
| 130 | DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration, | 133 | Common::Input::DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration, |
| 131 | s16 current_value) { | 134 | s16 current_value) { |
| 132 | constexpr s16 DefaultRingRange{800}; | 135 | constexpr s16 DefaultRingRange{800}; |
| 133 | 136 | ||
| 134 | // TODO: Get default calibration form ring itself | 137 | // TODO: Get default calibration form ring itself |
| @@ -144,15 +147,15 @@ DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibratio | |||
| 144 | .max_value = ring_data_max, | 147 | .max_value = ring_data_max, |
| 145 | .min_value = ring_data_min, | 148 | .min_value = ring_data_min, |
| 146 | }; | 149 | }; |
| 147 | return DriverResult::Success; | 150 | return Common::Input::DriverResult::Success; |
| 148 | } | 151 | } |
| 149 | 152 | ||
| 150 | DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address, | 153 | Common::Input::DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address, |
| 151 | bool& has_user_calibration) { | 154 | bool& has_user_calibration) { |
| 152 | MagicSpiCalibration spi_magic{}; | 155 | MagicSpiCalibration spi_magic{}; |
| 153 | const DriverResult result{ReadSPI(address, spi_magic)}; | 156 | const Common::Input::DriverResult result{ReadSPI(address, spi_magic)}; |
| 154 | has_user_calibration = false; | 157 | has_user_calibration = false; |
| 155 | if (result == DriverResult::Success) { | 158 | if (result == Common::Input::DriverResult::Success) { |
| 156 | has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 && | 159 | has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 && |
| 157 | spi_magic.second == CalibrationMagic::USR_MAGIC_1; | 160 | spi_magic.second == CalibrationMagic::USR_MAGIC_1; |
| 158 | } | 161 | } |
diff --git a/src/input_common/helpers/joycon_protocol/calibration.h b/src/input_common/helpers/joycon_protocol/calibration.h index c6fd0f729..82d94b366 100644 --- a/src/input_common/helpers/joycon_protocol/calibration.h +++ b/src/input_common/helpers/joycon_protocol/calibration.h | |||
| @@ -12,8 +12,11 @@ | |||
| 12 | 12 | ||
| 13 | #include "input_common/helpers/joycon_protocol/common_protocol.h" | 13 | #include "input_common/helpers/joycon_protocol/common_protocol.h" |
| 14 | 14 | ||
| 15 | namespace InputCommon::Joycon { | 15 | namespace Common::Input { |
| 16 | enum class DriverResult; | 16 | enum class DriverResult; |
| 17 | } | ||
| 18 | |||
| 19 | namespace InputCommon::Joycon { | ||
| 17 | struct JoyStickCalibration; | 20 | struct JoyStickCalibration; |
| 18 | struct IMUCalibration; | 21 | struct IMUCalibration; |
| 19 | struct JoyconHandle; | 22 | struct JoyconHandle; |
| @@ -31,30 +34,30 @@ public: | |||
| 31 | * @param is_factory_calibration if true factory values will be returned | 34 | * @param is_factory_calibration if true factory values will be returned |
| 32 | * @returns JoyStickCalibration of the left joystick | 35 | * @returns JoyStickCalibration of the left joystick |
| 33 | */ | 36 | */ |
| 34 | DriverResult GetLeftJoyStickCalibration(JoyStickCalibration& calibration); | 37 | Common::Input::DriverResult GetLeftJoyStickCalibration(JoyStickCalibration& calibration); |
| 35 | 38 | ||
| 36 | /** | 39 | /** |
| 37 | * Sends a request to obtain the right stick calibration from memory | 40 | * Sends a request to obtain the right stick calibration from memory |
| 38 | * @param is_factory_calibration if true factory values will be returned | 41 | * @param is_factory_calibration if true factory values will be returned |
| 39 | * @returns JoyStickCalibration of the right joystick | 42 | * @returns JoyStickCalibration of the right joystick |
| 40 | */ | 43 | */ |
| 41 | DriverResult GetRightJoyStickCalibration(JoyStickCalibration& calibration); | 44 | Common::Input::DriverResult GetRightJoyStickCalibration(JoyStickCalibration& calibration); |
| 42 | 45 | ||
| 43 | /** | 46 | /** |
| 44 | * Sends a request to obtain the motion calibration from memory | 47 | * Sends a request to obtain the motion calibration from memory |
| 45 | * @returns ImuCalibration of the motion sensor | 48 | * @returns ImuCalibration of the motion sensor |
| 46 | */ | 49 | */ |
| 47 | DriverResult GetImuCalibration(MotionCalibration& calibration); | 50 | Common::Input::DriverResult GetImuCalibration(MotionCalibration& calibration); |
| 48 | 51 | ||
| 49 | /** | 52 | /** |
| 50 | * Calculates on run time the proper calibration of the ring controller | 53 | * Calculates on run time the proper calibration of the ring controller |
| 51 | * @returns RingCalibration of the ring sensor | 54 | * @returns RingCalibration of the ring sensor |
| 52 | */ | 55 | */ |
| 53 | DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value); | 56 | Common::Input::DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value); |
| 54 | 57 | ||
| 55 | private: | 58 | private: |
| 56 | /// Returns true if the specified address corresponds to the magic value of user calibration | 59 | /// Returns true if the specified address corresponds to the magic value of user calibration |
| 57 | DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration); | 60 | Common::Input::DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration); |
| 58 | 61 | ||
| 59 | /// Converts a raw calibration block to an u16 value containing the x axis value | 62 | /// Converts a raw calibration block to an u16 value containing the x axis value |
| 60 | u16 GetXAxisCalibrationValue(std::span<u8> block) const; | 63 | u16 GetXAxisCalibrationValue(std::span<u8> block) const; |
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp index 51669261a..a6eecf980 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp +++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2022 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/input.h" | ||
| 4 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 5 | #include "input_common/helpers/joycon_protocol/common_protocol.h" | 6 | #include "input_common/helpers/joycon_protocol/common_protocol.h" |
| 6 | 7 | ||
| @@ -21,10 +22,10 @@ void JoyconCommonProtocol::SetNonBlocking() { | |||
| 21 | SDL_hid_set_nonblocking(hidapi_handle->handle, 1); | 22 | SDL_hid_set_nonblocking(hidapi_handle->handle, 1); |
| 22 | } | 23 | } |
| 23 | 24 | ||
| 24 | DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) { | 25 | Common::Input::DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) { |
| 25 | const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type); | 26 | const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type); |
| 26 | 27 | ||
| 27 | if (result == DriverResult::Success) { | 28 | if (result == Common::Input::DriverResult::Success) { |
| 28 | // Fallback to 3rd party pro controllers | 29 | // Fallback to 3rd party pro controllers |
| 29 | if (controller_type == ControllerType::None) { | 30 | if (controller_type == ControllerType::None) { |
| 30 | controller_type = ControllerType::Pro; | 31 | controller_type = ControllerType::Pro; |
| @@ -34,12 +35,13 @@ DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type | |||
| 34 | return result; | 35 | return result; |
| 35 | } | 36 | } |
| 36 | 37 | ||
| 37 | DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) { | 38 | Common::Input::DriverResult JoyconCommonProtocol::CheckDeviceAccess( |
| 39 | SDL_hid_device_info* device_info) { | ||
| 38 | ControllerType controller_type{ControllerType::None}; | 40 | ControllerType controller_type{ControllerType::None}; |
| 39 | const auto result = GetDeviceType(controller_type); | 41 | const auto result = GetDeviceType(controller_type); |
| 40 | 42 | ||
| 41 | if (result != DriverResult::Success || controller_type == ControllerType::None) { | 43 | if (result != Common::Input::DriverResult::Success || controller_type == ControllerType::None) { |
| 42 | return DriverResult::UnsupportedControllerType; | 44 | return Common::Input::DriverResult::UnsupportedControllerType; |
| 43 | } | 45 | } |
| 44 | 46 | ||
| 45 | hidapi_handle->handle = | 47 | hidapi_handle->handle = |
| @@ -48,32 +50,32 @@ DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device | |||
| 48 | if (!hidapi_handle->handle) { | 50 | if (!hidapi_handle->handle) { |
| 49 | LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", | 51 | LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", |
| 50 | device_info->vendor_id, device_info->product_id); | 52 | device_info->vendor_id, device_info->product_id); |
| 51 | return DriverResult::HandleInUse; | 53 | return Common::Input::DriverResult::HandleInUse; |
| 52 | } | 54 | } |
| 53 | 55 | ||
| 54 | SetNonBlocking(); | 56 | SetNonBlocking(); |
| 55 | return DriverResult::Success; | 57 | return Common::Input::DriverResult::Success; |
| 56 | } | 58 | } |
| 57 | 59 | ||
| 58 | DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) { | 60 | Common::Input::DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) { |
| 59 | const std::array<u8, 1> buffer{static_cast<u8>(report_mode)}; | 61 | const std::array<u8, 1> buffer{static_cast<u8>(report_mode)}; |
| 60 | return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer); | 62 | return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer); |
| 61 | } | 63 | } |
| 62 | 64 | ||
| 63 | DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) { | 65 | Common::Input::DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) { |
| 64 | const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size()); | 66 | const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size()); |
| 65 | 67 | ||
| 66 | if (result == -1) { | 68 | if (result == -1) { |
| 67 | return DriverResult::ErrorWritingData; | 69 | return Common::Input::DriverResult::ErrorWritingData; |
| 68 | } | 70 | } |
| 69 | 71 | ||
| 70 | return DriverResult::Success; | 72 | return Common::Input::DriverResult::Success; |
| 71 | } | 73 | } |
| 72 | 74 | ||
| 73 | DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, | 75 | Common::Input::DriverResult JoyconCommonProtocol::GetSubCommandResponse( |
| 74 | SubCommandResponse& output) { | 76 | SubCommand sc, SubCommandResponse& output) { |
| 75 | constexpr int timeout_mili = 66; | 77 | constexpr int timeout_mili = 66; |
| 76 | constexpr int MaxTries = 15; | 78 | constexpr int MaxTries = 10; |
| 77 | int tries = 0; | 79 | int tries = 0; |
| 78 | 80 | ||
| 79 | do { | 81 | do { |
| @@ -84,16 +86,17 @@ DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, | |||
| 84 | LOG_ERROR(Input, "No response from joycon"); | 86 | LOG_ERROR(Input, "No response from joycon"); |
| 85 | } | 87 | } |
| 86 | if (tries++ > MaxTries) { | 88 | if (tries++ > MaxTries) { |
| 87 | return DriverResult::Timeout; | 89 | return Common::Input::DriverResult::Timeout; |
| 88 | } | 90 | } |
| 89 | } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY && | 91 | } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY && |
| 90 | output.sub_command != sc); | 92 | output.sub_command != sc); |
| 91 | 93 | ||
| 92 | return DriverResult::Success; | 94 | return Common::Input::DriverResult::Success; |
| 93 | } | 95 | } |
| 94 | 96 | ||
| 95 | DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer, | 97 | Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, |
| 96 | SubCommandResponse& output) { | 98 | std::span<const u8> buffer, |
| 99 | SubCommandResponse& output) { | ||
| 97 | SubCommandPacket packet{ | 100 | SubCommandPacket packet{ |
| 98 | .output_report = OutputReport::RUMBLE_AND_SUBCMD, | 101 | .output_report = OutputReport::RUMBLE_AND_SUBCMD, |
| 99 | .packet_counter = GetCounter(), | 102 | .packet_counter = GetCounter(), |
| @@ -102,28 +105,28 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const | |||
| 102 | }; | 105 | }; |
| 103 | 106 | ||
| 104 | if (buffer.size() > packet.command_data.size()) { | 107 | if (buffer.size() > packet.command_data.size()) { |
| 105 | return DriverResult::InvalidParameters; | 108 | return Common::Input::DriverResult::InvalidParameters; |
| 106 | } | 109 | } |
| 107 | 110 | ||
| 108 | memcpy(packet.command_data.data(), buffer.data(), buffer.size()); | 111 | memcpy(packet.command_data.data(), buffer.data(), buffer.size()); |
| 109 | 112 | ||
| 110 | auto result = SendData(packet); | 113 | auto result = SendData(packet); |
| 111 | 114 | ||
| 112 | if (result != DriverResult::Success) { | 115 | if (result != Common::Input::DriverResult::Success) { |
| 113 | return result; | 116 | return result; |
| 114 | } | 117 | } |
| 115 | 118 | ||
| 116 | result = GetSubCommandResponse(sc, output); | 119 | return GetSubCommandResponse(sc, output); |
| 117 | |||
| 118 | return DriverResult::Success; | ||
| 119 | } | 120 | } |
| 120 | 121 | ||
| 121 | DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) { | 122 | Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, |
| 123 | std::span<const u8> buffer) { | ||
| 122 | SubCommandResponse output{}; | 124 | SubCommandResponse output{}; |
| 123 | return SendSubCommand(sc, buffer, output); | 125 | return SendSubCommand(sc, buffer, output); |
| 124 | } | 126 | } |
| 125 | 127 | ||
| 126 | DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const u8> buffer) { | 128 | Common::Input::DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, |
| 129 | std::span<const u8> buffer) { | ||
| 127 | SubCommandPacket packet{ | 130 | SubCommandPacket packet{ |
| 128 | .output_report = OutputReport::MCU_DATA, | 131 | .output_report = OutputReport::MCU_DATA, |
| 129 | .packet_counter = GetCounter(), | 132 | .packet_counter = GetCounter(), |
| @@ -132,7 +135,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const | |||
| 132 | }; | 135 | }; |
| 133 | 136 | ||
| 134 | if (buffer.size() > packet.command_data.size()) { | 137 | if (buffer.size() > packet.command_data.size()) { |
| 135 | return DriverResult::InvalidParameters; | 138 | return Common::Input::DriverResult::InvalidParameters; |
| 136 | } | 139 | } |
| 137 | 140 | ||
| 138 | memcpy(packet.command_data.data(), buffer.data(), buffer.size()); | 141 | memcpy(packet.command_data.data(), buffer.data(), buffer.size()); |
| @@ -140,7 +143,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const | |||
| 140 | return SendData(packet); | 143 | return SendData(packet); |
| 141 | } | 144 | } |
| 142 | 145 | ||
| 143 | DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) { | 146 | Common::Input::DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) { |
| 144 | VibrationPacket packet{ | 147 | VibrationPacket packet{ |
| 145 | .output_report = OutputReport::RUMBLE_ONLY, | 148 | .output_report = OutputReport::RUMBLE_ONLY, |
| 146 | .packet_counter = GetCounter(), | 149 | .packet_counter = GetCounter(), |
| @@ -148,7 +151,7 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe | |||
| 148 | }; | 151 | }; |
| 149 | 152 | ||
| 150 | if (buffer.size() > packet.vibration_data.size()) { | 153 | if (buffer.size() > packet.vibration_data.size()) { |
| 151 | return DriverResult::InvalidParameters; | 154 | return Common::Input::DriverResult::InvalidParameters; |
| 152 | } | 155 | } |
| 153 | 156 | ||
| 154 | memcpy(packet.vibration_data.data(), buffer.data(), buffer.size()); | 157 | memcpy(packet.vibration_data.data(), buffer.data(), buffer.size()); |
| @@ -156,9 +159,10 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe | |||
| 156 | return SendData(packet); | 159 | return SendData(packet); |
| 157 | } | 160 | } |
| 158 | 161 | ||
| 159 | DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) { | 162 | Common::Input::DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, |
| 163 | std::span<u8> output) { | ||
| 160 | constexpr std::size_t HeaderSize = 5; | 164 | constexpr std::size_t HeaderSize = 5; |
| 161 | constexpr std::size_t MaxTries = 10; | 165 | constexpr std::size_t MaxTries = 5; |
| 162 | std::size_t tries = 0; | 166 | std::size_t tries = 0; |
| 163 | SubCommandResponse response{}; | 167 | SubCommandResponse response{}; |
| 164 | std::array<u8, sizeof(ReadSpiPacket)> buffer{}; | 168 | std::array<u8, sizeof(ReadSpiPacket)> buffer{}; |
| @@ -170,36 +174,36 @@ DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> out | |||
| 170 | memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket)); | 174 | memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket)); |
| 171 | do { | 175 | do { |
| 172 | const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response); | 176 | const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response); |
| 173 | if (result != DriverResult::Success) { | 177 | if (result != Common::Input::DriverResult::Success) { |
| 174 | return result; | 178 | return result; |
| 175 | } | 179 | } |
| 176 | 180 | ||
| 177 | if (tries++ > MaxTries) { | 181 | if (tries++ > MaxTries) { |
| 178 | return DriverResult::Timeout; | 182 | return Common::Input::DriverResult::Timeout; |
| 179 | } | 183 | } |
| 180 | } while (response.spi_address != addr); | 184 | } while (response.spi_address != addr); |
| 181 | 185 | ||
| 182 | if (response.command_data.size() < packet_data.size + HeaderSize) { | 186 | if (response.command_data.size() < packet_data.size + HeaderSize) { |
| 183 | return DriverResult::WrongReply; | 187 | return Common::Input::DriverResult::WrongReply; |
| 184 | } | 188 | } |
| 185 | 189 | ||
| 186 | // Remove header from output | 190 | // Remove header from output |
| 187 | memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size); | 191 | memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size); |
| 188 | return DriverResult::Success; | 192 | return Common::Input::DriverResult::Success; |
| 189 | } | 193 | } |
| 190 | 194 | ||
| 191 | DriverResult JoyconCommonProtocol::EnableMCU(bool enable) { | 195 | Common::Input::DriverResult JoyconCommonProtocol::EnableMCU(bool enable) { |
| 192 | const std::array<u8, 1> mcu_state{static_cast<u8>(enable ? 1 : 0)}; | 196 | const std::array<u8, 1> mcu_state{static_cast<u8>(enable ? 1 : 0)}; |
| 193 | const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state); | 197 | const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state); |
| 194 | 198 | ||
| 195 | if (result != DriverResult::Success) { | 199 | if (result != Common::Input::DriverResult::Success) { |
| 196 | LOG_ERROR(Input, "Failed with error {}", result); | 200 | LOG_ERROR(Input, "Failed with error {}", result); |
| 197 | } | 201 | } |
| 198 | 202 | ||
| 199 | return result; | 203 | return result; |
| 200 | } | 204 | } |
| 201 | 205 | ||
| 202 | DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) { | 206 | Common::Input::DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) { |
| 203 | LOG_DEBUG(Input, "ConfigureMCU"); | 207 | LOG_DEBUG(Input, "ConfigureMCU"); |
| 204 | std::array<u8, sizeof(MCUConfig)> config_buffer; | 208 | std::array<u8, sizeof(MCUConfig)> config_buffer; |
| 205 | memcpy(config_buffer.data(), &config, sizeof(MCUConfig)); | 209 | memcpy(config_buffer.data(), &config, sizeof(MCUConfig)); |
| @@ -207,15 +211,15 @@ DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) { | |||
| 207 | 211 | ||
| 208 | const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer); | 212 | const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer); |
| 209 | 213 | ||
| 210 | if (result != DriverResult::Success) { | 214 | if (result != Common::Input::DriverResult::Success) { |
| 211 | LOG_ERROR(Input, "Failed with error {}", result); | 215 | LOG_ERROR(Input, "Failed with error {}", result); |
| 212 | } | 216 | } |
| 213 | 217 | ||
| 214 | return result; | 218 | return result; |
| 215 | } | 219 | } |
| 216 | 220 | ||
| 217 | DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode, | 221 | Common::Input::DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode, |
| 218 | MCUCommandResponse& output) { | 222 | MCUCommandResponse& output) { |
| 219 | constexpr int TimeoutMili = 200; | 223 | constexpr int TimeoutMili = 200; |
| 220 | constexpr int MaxTries = 9; | 224 | constexpr int MaxTries = 9; |
| 221 | int tries = 0; | 225 | int tries = 0; |
| @@ -228,17 +232,18 @@ DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode, | |||
| 228 | LOG_ERROR(Input, "No response from joycon attempt {}", tries); | 232 | LOG_ERROR(Input, "No response from joycon attempt {}", tries); |
| 229 | } | 233 | } |
| 230 | if (tries++ > MaxTries) { | 234 | if (tries++ > MaxTries) { |
| 231 | return DriverResult::Timeout; | 235 | return Common::Input::DriverResult::Timeout; |
| 232 | } | 236 | } |
| 233 | } while (output.input_report.report_mode != report_mode || | 237 | } while (output.input_report.report_mode != report_mode || |
| 234 | output.mcu_report == MCUReport::EmptyAwaitingCmd); | 238 | output.mcu_report == MCUReport::EmptyAwaitingCmd); |
| 235 | 239 | ||
| 236 | return DriverResult::Success; | 240 | return Common::Input::DriverResult::Success; |
| 237 | } | 241 | } |
| 238 | 242 | ||
| 239 | DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCommand sc, | 243 | Common::Input::DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, |
| 240 | std::span<const u8> buffer, | 244 | MCUSubCommand sc, |
| 241 | MCUCommandResponse& output) { | 245 | std::span<const u8> buffer, |
| 246 | MCUCommandResponse& output) { | ||
| 242 | SubCommandPacket packet{ | 247 | SubCommandPacket packet{ |
| 243 | .output_report = OutputReport::MCU_DATA, | 248 | .output_report = OutputReport::MCU_DATA, |
| 244 | .packet_counter = GetCounter(), | 249 | .packet_counter = GetCounter(), |
| @@ -247,23 +252,24 @@ DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCom | |||
| 247 | }; | 252 | }; |
| 248 | 253 | ||
| 249 | if (buffer.size() > packet.command_data.size()) { | 254 | if (buffer.size() > packet.command_data.size()) { |
| 250 | return DriverResult::InvalidParameters; | 255 | return Common::Input::DriverResult::InvalidParameters; |
| 251 | } | 256 | } |
| 252 | 257 | ||
| 253 | memcpy(packet.command_data.data(), buffer.data(), buffer.size()); | 258 | memcpy(packet.command_data.data(), buffer.data(), buffer.size()); |
| 254 | 259 | ||
| 255 | auto result = SendData(packet); | 260 | auto result = SendData(packet); |
| 256 | 261 | ||
| 257 | if (result != DriverResult::Success) { | 262 | if (result != Common::Input::DriverResult::Success) { |
| 258 | return result; | 263 | return result; |
| 259 | } | 264 | } |
| 260 | 265 | ||
| 261 | result = GetMCUDataResponse(report_mode, output); | 266 | result = GetMCUDataResponse(report_mode, output); |
| 262 | 267 | ||
| 263 | return DriverResult::Success; | 268 | return Common::Input::DriverResult::Success; |
| 264 | } | 269 | } |
| 265 | 270 | ||
| 266 | DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) { | 271 | Common::Input::DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, |
| 272 | MCUMode mode) { | ||
| 267 | MCUCommandResponse output{}; | 273 | MCUCommandResponse output{}; |
| 268 | constexpr std::size_t MaxTries{16}; | 274 | constexpr std::size_t MaxTries{16}; |
| 269 | std::size_t tries{}; | 275 | std::size_t tries{}; |
| @@ -271,17 +277,17 @@ DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMod | |||
| 271 | do { | 277 | do { |
| 272 | const auto result = SendMCUData(report_mode, MCUSubCommand::SetDeviceMode, {}, output); | 278 | const auto result = SendMCUData(report_mode, MCUSubCommand::SetDeviceMode, {}, output); |
| 273 | 279 | ||
| 274 | if (result != DriverResult::Success) { | 280 | if (result != Common::Input::DriverResult::Success) { |
| 275 | return result; | 281 | return result; |
| 276 | } | 282 | } |
| 277 | 283 | ||
| 278 | if (tries++ > MaxTries) { | 284 | if (tries++ > MaxTries) { |
| 279 | return DriverResult::WrongReply; | 285 | return Common::Input::DriverResult::WrongReply; |
| 280 | } | 286 | } |
| 281 | } while (output.mcu_report != MCUReport::StateReport || | 287 | } while (output.mcu_report != MCUReport::StateReport || |
| 282 | output.mcu_data[6] != static_cast<u8>(mode)); | 288 | output.mcu_data[6] != static_cast<u8>(mode)); |
| 283 | 289 | ||
| 284 | return DriverResult::Success; | 290 | return Common::Input::DriverResult::Success; |
| 285 | } | 291 | } |
| 286 | 292 | ||
| 287 | // crc-8-ccitt / polynomial 0x07 look up table | 293 | // crc-8-ccitt / polynomial 0x07 look up table |
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.h b/src/input_common/helpers/joycon_protocol/common_protocol.h index 411ec018a..dd667ca2b 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.h +++ b/src/input_common/helpers/joycon_protocol/common_protocol.h | |||
| @@ -38,30 +38,30 @@ public: | |||
| 38 | * Sends a request to obtain the joycon type from device | 38 | * Sends a request to obtain the joycon type from device |
| 39 | * @returns controller type of the joycon | 39 | * @returns controller type of the joycon |
| 40 | */ | 40 | */ |
| 41 | DriverResult GetDeviceType(ControllerType& controller_type); | 41 | Common::Input::DriverResult GetDeviceType(ControllerType& controller_type); |
| 42 | 42 | ||
| 43 | /** | 43 | /** |
| 44 | * Verifies and sets the joycon_handle if device is valid | 44 | * Verifies and sets the joycon_handle if device is valid |
| 45 | * @param device info from the driver | 45 | * @param device info from the driver |
| 46 | * @returns success if the device is valid | 46 | * @returns success if the device is valid |
| 47 | */ | 47 | */ |
| 48 | DriverResult CheckDeviceAccess(SDL_hid_device_info* device); | 48 | Common::Input::DriverResult CheckDeviceAccess(SDL_hid_device_info* device); |
| 49 | 49 | ||
| 50 | /** | 50 | /** |
| 51 | * Sends a request to set the polling mode of the joycon | 51 | * Sends a request to set the polling mode of the joycon |
| 52 | * @param report_mode polling mode to be set | 52 | * @param report_mode polling mode to be set |
| 53 | */ | 53 | */ |
| 54 | DriverResult SetReportMode(Joycon::ReportMode report_mode); | 54 | Common::Input::DriverResult SetReportMode(Joycon::ReportMode report_mode); |
| 55 | 55 | ||
| 56 | /** | 56 | /** |
| 57 | * Sends data to the joycon device | 57 | * Sends data to the joycon device |
| 58 | * @param buffer data to be send | 58 | * @param buffer data to be send |
| 59 | */ | 59 | */ |
| 60 | DriverResult SendRawData(std::span<const u8> buffer); | 60 | Common::Input::DriverResult SendRawData(std::span<const u8> buffer); |
| 61 | 61 | ||
| 62 | template <typename Output> | 62 | template <typename Output> |
| 63 | requires std::is_trivially_copyable_v<Output> | 63 | requires std::is_trivially_copyable_v<Output> |
| 64 | DriverResult SendData(const Output& output) { | 64 | Common::Input::DriverResult SendData(const Output& output) { |
| 65 | std::array<u8, sizeof(Output)> buffer; | 65 | std::array<u8, sizeof(Output)> buffer; |
| 66 | std::memcpy(buffer.data(), &output, sizeof(Output)); | 66 | std::memcpy(buffer.data(), &output, sizeof(Output)); |
| 67 | return SendRawData(buffer); | 67 | return SendRawData(buffer); |
| @@ -72,7 +72,8 @@ public: | |||
| 72 | * @param sub_command type of data to be returned | 72 | * @param sub_command type of data to be returned |
| 73 | * @returns a buffer containing the response | 73 | * @returns a buffer containing the response |
| 74 | */ | 74 | */ |
| 75 | DriverResult GetSubCommandResponse(SubCommand sub_command, SubCommandResponse& output); | 75 | Common::Input::DriverResult GetSubCommandResponse(SubCommand sub_command, |
| 76 | SubCommandResponse& output); | ||
| 76 | 77 | ||
| 77 | /** | 78 | /** |
| 78 | * Sends a sub command to the device and waits for it's reply | 79 | * Sends a sub command to the device and waits for it's reply |
| @@ -80,35 +81,35 @@ public: | |||
| 80 | * @param buffer data to be send | 81 | * @param buffer data to be send |
| 81 | * @returns output buffer containing the response | 82 | * @returns output buffer containing the response |
| 82 | */ | 83 | */ |
| 83 | DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer, | 84 | Common::Input::DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer, |
| 84 | SubCommandResponse& output); | 85 | SubCommandResponse& output); |
| 85 | 86 | ||
| 86 | /** | 87 | /** |
| 87 | * Sends a sub command to the device and waits for it's reply and ignores the output | 88 | * Sends a sub command to the device and waits for it's reply and ignores the output |
| 88 | * @param sc sub command to be send | 89 | * @param sc sub command to be send |
| 89 | * @param buffer data to be send | 90 | * @param buffer data to be send |
| 90 | */ | 91 | */ |
| 91 | DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer); | 92 | Common::Input::DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer); |
| 92 | 93 | ||
| 93 | /** | 94 | /** |
| 94 | * Sends a mcu command to the device | 95 | * Sends a mcu command to the device |
| 95 | * @param sc sub command to be send | 96 | * @param sc sub command to be send |
| 96 | * @param buffer data to be send | 97 | * @param buffer data to be send |
| 97 | */ | 98 | */ |
| 98 | DriverResult SendMCUCommand(SubCommand sc, std::span<const u8> buffer); | 99 | Common::Input::DriverResult SendMCUCommand(SubCommand sc, std::span<const u8> buffer); |
| 99 | 100 | ||
| 100 | /** | 101 | /** |
| 101 | * Sends vibration data to the joycon | 102 | * Sends vibration data to the joycon |
| 102 | * @param buffer data to be send | 103 | * @param buffer data to be send |
| 103 | */ | 104 | */ |
| 104 | DriverResult SendVibrationReport(std::span<const u8> buffer); | 105 | Common::Input::DriverResult SendVibrationReport(std::span<const u8> buffer); |
| 105 | 106 | ||
| 106 | /** | 107 | /** |
| 107 | * Reads the SPI memory stored on the joycon | 108 | * Reads the SPI memory stored on the joycon |
| 108 | * @param Initial address location | 109 | * @param Initial address location |
| 109 | * @returns output buffer containing the response | 110 | * @returns output buffer containing the response |
| 110 | */ | 111 | */ |
| 111 | DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output); | 112 | Common::Input::DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output); |
| 112 | 113 | ||
| 113 | /** | 114 | /** |
| 114 | * Reads the SPI memory stored on the joycon | 115 | * Reads the SPI memory stored on the joycon |
| @@ -117,37 +118,38 @@ public: | |||
| 117 | */ | 118 | */ |
| 118 | template <typename Output> | 119 | template <typename Output> |
| 119 | requires std::is_trivially_copyable_v<Output> | 120 | requires std::is_trivially_copyable_v<Output> |
| 120 | DriverResult ReadSPI(SpiAddress addr, Output& output) { | 121 | Common::Input::DriverResult ReadSPI(SpiAddress addr, Output& output) { |
| 121 | std::array<u8, sizeof(Output)> buffer; | 122 | std::array<u8, sizeof(Output)> buffer; |
| 122 | output = {}; | 123 | output = {}; |
| 123 | 124 | ||
| 124 | const auto result = ReadRawSPI(addr, buffer); | 125 | const auto result = ReadRawSPI(addr, buffer); |
| 125 | if (result != DriverResult::Success) { | 126 | if (result != Common::Input::DriverResult::Success) { |
| 126 | return result; | 127 | return result; |
| 127 | } | 128 | } |
| 128 | 129 | ||
| 129 | std::memcpy(&output, buffer.data(), sizeof(Output)); | 130 | std::memcpy(&output, buffer.data(), sizeof(Output)); |
| 130 | return DriverResult::Success; | 131 | return Common::Input::DriverResult::Success; |
| 131 | } | 132 | } |
| 132 | 133 | ||
| 133 | /** | 134 | /** |
| 134 | * Enables MCU chip on the joycon | 135 | * Enables MCU chip on the joycon |
| 135 | * @param enable if true the chip will be enabled | 136 | * @param enable if true the chip will be enabled |
| 136 | */ | 137 | */ |
| 137 | DriverResult EnableMCU(bool enable); | 138 | Common::Input::DriverResult EnableMCU(bool enable); |
| 138 | 139 | ||
| 139 | /** | 140 | /** |
| 140 | * Configures the MCU to the corresponding mode | 141 | * Configures the MCU to the corresponding mode |
| 141 | * @param MCUConfig configuration | 142 | * @param MCUConfig configuration |
| 142 | */ | 143 | */ |
| 143 | DriverResult ConfigureMCU(const MCUConfig& config); | 144 | Common::Input::DriverResult ConfigureMCU(const MCUConfig& config); |
| 144 | 145 | ||
| 145 | /** | 146 | /** |
| 146 | * Waits until there's MCU data available. On timeout returns error | 147 | * Waits until there's MCU data available. On timeout returns error |
| 147 | * @param report mode of the expected reply | 148 | * @param report mode of the expected reply |
| 148 | * @returns a buffer containing the response | 149 | * @returns a buffer containing the response |
| 149 | */ | 150 | */ |
| 150 | DriverResult GetMCUDataResponse(ReportMode report_mode_, MCUCommandResponse& output); | 151 | Common::Input::DriverResult GetMCUDataResponse(ReportMode report_mode_, |
| 152 | MCUCommandResponse& output); | ||
| 151 | 153 | ||
| 152 | /** | 154 | /** |
| 153 | * Sends data to the MCU chip and waits for it's reply | 155 | * Sends data to the MCU chip and waits for it's reply |
| @@ -156,15 +158,15 @@ public: | |||
| 156 | * @param buffer data to be send | 158 | * @param buffer data to be send |
| 157 | * @returns output buffer containing the response | 159 | * @returns output buffer containing the response |
| 158 | */ | 160 | */ |
| 159 | DriverResult SendMCUData(ReportMode report_mode, MCUSubCommand sc, std::span<const u8> buffer, | 161 | Common::Input::DriverResult SendMCUData(ReportMode report_mode, MCUSubCommand sc, |
| 160 | MCUCommandResponse& output); | 162 | std::span<const u8> buffer, MCUCommandResponse& output); |
| 161 | 163 | ||
| 162 | /** | 164 | /** |
| 163 | * Wait's until the MCU chip is on the specified mode | 165 | * Wait's until the MCU chip is on the specified mode |
| 164 | * @param report mode of the expected reply | 166 | * @param report mode of the expected reply |
| 165 | * @param MCUMode configuration | 167 | * @param MCUMode configuration |
| 166 | */ | 168 | */ |
| 167 | DriverResult WaitSetMCUMode(ReportMode report_mode, MCUMode mode); | 169 | Common::Input::DriverResult WaitSetMCUMode(ReportMode report_mode, MCUMode mode); |
| 168 | 170 | ||
| 169 | /** | 171 | /** |
| 170 | * Calculates the checksum from the MCU data | 172 | * Calculates the checksum from the MCU data |
diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.cpp b/src/input_common/helpers/joycon_protocol/generic_functions.cpp index 548a4b9e3..e9a056448 100644 --- a/src/input_common/helpers/joycon_protocol/generic_functions.cpp +++ b/src/input_common/helpers/joycon_protocol/generic_functions.cpp | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2022 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/input.h" | ||
| 4 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 5 | #include "input_common/helpers/joycon_protocol/generic_functions.h" | 6 | #include "input_common/helpers/joycon_protocol/generic_functions.h" |
| 6 | 7 | ||
| @@ -9,73 +10,74 @@ namespace InputCommon::Joycon { | |||
| 9 | GenericProtocol::GenericProtocol(std::shared_ptr<JoyconHandle> handle) | 10 | GenericProtocol::GenericProtocol(std::shared_ptr<JoyconHandle> handle) |
| 10 | : JoyconCommonProtocol(std::move(handle)) {} | 11 | : JoyconCommonProtocol(std::move(handle)) {} |
| 11 | 12 | ||
| 12 | DriverResult GenericProtocol::EnablePassiveMode() { | 13 | Common::Input::DriverResult GenericProtocol::EnablePassiveMode() { |
| 13 | ScopedSetBlocking sb(this); | 14 | ScopedSetBlocking sb(this); |
| 14 | return SetReportMode(ReportMode::SIMPLE_HID_MODE); | 15 | return SetReportMode(ReportMode::SIMPLE_HID_MODE); |
| 15 | } | 16 | } |
| 16 | 17 | ||
| 17 | DriverResult GenericProtocol::EnableActiveMode() { | 18 | Common::Input::DriverResult GenericProtocol::EnableActiveMode() { |
| 18 | ScopedSetBlocking sb(this); | 19 | ScopedSetBlocking sb(this); |
| 19 | return SetReportMode(ReportMode::STANDARD_FULL_60HZ); | 20 | return SetReportMode(ReportMode::STANDARD_FULL_60HZ); |
| 20 | } | 21 | } |
| 21 | 22 | ||
| 22 | DriverResult GenericProtocol::SetLowPowerMode(bool enable) { | 23 | Common::Input::DriverResult GenericProtocol::SetLowPowerMode(bool enable) { |
| 23 | ScopedSetBlocking sb(this); | 24 | ScopedSetBlocking sb(this); |
| 24 | const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)}; | 25 | const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)}; |
| 25 | return SendSubCommand(SubCommand::LOW_POWER_MODE, buffer); | 26 | return SendSubCommand(SubCommand::LOW_POWER_MODE, buffer); |
| 26 | } | 27 | } |
| 27 | 28 | ||
| 28 | DriverResult GenericProtocol::TriggersElapsed() { | 29 | Common::Input::DriverResult GenericProtocol::TriggersElapsed() { |
| 29 | ScopedSetBlocking sb(this); | 30 | ScopedSetBlocking sb(this); |
| 30 | return SendSubCommand(SubCommand::TRIGGERS_ELAPSED, {}); | 31 | return SendSubCommand(SubCommand::TRIGGERS_ELAPSED, {}); |
| 31 | } | 32 | } |
| 32 | 33 | ||
| 33 | DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) { | 34 | Common::Input::DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) { |
| 34 | ScopedSetBlocking sb(this); | 35 | ScopedSetBlocking sb(this); |
| 35 | SubCommandResponse output{}; | 36 | SubCommandResponse output{}; |
| 36 | 37 | ||
| 37 | const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output); | 38 | const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output); |
| 38 | 39 | ||
| 39 | device_info = {}; | 40 | device_info = {}; |
| 40 | if (result == DriverResult::Success) { | 41 | if (result == Common::Input::DriverResult::Success) { |
| 41 | device_info = output.device_info; | 42 | device_info = output.device_info; |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | return result; | 45 | return result; |
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) { | 48 | Common::Input::DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) { |
| 48 | return GetDeviceType(controller_type); | 49 | return GetDeviceType(controller_type); |
| 49 | } | 50 | } |
| 50 | 51 | ||
| 51 | DriverResult GenericProtocol::EnableImu(bool enable) { | 52 | Common::Input::DriverResult GenericProtocol::EnableImu(bool enable) { |
| 52 | ScopedSetBlocking sb(this); | 53 | ScopedSetBlocking sb(this); |
| 53 | const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)}; | 54 | const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)}; |
| 54 | return SendSubCommand(SubCommand::ENABLE_IMU, buffer); | 55 | return SendSubCommand(SubCommand::ENABLE_IMU, buffer); |
| 55 | } | 56 | } |
| 56 | 57 | ||
| 57 | DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec, | 58 | Common::Input::DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen, |
| 58 | AccelerometerSensitivity asen, | 59 | GyroPerformance gfrec, |
| 59 | AccelerometerPerformance afrec) { | 60 | AccelerometerSensitivity asen, |
| 61 | AccelerometerPerformance afrec) { | ||
| 60 | ScopedSetBlocking sb(this); | 62 | ScopedSetBlocking sb(this); |
| 61 | const std::array<u8, 4> buffer{static_cast<u8>(gsen), static_cast<u8>(asen), | 63 | const std::array<u8, 4> buffer{static_cast<u8>(gsen), static_cast<u8>(asen), |
| 62 | static_cast<u8>(gfrec), static_cast<u8>(afrec)}; | 64 | static_cast<u8>(gfrec), static_cast<u8>(afrec)}; |
| 63 | return SendSubCommand(SubCommand::SET_IMU_SENSITIVITY, buffer); | 65 | return SendSubCommand(SubCommand::SET_IMU_SENSITIVITY, buffer); |
| 64 | } | 66 | } |
| 65 | 67 | ||
| 66 | DriverResult GenericProtocol::GetBattery(u32& battery_level) { | 68 | Common::Input::DriverResult GenericProtocol::GetBattery(u32& battery_level) { |
| 67 | // This function is meant to request the high resolution battery status | 69 | // This function is meant to request the high resolution battery status |
| 68 | battery_level = 0; | 70 | battery_level = 0; |
| 69 | return DriverResult::NotSupported; | 71 | return Common::Input::DriverResult::NotSupported; |
| 70 | } | 72 | } |
| 71 | 73 | ||
| 72 | DriverResult GenericProtocol::GetColor(Color& color) { | 74 | Common::Input::DriverResult GenericProtocol::GetColor(Color& color) { |
| 73 | ScopedSetBlocking sb(this); | 75 | ScopedSetBlocking sb(this); |
| 74 | std::array<u8, 12> buffer{}; | 76 | std::array<u8, 12> buffer{}; |
| 75 | const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer); | 77 | const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer); |
| 76 | 78 | ||
| 77 | color = {}; | 79 | color = {}; |
| 78 | if (result == DriverResult::Success) { | 80 | if (result == Common::Input::DriverResult::Success) { |
| 79 | color.body = static_cast<u32>((buffer[0] << 16) | (buffer[1] << 8) | buffer[2]); | 81 | color.body = static_cast<u32>((buffer[0] << 16) | (buffer[1] << 8) | buffer[2]); |
| 80 | color.buttons = static_cast<u32>((buffer[3] << 16) | (buffer[4] << 8) | buffer[5]); | 82 | color.buttons = static_cast<u32>((buffer[3] << 16) | (buffer[4] << 8) | buffer[5]); |
| 81 | color.left_grip = static_cast<u32>((buffer[6] << 16) | (buffer[7] << 8) | buffer[8]); | 83 | color.left_grip = static_cast<u32>((buffer[6] << 16) | (buffer[7] << 8) | buffer[8]); |
| @@ -85,26 +87,26 @@ DriverResult GenericProtocol::GetColor(Color& color) { | |||
| 85 | return result; | 87 | return result; |
| 86 | } | 88 | } |
| 87 | 89 | ||
| 88 | DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) { | 90 | Common::Input::DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) { |
| 89 | ScopedSetBlocking sb(this); | 91 | ScopedSetBlocking sb(this); |
| 90 | std::array<u8, 16> buffer{}; | 92 | std::array<u8, 16> buffer{}; |
| 91 | const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer); | 93 | const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer); |
| 92 | 94 | ||
| 93 | serial_number = {}; | 95 | serial_number = {}; |
| 94 | if (result == DriverResult::Success) { | 96 | if (result == Common::Input::DriverResult::Success) { |
| 95 | memcpy(serial_number.data(), buffer.data() + 1, sizeof(SerialNumber)); | 97 | memcpy(serial_number.data(), buffer.data() + 1, sizeof(SerialNumber)); |
| 96 | } | 98 | } |
| 97 | 99 | ||
| 98 | return result; | 100 | return result; |
| 99 | } | 101 | } |
| 100 | 102 | ||
| 101 | DriverResult GenericProtocol::GetTemperature(u32& temperature) { | 103 | Common::Input::DriverResult GenericProtocol::GetTemperature(u32& temperature) { |
| 102 | // Not all devices have temperature sensor | 104 | // Not all devices have temperature sensor |
| 103 | temperature = 25; | 105 | temperature = 25; |
| 104 | return DriverResult::NotSupported; | 106 | return Common::Input::DriverResult::NotSupported; |
| 105 | } | 107 | } |
| 106 | 108 | ||
| 107 | DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) { | 109 | Common::Input::DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) { |
| 108 | DeviceInfo device_info{}; | 110 | DeviceInfo device_info{}; |
| 109 | 111 | ||
| 110 | const auto result = GetDeviceInfo(device_info); | 112 | const auto result = GetDeviceInfo(device_info); |
| @@ -113,23 +115,23 @@ DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) { | |||
| 113 | return result; | 115 | return result; |
| 114 | } | 116 | } |
| 115 | 117 | ||
| 116 | DriverResult GenericProtocol::SetHomeLight() { | 118 | Common::Input::DriverResult GenericProtocol::SetHomeLight() { |
| 117 | ScopedSetBlocking sb(this); | 119 | ScopedSetBlocking sb(this); |
| 118 | static constexpr std::array<u8, 3> buffer{0x0f, 0xf0, 0x00}; | 120 | static constexpr std::array<u8, 3> buffer{0x0f, 0xf0, 0x00}; |
| 119 | return SendSubCommand(SubCommand::SET_HOME_LIGHT, buffer); | 121 | return SendSubCommand(SubCommand::SET_HOME_LIGHT, buffer); |
| 120 | } | 122 | } |
| 121 | 123 | ||
| 122 | DriverResult GenericProtocol::SetLedBusy() { | 124 | Common::Input::DriverResult GenericProtocol::SetLedBusy() { |
| 123 | return DriverResult::NotSupported; | 125 | return Common::Input::DriverResult::NotSupported; |
| 124 | } | 126 | } |
| 125 | 127 | ||
| 126 | DriverResult GenericProtocol::SetLedPattern(u8 leds) { | 128 | Common::Input::DriverResult GenericProtocol::SetLedPattern(u8 leds) { |
| 127 | ScopedSetBlocking sb(this); | 129 | ScopedSetBlocking sb(this); |
| 128 | const std::array<u8, 1> buffer{leds}; | 130 | const std::array<u8, 1> buffer{leds}; |
| 129 | return SendSubCommand(SubCommand::SET_PLAYER_LIGHTS, buffer); | 131 | return SendSubCommand(SubCommand::SET_PLAYER_LIGHTS, buffer); |
| 130 | } | 132 | } |
| 131 | 133 | ||
| 132 | DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) { | 134 | Common::Input::DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) { |
| 133 | return SetLedPattern(static_cast<u8>(leds << 4)); | 135 | return SetLedPattern(static_cast<u8>(leds << 4)); |
| 134 | } | 136 | } |
| 135 | 137 | ||
diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.h b/src/input_common/helpers/joycon_protocol/generic_functions.h index 424831e81..90fcd17f6 100644 --- a/src/input_common/helpers/joycon_protocol/generic_functions.h +++ b/src/input_common/helpers/joycon_protocol/generic_functions.h | |||
| @@ -11,6 +11,10 @@ | |||
| 11 | #include "input_common/helpers/joycon_protocol/common_protocol.h" | 11 | #include "input_common/helpers/joycon_protocol/common_protocol.h" |
| 12 | #include "input_common/helpers/joycon_protocol/joycon_types.h" | 12 | #include "input_common/helpers/joycon_protocol/joycon_types.h" |
| 13 | 13 | ||
| 14 | namespace Common::Input { | ||
| 15 | enum class DriverResult; | ||
| 16 | } | ||
| 17 | |||
| 14 | namespace InputCommon::Joycon { | 18 | namespace InputCommon::Joycon { |
| 15 | 19 | ||
| 16 | /// Joycon driver functions that easily implemented | 20 | /// Joycon driver functions that easily implemented |
| @@ -20,34 +24,34 @@ public: | |||
| 20 | 24 | ||
| 21 | /// Enables passive mode. This mode only sends button data on change. Sticks will return digital | 25 | /// Enables passive mode. This mode only sends button data on change. Sticks will return digital |
| 22 | /// data instead of analog. Motion will be disabled | 26 | /// data instead of analog. Motion will be disabled |
| 23 | DriverResult EnablePassiveMode(); | 27 | Common::Input::DriverResult EnablePassiveMode(); |
| 24 | 28 | ||
| 25 | /// Enables active mode. This mode will return the current status every 5-15ms | 29 | /// Enables active mode. This mode will return the current status every 5-15ms |
| 26 | DriverResult EnableActiveMode(); | 30 | Common::Input::DriverResult EnableActiveMode(); |
| 27 | 31 | ||
| 28 | /// Enables or disables the low power mode | 32 | /// Enables or disables the low power mode |
| 29 | DriverResult SetLowPowerMode(bool enable); | 33 | Common::Input::DriverResult SetLowPowerMode(bool enable); |
| 30 | 34 | ||
| 31 | /// Unknown function used by the switch | 35 | /// Unknown function used by the switch |
| 32 | DriverResult TriggersElapsed(); | 36 | Common::Input::DriverResult TriggersElapsed(); |
| 33 | 37 | ||
| 34 | /** | 38 | /** |
| 35 | * Sends a request to obtain the joycon firmware and mac from handle | 39 | * Sends a request to obtain the joycon firmware and mac from handle |
| 36 | * @returns controller device info | 40 | * @returns controller device info |
| 37 | */ | 41 | */ |
| 38 | DriverResult GetDeviceInfo(DeviceInfo& controller_type); | 42 | Common::Input::DriverResult GetDeviceInfo(DeviceInfo& controller_type); |
| 39 | 43 | ||
| 40 | /** | 44 | /** |
| 41 | * Sends a request to obtain the joycon type from handle | 45 | * Sends a request to obtain the joycon type from handle |
| 42 | * @returns controller type of the joycon | 46 | * @returns controller type of the joycon |
| 43 | */ | 47 | */ |
| 44 | DriverResult GetControllerType(ControllerType& controller_type); | 48 | Common::Input::DriverResult GetControllerType(ControllerType& controller_type); |
| 45 | 49 | ||
| 46 | /** | 50 | /** |
| 47 | * Enables motion input | 51 | * Enables motion input |
| 48 | * @param enable if true motion data will be enabled | 52 | * @param enable if true motion data will be enabled |
| 49 | */ | 53 | */ |
| 50 | DriverResult EnableImu(bool enable); | 54 | Common::Input::DriverResult EnableImu(bool enable); |
| 51 | 55 | ||
| 52 | /** | 56 | /** |
| 53 | * Configures the motion sensor with the specified parameters | 57 | * Configures the motion sensor with the specified parameters |
| @@ -56,59 +60,60 @@ public: | |||
| 56 | * @param asen accelerometer sensitivity in G force | 60 | * @param asen accelerometer sensitivity in G force |
| 57 | * @param afrec accelerometer frequency in hertz | 61 | * @param afrec accelerometer frequency in hertz |
| 58 | */ | 62 | */ |
| 59 | DriverResult SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec, | 63 | Common::Input::DriverResult SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec, |
| 60 | AccelerometerSensitivity asen, AccelerometerPerformance afrec); | 64 | AccelerometerSensitivity asen, |
| 65 | AccelerometerPerformance afrec); | ||
| 61 | 66 | ||
| 62 | /** | 67 | /** |
| 63 | * Request battery level from the device | 68 | * Request battery level from the device |
| 64 | * @returns battery level | 69 | * @returns battery level |
| 65 | */ | 70 | */ |
| 66 | DriverResult GetBattery(u32& battery_level); | 71 | Common::Input::DriverResult GetBattery(u32& battery_level); |
| 67 | 72 | ||
| 68 | /** | 73 | /** |
| 69 | * Request joycon colors from the device | 74 | * Request joycon colors from the device |
| 70 | * @returns colors of the body and buttons | 75 | * @returns colors of the body and buttons |
| 71 | */ | 76 | */ |
| 72 | DriverResult GetColor(Color& color); | 77 | Common::Input::DriverResult GetColor(Color& color); |
| 73 | 78 | ||
| 74 | /** | 79 | /** |
| 75 | * Request joycon serial number from the device | 80 | * Request joycon serial number from the device |
| 76 | * @returns 16 byte serial number | 81 | * @returns 16 byte serial number |
| 77 | */ | 82 | */ |
| 78 | DriverResult GetSerialNumber(SerialNumber& serial_number); | 83 | Common::Input::DriverResult GetSerialNumber(SerialNumber& serial_number); |
| 79 | 84 | ||
| 80 | /** | 85 | /** |
| 81 | * Request joycon serial number from the device | 86 | * Request joycon serial number from the device |
| 82 | * @returns 16 byte serial number | 87 | * @returns 16 byte serial number |
| 83 | */ | 88 | */ |
| 84 | DriverResult GetTemperature(u32& temperature); | 89 | Common::Input::DriverResult GetTemperature(u32& temperature); |
| 85 | 90 | ||
| 86 | /** | 91 | /** |
| 87 | * Request joycon serial number from the device | 92 | * Request joycon serial number from the device |
| 88 | * @returns 16 byte serial number | 93 | * @returns 16 byte serial number |
| 89 | */ | 94 | */ |
| 90 | DriverResult GetVersionNumber(FirmwareVersion& version); | 95 | Common::Input::DriverResult GetVersionNumber(FirmwareVersion& version); |
| 91 | 96 | ||
| 92 | /** | 97 | /** |
| 93 | * Sets home led behaviour | 98 | * Sets home led behaviour |
| 94 | */ | 99 | */ |
| 95 | DriverResult SetHomeLight(); | 100 | Common::Input::DriverResult SetHomeLight(); |
| 96 | 101 | ||
| 97 | /** | 102 | /** |
| 98 | * Sets home led into a slow breathing state | 103 | * Sets home led into a slow breathing state |
| 99 | */ | 104 | */ |
| 100 | DriverResult SetLedBusy(); | 105 | Common::Input::DriverResult SetLedBusy(); |
| 101 | 106 | ||
| 102 | /** | 107 | /** |
| 103 | * Sets the 4 player leds on the joycon on a solid state | 108 | * Sets the 4 player leds on the joycon on a solid state |
| 104 | * @params bit flag containing the led state | 109 | * @params bit flag containing the led state |
| 105 | */ | 110 | */ |
| 106 | DriverResult SetLedPattern(u8 leds); | 111 | Common::Input::DriverResult SetLedPattern(u8 leds); |
| 107 | 112 | ||
| 108 | /** | 113 | /** |
| 109 | * Sets the 4 player leds on the joycon on a blinking state | 114 | * Sets the 4 player leds on the joycon on a blinking state |
| 110 | * @returns bit flag containing the led state | 115 | * @returns bit flag containing the led state |
| 111 | */ | 116 | */ |
| 112 | DriverResult SetLedBlinkPattern(u8 leds); | 117 | Common::Input::DriverResult SetLedBlinkPattern(u8 leds); |
| 113 | }; | 118 | }; |
| 114 | } // namespace InputCommon::Joycon | 119 | } // namespace InputCommon::Joycon |
diff --git a/src/input_common/helpers/joycon_protocol/irs.cpp b/src/input_common/helpers/joycon_protocol/irs.cpp index 731fd5981..68b0589e3 100644 --- a/src/input_common/helpers/joycon_protocol/irs.cpp +++ b/src/input_common/helpers/joycon_protocol/irs.cpp | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2022 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 <thread> | 4 | #include "common/input.h" |
| 5 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 6 | #include "input_common/helpers/joycon_protocol/irs.h" | 6 | #include "input_common/helpers/joycon_protocol/irs.h" |
| 7 | 7 | ||
| @@ -10,21 +10,21 @@ namespace InputCommon::Joycon { | |||
| 10 | IrsProtocol::IrsProtocol(std::shared_ptr<JoyconHandle> handle) | 10 | IrsProtocol::IrsProtocol(std::shared_ptr<JoyconHandle> handle) |
| 11 | : JoyconCommonProtocol(std::move(handle)) {} | 11 | : JoyconCommonProtocol(std::move(handle)) {} |
| 12 | 12 | ||
| 13 | DriverResult IrsProtocol::EnableIrs() { | 13 | Common::Input::DriverResult IrsProtocol::EnableIrs() { |
| 14 | LOG_INFO(Input, "Enable IRS"); | 14 | LOG_INFO(Input, "Enable IRS"); |
| 15 | ScopedSetBlocking sb(this); | 15 | ScopedSetBlocking sb(this); |
| 16 | DriverResult result{DriverResult::Success}; | 16 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; |
| 17 | 17 | ||
| 18 | if (result == DriverResult::Success) { | 18 | if (result == Common::Input::DriverResult::Success) { |
| 19 | result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ); | 19 | result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ); |
| 20 | } | 20 | } |
| 21 | if (result == DriverResult::Success) { | 21 | if (result == Common::Input::DriverResult::Success) { |
| 22 | result = EnableMCU(true); | 22 | result = EnableMCU(true); |
| 23 | } | 23 | } |
| 24 | if (result == DriverResult::Success) { | 24 | if (result == Common::Input::DriverResult::Success) { |
| 25 | result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby); | 25 | result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby); |
| 26 | } | 26 | } |
| 27 | if (result == DriverResult::Success) { | 27 | if (result == Common::Input::DriverResult::Success) { |
| 28 | const MCUConfig config{ | 28 | const MCUConfig config{ |
| 29 | .command = MCUCommand::ConfigureMCU, | 29 | .command = MCUCommand::ConfigureMCU, |
| 30 | .sub_command = MCUSubCommand::SetMCUMode, | 30 | .sub_command = MCUSubCommand::SetMCUMode, |
| @@ -34,16 +34,16 @@ DriverResult IrsProtocol::EnableIrs() { | |||
| 34 | 34 | ||
| 35 | result = ConfigureMCU(config); | 35 | result = ConfigureMCU(config); |
| 36 | } | 36 | } |
| 37 | if (result == DriverResult::Success) { | 37 | if (result == Common::Input::DriverResult::Success) { |
| 38 | result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::IR); | 38 | result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::IR); |
| 39 | } | 39 | } |
| 40 | if (result == DriverResult::Success) { | 40 | if (result == Common::Input::DriverResult::Success) { |
| 41 | result = ConfigureIrs(); | 41 | result = ConfigureIrs(); |
| 42 | } | 42 | } |
| 43 | if (result == DriverResult::Success) { | 43 | if (result == Common::Input::DriverResult::Success) { |
| 44 | result = WriteRegistersStep1(); | 44 | result = WriteRegistersStep1(); |
| 45 | } | 45 | } |
| 46 | if (result == DriverResult::Success) { | 46 | if (result == Common::Input::DriverResult::Success) { |
| 47 | result = WriteRegistersStep2(); | 47 | result = WriteRegistersStep2(); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| @@ -52,12 +52,12 @@ DriverResult IrsProtocol::EnableIrs() { | |||
| 52 | return result; | 52 | return result; |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | DriverResult IrsProtocol::DisableIrs() { | 55 | Common::Input::DriverResult IrsProtocol::DisableIrs() { |
| 56 | LOG_DEBUG(Input, "Disable IRS"); | 56 | LOG_DEBUG(Input, "Disable IRS"); |
| 57 | ScopedSetBlocking sb(this); | 57 | ScopedSetBlocking sb(this); |
| 58 | DriverResult result{DriverResult::Success}; | 58 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; |
| 59 | 59 | ||
| 60 | if (result == DriverResult::Success) { | 60 | if (result == Common::Input::DriverResult::Success) { |
| 61 | result = EnableMCU(false); | 61 | result = EnableMCU(false); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| @@ -66,7 +66,7 @@ DriverResult IrsProtocol::DisableIrs() { | |||
| 66 | return result; | 66 | return result; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) { | 69 | Common::Input::DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) { |
| 70 | irs_mode = mode; | 70 | irs_mode = mode; |
| 71 | switch (format) { | 71 | switch (format) { |
| 72 | case IrsResolution::Size320x240: | 72 | case IrsResolution::Size320x240: |
| @@ -103,10 +103,10 @@ DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) { | |||
| 103 | return EnableIrs(); | 103 | return EnableIrs(); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | return DriverResult::Success; | 106 | return Common::Input::DriverResult::Success; |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) { | 109 | Common::Input::DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) { |
| 110 | const u8 next_packet_fragment = | 110 | const u8 next_packet_fragment = |
| 111 | static_cast<u8>((packet_fragment + 1) % (static_cast<u8>(fragments) + 1)); | 111 | static_cast<u8>((packet_fragment + 1) % (static_cast<u8>(fragments) + 1)); |
| 112 | 112 | ||
| @@ -129,7 +129,7 @@ DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) { | |||
| 129 | return RequestFrame(packet_fragment); | 129 | return RequestFrame(packet_fragment); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | DriverResult IrsProtocol::ConfigureIrs() { | 132 | Common::Input::DriverResult IrsProtocol::ConfigureIrs() { |
| 133 | LOG_DEBUG(Input, "Configure IRS"); | 133 | LOG_DEBUG(Input, "Configure IRS"); |
| 134 | constexpr std::size_t max_tries = 28; | 134 | constexpr std::size_t max_tries = 28; |
| 135 | SubCommandResponse output{}; | 135 | SubCommandResponse output{}; |
| @@ -152,20 +152,20 @@ DriverResult IrsProtocol::ConfigureIrs() { | |||
| 152 | do { | 152 | do { |
| 153 | const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); | 153 | const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); |
| 154 | 154 | ||
| 155 | if (result != DriverResult::Success) { | 155 | if (result != Common::Input::DriverResult::Success) { |
| 156 | return result; | 156 | return result; |
| 157 | } | 157 | } |
| 158 | if (tries++ >= max_tries) { | 158 | if (tries++ >= max_tries) { |
| 159 | return DriverResult::WrongReply; | 159 | return Common::Input::DriverResult::WrongReply; |
| 160 | } | 160 | } |
| 161 | } while (output.command_data[0] != 0x0b); | 161 | } while (output.command_data[0] != 0x0b); |
| 162 | 162 | ||
| 163 | return DriverResult::Success; | 163 | return Common::Input::DriverResult::Success; |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | DriverResult IrsProtocol::WriteRegistersStep1() { | 166 | Common::Input::DriverResult IrsProtocol::WriteRegistersStep1() { |
| 167 | LOG_DEBUG(Input, "WriteRegistersStep1"); | 167 | LOG_DEBUG(Input, "WriteRegistersStep1"); |
| 168 | DriverResult result{DriverResult::Success}; | 168 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; |
| 169 | constexpr std::size_t max_tries = 28; | 169 | constexpr std::size_t max_tries = 28; |
| 170 | SubCommandResponse output{}; | 170 | SubCommandResponse output{}; |
| 171 | std::size_t tries = 0; | 171 | std::size_t tries = 0; |
| @@ -197,7 +197,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() { | |||
| 197 | mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36); | 197 | mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36); |
| 198 | mcu_request[37] = 0xFF; | 198 | mcu_request[37] = 0xFF; |
| 199 | 199 | ||
| 200 | if (result != DriverResult::Success) { | 200 | if (result != Common::Input::DriverResult::Success) { |
| 201 | return result; | 201 | return result; |
| 202 | } | 202 | } |
| 203 | 203 | ||
| @@ -205,26 +205,26 @@ DriverResult IrsProtocol::WriteRegistersStep1() { | |||
| 205 | result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); | 205 | result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); |
| 206 | 206 | ||
| 207 | // First time we need to set the report mode | 207 | // First time we need to set the report mode |
| 208 | if (result == DriverResult::Success && tries == 0) { | 208 | if (result == Common::Input::DriverResult::Success && tries == 0) { |
| 209 | result = SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request); | 209 | result = SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request); |
| 210 | } | 210 | } |
| 211 | if (result == DriverResult::Success && tries == 0) { | 211 | if (result == Common::Input::DriverResult::Success && tries == 0) { |
| 212 | GetSubCommandResponse(SubCommand::SET_MCU_CONFIG, output); | 212 | GetSubCommandResponse(SubCommand::SET_MCU_CONFIG, output); |
| 213 | } | 213 | } |
| 214 | 214 | ||
| 215 | if (result != DriverResult::Success) { | 215 | if (result != Common::Input::DriverResult::Success) { |
| 216 | return result; | 216 | return result; |
| 217 | } | 217 | } |
| 218 | if (tries++ >= max_tries) { | 218 | if (tries++ >= max_tries) { |
| 219 | return DriverResult::WrongReply; | 219 | return Common::Input::DriverResult::WrongReply; |
| 220 | } | 220 | } |
| 221 | } while (!(output.command_data[0] == 0x13 && output.command_data[2] == 0x07) && | 221 | } while (!(output.command_data[0] == 0x13 && output.command_data[2] == 0x07) && |
| 222 | output.command_data[0] != 0x23); | 222 | output.command_data[0] != 0x23); |
| 223 | 223 | ||
| 224 | return DriverResult::Success; | 224 | return Common::Input::DriverResult::Success; |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | DriverResult IrsProtocol::WriteRegistersStep2() { | 227 | Common::Input::DriverResult IrsProtocol::WriteRegistersStep2() { |
| 228 | LOG_DEBUG(Input, "WriteRegistersStep2"); | 228 | LOG_DEBUG(Input, "WriteRegistersStep2"); |
| 229 | constexpr std::size_t max_tries = 28; | 229 | constexpr std::size_t max_tries = 28; |
| 230 | SubCommandResponse output{}; | 230 | SubCommandResponse output{}; |
| @@ -255,18 +255,18 @@ DriverResult IrsProtocol::WriteRegistersStep2() { | |||
| 255 | do { | 255 | do { |
| 256 | const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); | 256 | const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); |
| 257 | 257 | ||
| 258 | if (result != DriverResult::Success) { | 258 | if (result != Common::Input::DriverResult::Success) { |
| 259 | return result; | 259 | return result; |
| 260 | } | 260 | } |
| 261 | if (tries++ >= max_tries) { | 261 | if (tries++ >= max_tries) { |
| 262 | return DriverResult::WrongReply; | 262 | return Common::Input::DriverResult::WrongReply; |
| 263 | } | 263 | } |
| 264 | } while (output.command_data[0] != 0x13 && output.command_data[0] != 0x23); | 264 | } while (output.command_data[0] != 0x13 && output.command_data[0] != 0x23); |
| 265 | 265 | ||
| 266 | return DriverResult::Success; | 266 | return Common::Input::DriverResult::Success; |
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | DriverResult IrsProtocol::RequestFrame(u8 frame) { | 269 | Common::Input::DriverResult IrsProtocol::RequestFrame(u8 frame) { |
| 270 | std::array<u8, 38> mcu_request{}; | 270 | std::array<u8, 38> mcu_request{}; |
| 271 | mcu_request[3] = frame; | 271 | mcu_request[3] = frame; |
| 272 | mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36); | 272 | mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36); |
| @@ -274,7 +274,7 @@ DriverResult IrsProtocol::RequestFrame(u8 frame) { | |||
| 274 | return SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request); | 274 | return SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request); |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | DriverResult IrsProtocol::ResendFrame(u8 frame) { | 277 | Common::Input::DriverResult IrsProtocol::ResendFrame(u8 frame) { |
| 278 | std::array<u8, 38> mcu_request{}; | 278 | std::array<u8, 38> mcu_request{}; |
| 279 | mcu_request[1] = 0x1; | 279 | mcu_request[1] = 0x1; |
| 280 | mcu_request[2] = frame; | 280 | mcu_request[2] = frame; |
diff --git a/src/input_common/helpers/joycon_protocol/irs.h b/src/input_common/helpers/joycon_protocol/irs.h index 76dfa02ea..714cbb6b2 100644 --- a/src/input_common/helpers/joycon_protocol/irs.h +++ b/src/input_common/helpers/joycon_protocol/irs.h | |||
| @@ -13,19 +13,23 @@ | |||
| 13 | #include "input_common/helpers/joycon_protocol/common_protocol.h" | 13 | #include "input_common/helpers/joycon_protocol/common_protocol.h" |
| 14 | #include "input_common/helpers/joycon_protocol/joycon_types.h" | 14 | #include "input_common/helpers/joycon_protocol/joycon_types.h" |
| 15 | 15 | ||
| 16 | namespace Common::Input { | ||
| 17 | enum class DriverResult; | ||
| 18 | } | ||
| 19 | |||
| 16 | namespace InputCommon::Joycon { | 20 | namespace InputCommon::Joycon { |
| 17 | 21 | ||
| 18 | class IrsProtocol final : private JoyconCommonProtocol { | 22 | class IrsProtocol final : private JoyconCommonProtocol { |
| 19 | public: | 23 | public: |
| 20 | explicit IrsProtocol(std::shared_ptr<JoyconHandle> handle); | 24 | explicit IrsProtocol(std::shared_ptr<JoyconHandle> handle); |
| 21 | 25 | ||
| 22 | DriverResult EnableIrs(); | 26 | Common::Input::DriverResult EnableIrs(); |
| 23 | 27 | ||
| 24 | DriverResult DisableIrs(); | 28 | Common::Input::DriverResult DisableIrs(); |
| 25 | 29 | ||
| 26 | DriverResult SetIrsConfig(IrsMode mode, IrsResolution format); | 30 | Common::Input::DriverResult SetIrsConfig(IrsMode mode, IrsResolution format); |
| 27 | 31 | ||
| 28 | DriverResult RequestImage(std::span<u8> buffer); | 32 | Common::Input::DriverResult RequestImage(std::span<u8> buffer); |
| 29 | 33 | ||
| 30 | std::vector<u8> GetImage() const; | 34 | std::vector<u8> GetImage() const; |
| 31 | 35 | ||
| @@ -34,13 +38,13 @@ public: | |||
| 34 | bool IsEnabled() const; | 38 | bool IsEnabled() const; |
| 35 | 39 | ||
| 36 | private: | 40 | private: |
| 37 | DriverResult ConfigureIrs(); | 41 | Common::Input::DriverResult ConfigureIrs(); |
| 38 | 42 | ||
| 39 | DriverResult WriteRegistersStep1(); | 43 | Common::Input::DriverResult WriteRegistersStep1(); |
| 40 | DriverResult WriteRegistersStep2(); | 44 | Common::Input::DriverResult WriteRegistersStep2(); |
| 41 | 45 | ||
| 42 | DriverResult RequestFrame(u8 frame); | 46 | Common::Input::DriverResult RequestFrame(u8 frame); |
| 43 | DriverResult ResendFrame(u8 frame); | 47 | Common::Input::DriverResult ResendFrame(u8 frame); |
| 44 | 48 | ||
| 45 | IrsMode irs_mode{IrsMode::ImageTransfer}; | 49 | IrsMode irs_mode{IrsMode::ImageTransfer}; |
| 46 | IrsResolution resolution{IrsResolution::Size40x30}; | 50 | IrsResolution resolution{IrsResolution::Size40x30}; |
diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h index 5007b0e18..77a43c67a 100644 --- a/src/input_common/helpers/joycon_protocol/joycon_types.h +++ b/src/input_common/helpers/joycon_protocol/joycon_types.h | |||
| @@ -24,6 +24,7 @@ constexpr std::array<u8, 8> DefaultVibrationBuffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x | |||
| 24 | using MacAddress = std::array<u8, 6>; | 24 | using MacAddress = std::array<u8, 6>; |
| 25 | using SerialNumber = std::array<u8, 15>; | 25 | using SerialNumber = std::array<u8, 15>; |
| 26 | using TagUUID = std::array<u8, 7>; | 26 | using TagUUID = std::array<u8, 7>; |
| 27 | using MifareUUID = std::array<u8, 4>; | ||
| 27 | 28 | ||
| 28 | enum class ControllerType : u8 { | 29 | enum class ControllerType : u8 { |
| 29 | None = 0x00, | 30 | None = 0x00, |
| @@ -307,6 +308,19 @@ enum class NFCStatus : u8 { | |||
| 307 | WriteDone = 0x05, | 308 | WriteDone = 0x05, |
| 308 | TagLost = 0x07, | 309 | TagLost = 0x07, |
| 309 | WriteReady = 0x09, | 310 | WriteReady = 0x09, |
| 311 | MifareDone = 0x10, | ||
| 312 | }; | ||
| 313 | |||
| 314 | enum class MifareCmd : u8 { | ||
| 315 | None = 0x00, | ||
| 316 | Read = 0x30, | ||
| 317 | AuthA = 0x60, | ||
| 318 | AuthB = 0x61, | ||
| 319 | Write = 0xA0, | ||
| 320 | Transfer = 0xB0, | ||
| 321 | Decrement = 0xC0, | ||
| 322 | Increment = 0xC1, | ||
| 323 | Store = 0xC2 | ||
| 310 | }; | 324 | }; |
| 311 | 325 | ||
| 312 | enum class IrsMode : u8 { | 326 | enum class IrsMode : u8 { |
| @@ -388,23 +402,6 @@ enum class ExternalDeviceId : u16 { | |||
| 388 | Starlink = 0x2800, | 402 | Starlink = 0x2800, |
| 389 | }; | 403 | }; |
| 390 | 404 | ||
| 391 | enum class DriverResult { | ||
| 392 | Success, | ||
| 393 | WrongReply, | ||
| 394 | Timeout, | ||
| 395 | InvalidParameters, | ||
| 396 | UnsupportedControllerType, | ||
| 397 | HandleInUse, | ||
| 398 | ErrorReadingData, | ||
| 399 | ErrorWritingData, | ||
| 400 | NoDeviceDetected, | ||
| 401 | InvalidHandle, | ||
| 402 | NotSupported, | ||
| 403 | Disabled, | ||
| 404 | Delayed, | ||
| 405 | Unknown, | ||
| 406 | }; | ||
| 407 | |||
| 408 | struct MotionSensorCalibration { | 405 | struct MotionSensorCalibration { |
| 409 | s16 offset; | 406 | s16 offset; |
| 410 | s16 scale; | 407 | s16 scale; |
| @@ -592,6 +589,14 @@ struct NFCWriteCommandData { | |||
| 592 | static_assert(sizeof(NFCWriteCommandData) == 0x15, "NFCWriteCommandData is an invalid size"); | 589 | static_assert(sizeof(NFCWriteCommandData) == 0x15, "NFCWriteCommandData is an invalid size"); |
| 593 | #pragma pack(pop) | 590 | #pragma pack(pop) |
| 594 | 591 | ||
| 592 | struct MifareCommandData { | ||
| 593 | u8 unknown1; | ||
| 594 | u8 unknown2; | ||
| 595 | u8 number_of_short_bytes; | ||
| 596 | MifareUUID uid; | ||
| 597 | }; | ||
| 598 | static_assert(sizeof(MifareCommandData) == 0x7, "MifareCommandData is an invalid size"); | ||
| 599 | |||
| 595 | struct NFCPollingCommandData { | 600 | struct NFCPollingCommandData { |
| 596 | u8 enable_mifare; | 601 | u8 enable_mifare; |
| 597 | u8 unknown_1; | 602 | u8 unknown_1; |
| @@ -629,6 +634,41 @@ struct NFCWritePackage { | |||
| 629 | std::array<NFCDataChunk, 4> data_chunks; | 634 | std::array<NFCDataChunk, 4> data_chunks; |
| 630 | }; | 635 | }; |
| 631 | 636 | ||
| 637 | struct MifareReadChunk { | ||
| 638 | MifareCmd command; | ||
| 639 | std::array<u8, 0x6> sector_key; | ||
| 640 | u8 sector; | ||
| 641 | }; | ||
| 642 | |||
| 643 | struct MifareWriteChunk { | ||
| 644 | MifareCmd command; | ||
| 645 | std::array<u8, 0x6> sector_key; | ||
| 646 | u8 sector; | ||
| 647 | std::array<u8, 0x10> data; | ||
| 648 | }; | ||
| 649 | |||
| 650 | struct MifareReadData { | ||
| 651 | u8 sector; | ||
| 652 | std::array<u8, 0x10> data; | ||
| 653 | }; | ||
| 654 | |||
| 655 | struct MifareReadPackage { | ||
| 656 | MifareCommandData command_data; | ||
| 657 | std::array<MifareReadChunk, 0x10> data_chunks; | ||
| 658 | }; | ||
| 659 | |||
| 660 | struct MifareWritePackage { | ||
| 661 | MifareCommandData command_data; | ||
| 662 | std::array<MifareWriteChunk, 0x10> data_chunks; | ||
| 663 | }; | ||
| 664 | |||
| 665 | struct TagInfo { | ||
| 666 | u8 uuid_length; | ||
| 667 | u8 protocol; | ||
| 668 | u8 tag_type; | ||
| 669 | std::array<u8, 10> uuid; | ||
| 670 | }; | ||
| 671 | |||
| 632 | struct IrsConfigure { | 672 | struct IrsConfigure { |
| 633 | MCUCommand command; | 673 | MCUCommand command; |
| 634 | MCUSubCommand sub_command; | 674 | MCUSubCommand sub_command; |
| @@ -744,7 +784,7 @@ struct JoyconCallbacks { | |||
| 744 | std::function<void(int, f32)> on_stick_data; | 784 | std::function<void(int, f32)> on_stick_data; |
| 745 | std::function<void(int, const MotionData&)> on_motion_data; | 785 | std::function<void(int, const MotionData&)> on_motion_data; |
| 746 | std::function<void(f32)> on_ring_data; | 786 | std::function<void(f32)> on_ring_data; |
| 747 | std::function<void(const std::vector<u8>&)> on_amiibo_data; | 787 | std::function<void(const Joycon::TagInfo&)> on_amiibo_data; |
| 748 | std::function<void(const std::vector<u8>&, IrsResolution)> on_camera_data; | 788 | std::function<void(const std::vector<u8>&, IrsResolution)> on_camera_data; |
| 749 | }; | 789 | }; |
| 750 | 790 | ||
diff --git a/src/input_common/helpers/joycon_protocol/nfc.cpp b/src/input_common/helpers/joycon_protocol/nfc.cpp index f7058c4a7..09953394b 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.cpp +++ b/src/input_common/helpers/joycon_protocol/nfc.cpp | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2022 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 <thread> | 4 | #include "common/input.h" |
| 5 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 6 | #include "input_common/helpers/joycon_protocol/nfc.h" | 6 | #include "input_common/helpers/joycon_protocol/nfc.h" |
| 7 | 7 | ||
| @@ -10,21 +10,21 @@ namespace InputCommon::Joycon { | |||
| 10 | NfcProtocol::NfcProtocol(std::shared_ptr<JoyconHandle> handle) | 10 | NfcProtocol::NfcProtocol(std::shared_ptr<JoyconHandle> handle) |
| 11 | : JoyconCommonProtocol(std::move(handle)) {} | 11 | : JoyconCommonProtocol(std::move(handle)) {} |
| 12 | 12 | ||
| 13 | DriverResult NfcProtocol::EnableNfc() { | 13 | Common::Input::DriverResult NfcProtocol::EnableNfc() { |
| 14 | LOG_INFO(Input, "Enable NFC"); | 14 | LOG_INFO(Input, "Enable NFC"); |
| 15 | ScopedSetBlocking sb(this); | 15 | ScopedSetBlocking sb(this); |
| 16 | DriverResult result{DriverResult::Success}; | 16 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; |
| 17 | 17 | ||
| 18 | if (result == DriverResult::Success) { | 18 | if (result == Common::Input::DriverResult::Success) { |
| 19 | result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ); | 19 | result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ); |
| 20 | } | 20 | } |
| 21 | if (result == DriverResult::Success) { | 21 | if (result == Common::Input::DriverResult::Success) { |
| 22 | result = EnableMCU(true); | 22 | result = EnableMCU(true); |
| 23 | } | 23 | } |
| 24 | if (result == DriverResult::Success) { | 24 | if (result == Common::Input::DriverResult::Success) { |
| 25 | result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby); | 25 | result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby); |
| 26 | } | 26 | } |
| 27 | if (result == DriverResult::Success) { | 27 | if (result == Common::Input::DriverResult::Success) { |
| 28 | const MCUConfig config{ | 28 | const MCUConfig config{ |
| 29 | .command = MCUCommand::ConfigureMCU, | 29 | .command = MCUCommand::ConfigureMCU, |
| 30 | .sub_command = MCUSubCommand::SetMCUMode, | 30 | .sub_command = MCUSubCommand::SetMCUMode, |
| @@ -34,123 +34,240 @@ DriverResult NfcProtocol::EnableNfc() { | |||
| 34 | 34 | ||
| 35 | result = ConfigureMCU(config); | 35 | result = ConfigureMCU(config); |
| 36 | } | 36 | } |
| 37 | if (result == DriverResult::Success) { | 37 | if (result == Common::Input::DriverResult::Success) { |
| 38 | result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::NFC); | 38 | result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::NFC); |
| 39 | } | 39 | } |
| 40 | if (result == DriverResult::Success) { | 40 | if (result == Common::Input::DriverResult::Success) { |
| 41 | result = WaitUntilNfcIs(NFCStatus::Ready); | 41 | result = WaitUntilNfcIs(NFCStatus::Ready); |
| 42 | } | 42 | } |
| 43 | if (result == Common::Input::DriverResult::Success) { | ||
| 44 | MCUCommandResponse output{}; | ||
| 45 | result = SendStopPollingRequest(output); | ||
| 46 | } | ||
| 47 | if (result == Common::Input::DriverResult::Success) { | ||
| 48 | result = WaitUntilNfcIs(NFCStatus::Ready); | ||
| 49 | } | ||
| 50 | if (result == Common::Input::DriverResult::Success) { | ||
| 51 | is_enabled = true; | ||
| 52 | } | ||
| 43 | 53 | ||
| 44 | return result; | 54 | return result; |
| 45 | } | 55 | } |
| 46 | 56 | ||
| 47 | DriverResult NfcProtocol::DisableNfc() { | 57 | Common::Input::DriverResult NfcProtocol::DisableNfc() { |
| 48 | LOG_DEBUG(Input, "Disable NFC"); | 58 | LOG_DEBUG(Input, "Disable NFC"); |
| 49 | ScopedSetBlocking sb(this); | 59 | ScopedSetBlocking sb(this); |
| 50 | DriverResult result{DriverResult::Success}; | 60 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; |
| 51 | 61 | ||
| 52 | if (result == DriverResult::Success) { | 62 | if (result == Common::Input::DriverResult::Success) { |
| 53 | result = EnableMCU(false); | 63 | result = EnableMCU(false); |
| 54 | } | 64 | } |
| 55 | 65 | ||
| 56 | is_enabled = false; | 66 | is_enabled = false; |
| 67 | is_polling = false; | ||
| 57 | 68 | ||
| 58 | return result; | 69 | return result; |
| 59 | } | 70 | } |
| 60 | 71 | ||
| 61 | DriverResult NfcProtocol::StartNFCPollingMode() { | 72 | Common::Input::DriverResult NfcProtocol::StartNFCPollingMode() { |
| 62 | LOG_DEBUG(Input, "Start NFC pooling Mode"); | 73 | LOG_DEBUG(Input, "Start NFC polling Mode"); |
| 63 | ScopedSetBlocking sb(this); | 74 | ScopedSetBlocking sb(this); |
| 64 | DriverResult result{DriverResult::Success}; | 75 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; |
| 65 | 76 | ||
| 66 | if (result == DriverResult::Success) { | 77 | if (result == Common::Input::DriverResult::Success) { |
| 67 | MCUCommandResponse output{}; | 78 | MCUCommandResponse output{}; |
| 68 | result = SendStopPollingRequest(output); | 79 | result = SendStartPollingRequest(output); |
| 69 | } | 80 | } |
| 70 | if (result == DriverResult::Success) { | 81 | if (result == Common::Input::DriverResult::Success) { |
| 71 | result = WaitUntilNfcIs(NFCStatus::Ready); | 82 | result = WaitUntilNfcIs(NFCStatus::Polling); |
| 83 | } | ||
| 84 | if (result == Common::Input::DriverResult::Success) { | ||
| 85 | is_polling = true; | ||
| 72 | } | 86 | } |
| 73 | if (result == DriverResult::Success) { | 87 | |
| 88 | return result; | ||
| 89 | } | ||
| 90 | |||
| 91 | Common::Input::DriverResult NfcProtocol::StopNFCPollingMode() { | ||
| 92 | LOG_DEBUG(Input, "Stop NFC polling Mode"); | ||
| 93 | ScopedSetBlocking sb(this); | ||
| 94 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; | ||
| 95 | |||
| 96 | if (result == Common::Input::DriverResult::Success) { | ||
| 74 | MCUCommandResponse output{}; | 97 | MCUCommandResponse output{}; |
| 75 | result = SendStartPollingRequest(output); | 98 | result = SendStopPollingRequest(output); |
| 76 | } | 99 | } |
| 77 | if (result == DriverResult::Success) { | 100 | if (result == Common::Input::DriverResult::Success) { |
| 78 | result = WaitUntilNfcIs(NFCStatus::Polling); | 101 | result = WaitUntilNfcIs(NFCStatus::WriteReady); |
| 79 | } | 102 | } |
| 80 | if (result == DriverResult::Success) { | 103 | if (result == Common::Input::DriverResult::Success) { |
| 81 | is_enabled = true; | 104 | is_polling = false; |
| 82 | } | 105 | } |
| 83 | 106 | ||
| 84 | return result; | 107 | return result; |
| 85 | } | 108 | } |
| 86 | 109 | ||
| 87 | DriverResult NfcProtocol::ScanAmiibo(std::vector<u8>& data) { | 110 | Common::Input::DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) { |
| 88 | if (update_counter++ < AMIIBO_UPDATE_DELAY) { | 111 | if (update_counter++ < AMIIBO_UPDATE_DELAY) { |
| 89 | return DriverResult::Delayed; | 112 | return Common::Input::DriverResult::Delayed; |
| 90 | } | 113 | } |
| 91 | update_counter = 0; | 114 | update_counter = 0; |
| 92 | 115 | ||
| 93 | LOG_DEBUG(Input, "Scan for amiibos"); | 116 | LOG_DEBUG(Input, "Scan for amiibos"); |
| 94 | ScopedSetBlocking sb(this); | 117 | ScopedSetBlocking sb(this); |
| 95 | DriverResult result{DriverResult::Success}; | 118 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; |
| 96 | TagFoundData tag_data{}; | 119 | TagFoundData tag_data{}; |
| 97 | 120 | ||
| 98 | if (result == DriverResult::Success) { | 121 | if (result == Common::Input::DriverResult::Success) { |
| 99 | result = IsTagInRange(tag_data); | 122 | result = IsTagInRange(tag_data); |
| 100 | } | 123 | } |
| 101 | 124 | ||
| 102 | if (result == DriverResult::Success) { | 125 | if (result == Common::Input::DriverResult::Success) { |
| 126 | tag_info = { | ||
| 127 | .uuid_length = tag_data.uuid_size, | ||
| 128 | .protocol = 1, | ||
| 129 | .tag_type = tag_data.type, | ||
| 130 | .uuid = {}, | ||
| 131 | }; | ||
| 132 | |||
| 133 | memcpy(tag_info.uuid.data(), tag_data.uuid.data(), tag_data.uuid_size); | ||
| 134 | |||
| 135 | // Investigate why mifare type is not correct | ||
| 136 | if (tag_info.tag_type == 144) { | ||
| 137 | tag_info.tag_type = 1U << 6; | ||
| 138 | } | ||
| 139 | |||
| 103 | std::string uuid_string; | 140 | std::string uuid_string; |
| 104 | for (auto& content : tag_data.uuid) { | 141 | for (auto& content : tag_data.uuid) { |
| 105 | uuid_string += fmt::format(" {:02x}", content); | 142 | uuid_string += fmt::format(" {:02x}", content); |
| 106 | } | 143 | } |
| 107 | LOG_INFO(Input, "Tag detected, type={}, uuid={}", tag_data.type, uuid_string); | 144 | LOG_INFO(Input, "Tag detected, type={}, uuid={}", tag_data.type, uuid_string); |
| 145 | } | ||
| 146 | |||
| 147 | return result; | ||
| 148 | } | ||
| 149 | |||
| 150 | Common::Input::DriverResult NfcProtocol::ReadAmiibo(std::vector<u8>& data) { | ||
| 151 | LOG_DEBUG(Input, "Scan for amiibos"); | ||
| 152 | ScopedSetBlocking sb(this); | ||
| 153 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; | ||
| 154 | TagFoundData tag_data{}; | ||
| 155 | |||
| 156 | if (result == Common::Input::DriverResult::Success) { | ||
| 157 | result = IsTagInRange(tag_data, 7); | ||
| 158 | } | ||
| 159 | |||
| 160 | if (result == Common::Input::DriverResult::Success) { | ||
| 108 | result = GetAmiiboData(data); | 161 | result = GetAmiiboData(data); |
| 109 | } | 162 | } |
| 110 | 163 | ||
| 111 | return result; | 164 | return result; |
| 112 | } | 165 | } |
| 113 | 166 | ||
| 114 | DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) { | 167 | Common::Input::DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) { |
| 115 | LOG_DEBUG(Input, "Write amiibo"); | 168 | LOG_DEBUG(Input, "Write amiibo"); |
| 116 | ScopedSetBlocking sb(this); | 169 | ScopedSetBlocking sb(this); |
| 117 | DriverResult result{DriverResult::Success}; | 170 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; |
| 118 | TagUUID tag_uuid = GetTagUUID(data); | 171 | TagUUID tag_uuid = GetTagUUID(data); |
| 119 | TagFoundData tag_data{}; | 172 | TagFoundData tag_data{}; |
| 120 | 173 | ||
| 121 | if (result == DriverResult::Success) { | 174 | if (result == Common::Input::DriverResult::Success) { |
| 122 | result = IsTagInRange(tag_data, 7); | 175 | result = IsTagInRange(tag_data, 7); |
| 123 | } | 176 | } |
| 124 | if (result == DriverResult::Success) { | 177 | if (result == Common::Input::DriverResult::Success) { |
| 125 | if (tag_data.uuid != tag_uuid) { | 178 | if (tag_data.uuid != tag_uuid) { |
| 126 | result = DriverResult::InvalidParameters; | 179 | result = Common::Input::DriverResult::InvalidParameters; |
| 127 | } | 180 | } |
| 128 | } | 181 | } |
| 129 | if (result == DriverResult::Success) { | 182 | if (result == Common::Input::DriverResult::Success) { |
| 130 | MCUCommandResponse output{}; | 183 | MCUCommandResponse output{}; |
| 131 | result = SendStopPollingRequest(output); | 184 | result = SendStopPollingRequest(output); |
| 132 | } | 185 | } |
| 133 | if (result == DriverResult::Success) { | 186 | if (result == Common::Input::DriverResult::Success) { |
| 134 | result = WaitUntilNfcIs(NFCStatus::Ready); | 187 | result = WaitUntilNfcIs(NFCStatus::Ready); |
| 135 | } | 188 | } |
| 136 | if (result == DriverResult::Success) { | 189 | if (result == Common::Input::DriverResult::Success) { |
| 137 | MCUCommandResponse output{}; | 190 | MCUCommandResponse output{}; |
| 138 | result = SendStartPollingRequest(output, true); | 191 | result = SendStartPollingRequest(output, true); |
| 139 | } | 192 | } |
| 140 | if (result == DriverResult::Success) { | 193 | if (result == Common::Input::DriverResult::Success) { |
| 141 | result = WaitUntilNfcIs(NFCStatus::WriteReady); | 194 | result = WaitUntilNfcIs(NFCStatus::WriteReady); |
| 142 | } | 195 | } |
| 143 | if (result == DriverResult::Success) { | 196 | if (result == Common::Input::DriverResult::Success) { |
| 144 | result = WriteAmiiboData(tag_uuid, data); | 197 | result = WriteAmiiboData(tag_uuid, data); |
| 145 | } | 198 | } |
| 146 | if (result == DriverResult::Success) { | 199 | if (result == Common::Input::DriverResult::Success) { |
| 147 | result = WaitUntilNfcIs(NFCStatus::WriteDone); | 200 | result = WaitUntilNfcIs(NFCStatus::WriteDone); |
| 148 | } | 201 | } |
| 149 | if (result == DriverResult::Success) { | 202 | if (result == Common::Input::DriverResult::Success) { |
| 203 | MCUCommandResponse output{}; | ||
| 204 | result = SendStopPollingRequest(output); | ||
| 205 | } | ||
| 206 | |||
| 207 | return result; | ||
| 208 | } | ||
| 209 | |||
| 210 | Common::Input::DriverResult NfcProtocol::ReadMifare(std::span<const MifareReadChunk> read_request, | ||
| 211 | std::span<MifareReadData> out_data) { | ||
| 212 | LOG_DEBUG(Input, "Read mifare"); | ||
| 213 | ScopedSetBlocking sb(this); | ||
| 214 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; | ||
| 215 | TagFoundData tag_data{}; | ||
| 216 | MifareUUID tag_uuid{}; | ||
| 217 | |||
| 218 | if (result == Common::Input::DriverResult::Success) { | ||
| 219 | result = IsTagInRange(tag_data, 7); | ||
| 220 | } | ||
| 221 | if (result == Common::Input::DriverResult::Success) { | ||
| 222 | memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID)); | ||
| 223 | result = GetMifareData(tag_uuid, read_request, out_data); | ||
| 224 | } | ||
| 225 | if (result == Common::Input::DriverResult::Success) { | ||
| 150 | MCUCommandResponse output{}; | 226 | MCUCommandResponse output{}; |
| 151 | result = SendStopPollingRequest(output); | 227 | result = SendStopPollingRequest(output); |
| 152 | } | 228 | } |
| 229 | if (result == Common::Input::DriverResult::Success) { | ||
| 230 | result = WaitUntilNfcIs(NFCStatus::Ready); | ||
| 231 | } | ||
| 232 | if (result == Common::Input::DriverResult::Success) { | ||
| 233 | MCUCommandResponse output{}; | ||
| 234 | result = SendStartPollingRequest(output, true); | ||
| 235 | } | ||
| 236 | if (result == Common::Input::DriverResult::Success) { | ||
| 237 | result = WaitUntilNfcIs(NFCStatus::WriteReady); | ||
| 238 | } | ||
| 239 | return result; | ||
| 240 | } | ||
| 241 | |||
| 242 | Common::Input::DriverResult NfcProtocol::WriteMifare( | ||
| 243 | std::span<const MifareWriteChunk> write_request) { | ||
| 244 | LOG_DEBUG(Input, "Write mifare"); | ||
| 245 | ScopedSetBlocking sb(this); | ||
| 246 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; | ||
| 247 | TagFoundData tag_data{}; | ||
| 248 | MifareUUID tag_uuid{}; | ||
| 153 | 249 | ||
| 250 | if (result == Common::Input::DriverResult::Success) { | ||
| 251 | result = IsTagInRange(tag_data, 7); | ||
| 252 | } | ||
| 253 | if (result == Common::Input::DriverResult::Success) { | ||
| 254 | memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID)); | ||
| 255 | result = WriteMifareData(tag_uuid, write_request); | ||
| 256 | } | ||
| 257 | if (result == Common::Input::DriverResult::Success) { | ||
| 258 | MCUCommandResponse output{}; | ||
| 259 | result = SendStopPollingRequest(output); | ||
| 260 | } | ||
| 261 | if (result == Common::Input::DriverResult::Success) { | ||
| 262 | result = WaitUntilNfcIs(NFCStatus::Ready); | ||
| 263 | } | ||
| 264 | if (result == Common::Input::DriverResult::Success) { | ||
| 265 | MCUCommandResponse output{}; | ||
| 266 | result = SendStartPollingRequest(output, true); | ||
| 267 | } | ||
| 268 | if (result == Common::Input::DriverResult::Success) { | ||
| 269 | result = WaitUntilNfcIs(NFCStatus::WriteReady); | ||
| 270 | } | ||
| 154 | return result; | 271 | return result; |
| 155 | } | 272 | } |
| 156 | 273 | ||
| @@ -161,17 +278,17 @@ bool NfcProtocol::HasAmiibo() { | |||
| 161 | update_counter = 0; | 278 | update_counter = 0; |
| 162 | 279 | ||
| 163 | ScopedSetBlocking sb(this); | 280 | ScopedSetBlocking sb(this); |
| 164 | DriverResult result{DriverResult::Success}; | 281 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; |
| 165 | TagFoundData tag_data{}; | 282 | TagFoundData tag_data{}; |
| 166 | 283 | ||
| 167 | if (result == DriverResult::Success) { | 284 | if (result == Common::Input::DriverResult::Success) { |
| 168 | result = IsTagInRange(tag_data, 7); | 285 | result = IsTagInRange(tag_data, 7); |
| 169 | } | 286 | } |
| 170 | 287 | ||
| 171 | return result == DriverResult::Success; | 288 | return result == Common::Input::DriverResult::Success; |
| 172 | } | 289 | } |
| 173 | 290 | ||
| 174 | DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) { | 291 | Common::Input::DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) { |
| 175 | constexpr std::size_t timeout_limit = 10; | 292 | constexpr std::size_t timeout_limit = 10; |
| 176 | MCUCommandResponse output{}; | 293 | MCUCommandResponse output{}; |
| 177 | std::size_t tries = 0; | 294 | std::size_t tries = 0; |
| @@ -179,30 +296,31 @@ DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) { | |||
| 179 | do { | 296 | do { |
| 180 | auto result = SendNextPackageRequest(output, {}); | 297 | auto result = SendNextPackageRequest(output, {}); |
| 181 | 298 | ||
| 182 | if (result != DriverResult::Success) { | 299 | if (result != Common::Input::DriverResult::Success) { |
| 183 | return result; | 300 | return result; |
| 184 | } | 301 | } |
| 185 | if (tries++ > timeout_limit) { | 302 | if (tries++ > timeout_limit) { |
| 186 | return DriverResult::Timeout; | 303 | return Common::Input::DriverResult::Timeout; |
| 187 | } | 304 | } |
| 188 | } while (output.mcu_report != MCUReport::NFCState || | 305 | } while (output.mcu_report != MCUReport::NFCState || |
| 189 | (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 || | 306 | (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 || |
| 190 | output.mcu_data[5] != 0x31 || output.mcu_data[6] != static_cast<u8>(status)); | 307 | output.mcu_data[5] != 0x31 || output.mcu_data[6] != static_cast<u8>(status)); |
| 191 | 308 | ||
| 192 | return DriverResult::Success; | 309 | return Common::Input::DriverResult::Success; |
| 193 | } | 310 | } |
| 194 | 311 | ||
| 195 | DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, std::size_t timeout_limit) { | 312 | Common::Input::DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, |
| 313 | std::size_t timeout_limit) { | ||
| 196 | MCUCommandResponse output{}; | 314 | MCUCommandResponse output{}; |
| 197 | std::size_t tries = 0; | 315 | std::size_t tries = 0; |
| 198 | 316 | ||
| 199 | do { | 317 | do { |
| 200 | const auto result = SendNextPackageRequest(output, {}); | 318 | const auto result = SendNextPackageRequest(output, {}); |
| 201 | if (result != DriverResult::Success) { | 319 | if (result != Common::Input::DriverResult::Success) { |
| 202 | return result; | 320 | return result; |
| 203 | } | 321 | } |
| 204 | if (tries++ > timeout_limit) { | 322 | if (tries++ > timeout_limit) { |
| 205 | return DriverResult::Timeout; | 323 | return Common::Input::DriverResult::Timeout; |
| 206 | } | 324 | } |
| 207 | } while (output.mcu_report != MCUReport::NFCState || | 325 | } while (output.mcu_report != MCUReport::NFCState || |
| 208 | (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 || | 326 | (output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 || |
| @@ -212,10 +330,10 @@ DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, std::size_t timeout_l | |||
| 212 | data.uuid_size = std::min(output.mcu_data[14], static_cast<u8>(sizeof(TagUUID))); | 330 | data.uuid_size = std::min(output.mcu_data[14], static_cast<u8>(sizeof(TagUUID))); |
| 213 | memcpy(data.uuid.data(), output.mcu_data.data() + 15, data.uuid.size()); | 331 | memcpy(data.uuid.data(), output.mcu_data.data() + 15, data.uuid.size()); |
| 214 | 332 | ||
| 215 | return DriverResult::Success; | 333 | return Common::Input::DriverResult::Success; |
| 216 | } | 334 | } |
| 217 | 335 | ||
| 218 | DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) { | 336 | Common::Input::DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) { |
| 219 | constexpr std::size_t timeout_limit = 60; | 337 | constexpr std::size_t timeout_limit = 60; |
| 220 | MCUCommandResponse output{}; | 338 | MCUCommandResponse output{}; |
| 221 | std::size_t tries = 0; | 339 | std::size_t tries = 0; |
| @@ -224,7 +342,7 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) { | |||
| 224 | std::size_t ntag_buffer_pos = 0; | 342 | std::size_t ntag_buffer_pos = 0; |
| 225 | auto result = SendReadAmiiboRequest(output, NFCPages::Block135); | 343 | auto result = SendReadAmiiboRequest(output, NFCPages::Block135); |
| 226 | 344 | ||
| 227 | if (result != DriverResult::Success) { | 345 | if (result != Common::Input::DriverResult::Success) { |
| 228 | return result; | 346 | return result; |
| 229 | } | 347 | } |
| 230 | 348 | ||
| @@ -233,14 +351,14 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) { | |||
| 233 | result = SendNextPackageRequest(output, package_index); | 351 | result = SendNextPackageRequest(output, package_index); |
| 234 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); | 352 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); |
| 235 | 353 | ||
| 236 | if (result != DriverResult::Success) { | 354 | if (result != Common::Input::DriverResult::Success) { |
| 237 | return result; | 355 | return result; |
| 238 | } | 356 | } |
| 239 | 357 | ||
| 240 | if ((output.mcu_report == MCUReport::NFCReadData || | 358 | if ((output.mcu_report == MCUReport::NFCReadData || |
| 241 | output.mcu_report == MCUReport::NFCState) && | 359 | output.mcu_report == MCUReport::NFCState) && |
| 242 | nfc_status == NFCStatus::TagLost) { | 360 | nfc_status == NFCStatus::TagLost) { |
| 243 | return DriverResult::ErrorReadingData; | 361 | return Common::Input::DriverResult::ErrorReadingData; |
| 244 | } | 362 | } |
| 245 | 363 | ||
| 246 | if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) { | 364 | if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) { |
| @@ -259,14 +377,15 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) { | |||
| 259 | 377 | ||
| 260 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) { | 378 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) { |
| 261 | LOG_INFO(Input, "Finished reading amiibo"); | 379 | LOG_INFO(Input, "Finished reading amiibo"); |
| 262 | return DriverResult::Success; | 380 | return Common::Input::DriverResult::Success; |
| 263 | } | 381 | } |
| 264 | } | 382 | } |
| 265 | 383 | ||
| 266 | return DriverResult::Timeout; | 384 | return Common::Input::DriverResult::Timeout; |
| 267 | } | 385 | } |
| 268 | 386 | ||
| 269 | DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data) { | 387 | Common::Input::DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, |
| 388 | std::span<const u8> data) { | ||
| 270 | constexpr std::size_t timeout_limit = 60; | 389 | constexpr std::size_t timeout_limit = 60; |
| 271 | const auto nfc_data = MakeAmiiboWritePackage(tag_uuid, data); | 390 | const auto nfc_data = MakeAmiiboWritePackage(tag_uuid, data); |
| 272 | const std::vector<u8> nfc_buffer_data = SerializeWritePackage(nfc_data); | 391 | const std::vector<u8> nfc_buffer_data = SerializeWritePackage(nfc_data); |
| @@ -281,7 +400,7 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con | |||
| 281 | 400 | ||
| 282 | auto result = SendWriteAmiiboRequest(output, tag_uuid); | 401 | auto result = SendWriteAmiiboRequest(output, tag_uuid); |
| 283 | 402 | ||
| 284 | if (result != DriverResult::Success) { | 403 | if (result != Common::Input::DriverResult::Success) { |
| 285 | return result; | 404 | return result; |
| 286 | } | 405 | } |
| 287 | 406 | ||
| @@ -290,14 +409,14 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con | |||
| 290 | result = SendNextPackageRequest(output, package_index); | 409 | result = SendNextPackageRequest(output, package_index); |
| 291 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); | 410 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); |
| 292 | 411 | ||
| 293 | if (result != DriverResult::Success) { | 412 | if (result != Common::Input::DriverResult::Success) { |
| 294 | return result; | 413 | return result; |
| 295 | } | 414 | } |
| 296 | 415 | ||
| 297 | if ((output.mcu_report == MCUReport::NFCReadData || | 416 | if ((output.mcu_report == MCUReport::NFCReadData || |
| 298 | output.mcu_report == MCUReport::NFCState) && | 417 | output.mcu_report == MCUReport::NFCState) && |
| 299 | nfc_status == NFCStatus::TagLost) { | 418 | nfc_status == NFCStatus::TagLost) { |
| 300 | return DriverResult::ErrorReadingData; | 419 | return Common::Input::DriverResult::ErrorReadingData; |
| 301 | } | 420 | } |
| 302 | 421 | ||
| 303 | if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) { | 422 | if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) { |
| @@ -326,7 +445,131 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con | |||
| 326 | if ((output.mcu_report == MCUReport::NFCReadData || | 445 | if ((output.mcu_report == MCUReport::NFCReadData || |
| 327 | output.mcu_report == MCUReport::NFCState) && | 446 | output.mcu_report == MCUReport::NFCState) && |
| 328 | nfc_status == NFCStatus::TagLost) { | 447 | nfc_status == NFCStatus::TagLost) { |
| 329 | return DriverResult::ErrorReadingData; | 448 | return Common::Input::DriverResult::ErrorReadingData; |
| 449 | } | ||
| 450 | |||
| 451 | // Increase position when data is confirmed by the joycon | ||
| 452 | if (output.mcu_report == MCUReport::NFCState && | ||
| 453 | (output.mcu_data[1] << 8) + output.mcu_data[0] == 0x0500 && | ||
| 454 | output.mcu_data[3] == block_id) { | ||
| 455 | block_id++; | ||
| 456 | current_position = next_position; | ||
| 457 | } | ||
| 458 | } | ||
| 459 | |||
| 460 | return result; | ||
| 461 | } | ||
| 462 | |||
| 463 | Common::Input::DriverResult NfcProtocol::GetMifareData( | ||
| 464 | const MifareUUID& tag_uuid, std::span<const MifareReadChunk> read_request, | ||
| 465 | std::span<MifareReadData> out_data) { | ||
| 466 | constexpr std::size_t timeout_limit = 60; | ||
| 467 | const auto nfc_data = MakeMifareReadPackage(tag_uuid, read_request); | ||
| 468 | const std::vector<u8> nfc_buffer_data = SerializeMifareReadPackage(nfc_data); | ||
| 469 | std::span<const u8> buffer(nfc_buffer_data); | ||
| 470 | Common::Input::DriverResult result = Common::Input::DriverResult::Success; | ||
| 471 | MCUCommandResponse output{}; | ||
| 472 | u8 block_id = 1; | ||
| 473 | u8 package_index = 0; | ||
| 474 | std::size_t tries = 0; | ||
| 475 | std::size_t current_position = 0; | ||
| 476 | |||
| 477 | LOG_INFO(Input, "Reading Mifare data"); | ||
| 478 | |||
| 479 | // Send data request. Nfc buffer size is 31, Send the data in smaller packages | ||
| 480 | while (current_position < buffer.size() && tries++ < timeout_limit) { | ||
| 481 | const std::size_t next_position = | ||
| 482 | std::min(current_position + sizeof(NFCRequestState::raw_data), buffer.size()); | ||
| 483 | const std::size_t block_size = next_position - current_position; | ||
| 484 | const bool is_last_packet = block_size < sizeof(NFCRequestState::raw_data); | ||
| 485 | |||
| 486 | SendReadDataMifareRequest(output, block_id, is_last_packet, | ||
| 487 | buffer.subspan(current_position, block_size)); | ||
| 488 | |||
| 489 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); | ||
| 490 | |||
| 491 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { | ||
| 492 | return Common::Input::DriverResult::ErrorReadingData; | ||
| 493 | } | ||
| 494 | |||
| 495 | // Increase position when data is confirmed by the joycon | ||
| 496 | if (output.mcu_report == MCUReport::NFCState && | ||
| 497 | (output.mcu_data[1] << 8) + output.mcu_data[0] == 0x0500 && | ||
| 498 | output.mcu_data[3] == block_id) { | ||
| 499 | block_id++; | ||
| 500 | current_position = next_position; | ||
| 501 | } | ||
| 502 | } | ||
| 503 | |||
| 504 | if (result != Common::Input::DriverResult::Success) { | ||
| 505 | return result; | ||
| 506 | } | ||
| 507 | |||
| 508 | // Wait for reply and save the output data | ||
| 509 | while (tries++ < timeout_limit) { | ||
| 510 | result = SendNextPackageRequest(output, package_index); | ||
| 511 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); | ||
| 512 | |||
| 513 | if (result != Common::Input::DriverResult::Success) { | ||
| 514 | return result; | ||
| 515 | } | ||
| 516 | |||
| 517 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { | ||
| 518 | return Common::Input::DriverResult::ErrorReadingData; | ||
| 519 | } | ||
| 520 | |||
| 521 | if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { | ||
| 522 | constexpr std::size_t DATA_LENGHT = 0x10 + 1; | ||
| 523 | constexpr std::size_t DATA_START = 11; | ||
| 524 | const u8 number_of_elements = output.mcu_data[10]; | ||
| 525 | for (std::size_t i = 0; i < number_of_elements; i++) { | ||
| 526 | out_data[i].sector = output.mcu_data[DATA_START + (i * DATA_LENGHT)]; | ||
| 527 | memcpy(out_data[i].data.data(), | ||
| 528 | output.mcu_data.data() + DATA_START + 1 + (i * DATA_LENGHT), | ||
| 529 | sizeof(MifareReadData::data)); | ||
| 530 | } | ||
| 531 | package_index++; | ||
| 532 | continue; | ||
| 533 | } | ||
| 534 | |||
| 535 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::MifareDone) { | ||
| 536 | LOG_INFO(Input, "Finished reading mifare"); | ||
| 537 | break; | ||
| 538 | } | ||
| 539 | } | ||
| 540 | |||
| 541 | return result; | ||
| 542 | } | ||
| 543 | |||
| 544 | Common::Input::DriverResult NfcProtocol::WriteMifareData( | ||
| 545 | const MifareUUID& tag_uuid, std::span<const MifareWriteChunk> write_request) { | ||
| 546 | constexpr std::size_t timeout_limit = 60; | ||
| 547 | const auto nfc_data = MakeMifareWritePackage(tag_uuid, write_request); | ||
| 548 | const std::vector<u8> nfc_buffer_data = SerializeMifareWritePackage(nfc_data); | ||
| 549 | std::span<const u8> buffer(nfc_buffer_data); | ||
| 550 | Common::Input::DriverResult result = Common::Input::DriverResult::Success; | ||
| 551 | MCUCommandResponse output{}; | ||
| 552 | u8 block_id = 1; | ||
| 553 | u8 package_index = 0; | ||
| 554 | std::size_t tries = 0; | ||
| 555 | std::size_t current_position = 0; | ||
| 556 | |||
| 557 | LOG_INFO(Input, "Writing Mifare data"); | ||
| 558 | |||
| 559 | // Send data request. Nfc buffer size is 31, Send the data in smaller packages | ||
| 560 | while (current_position < buffer.size() && tries++ < timeout_limit) { | ||
| 561 | const std::size_t next_position = | ||
| 562 | std::min(current_position + sizeof(NFCRequestState::raw_data), buffer.size()); | ||
| 563 | const std::size_t block_size = next_position - current_position; | ||
| 564 | const bool is_last_packet = block_size < sizeof(NFCRequestState::raw_data); | ||
| 565 | |||
| 566 | SendReadDataMifareRequest(output, block_id, is_last_packet, | ||
| 567 | buffer.subspan(current_position, block_size)); | ||
| 568 | |||
| 569 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); | ||
| 570 | |||
| 571 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { | ||
| 572 | return Common::Input::DriverResult::ErrorReadingData; | ||
| 330 | } | 573 | } |
| 331 | 574 | ||
| 332 | // Increase position when data is confirmed by the joycon | 575 | // Increase position when data is confirmed by the joycon |
| @@ -338,11 +581,39 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con | |||
| 338 | } | 581 | } |
| 339 | } | 582 | } |
| 340 | 583 | ||
| 584 | if (result != Common::Input::DriverResult::Success) { | ||
| 585 | return result; | ||
| 586 | } | ||
| 587 | |||
| 588 | // Wait for reply and ignore the output data | ||
| 589 | while (tries++ < timeout_limit) { | ||
| 590 | result = SendNextPackageRequest(output, package_index); | ||
| 591 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); | ||
| 592 | |||
| 593 | if (result != Common::Input::DriverResult::Success) { | ||
| 594 | return result; | ||
| 595 | } | ||
| 596 | |||
| 597 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { | ||
| 598 | return Common::Input::DriverResult::ErrorReadingData; | ||
| 599 | } | ||
| 600 | |||
| 601 | if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { | ||
| 602 | package_index++; | ||
| 603 | continue; | ||
| 604 | } | ||
| 605 | |||
| 606 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::MifareDone) { | ||
| 607 | LOG_INFO(Input, "Finished writing mifare"); | ||
| 608 | break; | ||
| 609 | } | ||
| 610 | } | ||
| 611 | |||
| 341 | return result; | 612 | return result; |
| 342 | } | 613 | } |
| 343 | 614 | ||
| 344 | DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output, | 615 | Common::Input::DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output, |
| 345 | bool is_second_attempt) { | 616 | bool is_second_attempt) { |
| 346 | NFCRequestState request{ | 617 | NFCRequestState request{ |
| 347 | .command_argument = NFCCommand::StartPolling, | 618 | .command_argument = NFCCommand::StartPolling, |
| 348 | .block_id = {}, | 619 | .block_id = {}, |
| @@ -367,7 +638,7 @@ DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output, | |||
| 367 | output); | 638 | output); |
| 368 | } | 639 | } |
| 369 | 640 | ||
| 370 | DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) { | 641 | Common::Input::DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) { |
| 371 | NFCRequestState request{ | 642 | NFCRequestState request{ |
| 372 | .command_argument = NFCCommand::StopPolling, | 643 | .command_argument = NFCCommand::StopPolling, |
| 373 | .block_id = {}, | 644 | .block_id = {}, |
| @@ -385,7 +656,8 @@ DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) { | |||
| 385 | output); | 656 | output); |
| 386 | } | 657 | } |
| 387 | 658 | ||
| 388 | DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id) { | 659 | Common::Input::DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, |
| 660 | u8 packet_id) { | ||
| 389 | NFCRequestState request{ | 661 | NFCRequestState request{ |
| 390 | .command_argument = NFCCommand::StartWaitingRecieve, | 662 | .command_argument = NFCCommand::StartWaitingRecieve, |
| 391 | .block_id = {}, | 663 | .block_id = {}, |
| @@ -403,7 +675,8 @@ DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, u8 | |||
| 403 | output); | 675 | output); |
| 404 | } | 676 | } |
| 405 | 677 | ||
| 406 | DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages) { | 678 | Common::Input::DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, |
| 679 | NFCPages ntag_pages) { | ||
| 407 | NFCRequestState request{ | 680 | NFCRequestState request{ |
| 408 | .command_argument = NFCCommand::ReadNtag, | 681 | .command_argument = NFCCommand::ReadNtag, |
| 409 | .block_id = {}, | 682 | .block_id = {}, |
| @@ -428,8 +701,8 @@ DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCP | |||
| 428 | output); | 701 | output); |
| 429 | } | 702 | } |
| 430 | 703 | ||
| 431 | DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output, | 704 | Common::Input::DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output, |
| 432 | const TagUUID& tag_uuid) { | 705 | const TagUUID& tag_uuid) { |
| 433 | NFCRequestState request{ | 706 | NFCRequestState request{ |
| 434 | .command_argument = NFCCommand::ReadNtag, | 707 | .command_argument = NFCCommand::ReadNtag, |
| 435 | .block_id = {}, | 708 | .block_id = {}, |
| @@ -454,9 +727,10 @@ DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output, | |||
| 454 | output); | 727 | output); |
| 455 | } | 728 | } |
| 456 | 729 | ||
| 457 | DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, | 730 | Common::Input::DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output, |
| 458 | bool is_last_packet, | 731 | u8 block_id, |
| 459 | std::span<const u8> data) { | 732 | bool is_last_packet, |
| 733 | std::span<const u8> data) { | ||
| 460 | const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data)); | 734 | const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data)); |
| 461 | NFCRequestState request{ | 735 | NFCRequestState request{ |
| 462 | .command_argument = NFCCommand::WriteNtag, | 736 | .command_argument = NFCCommand::WriteNtag, |
| @@ -477,6 +751,29 @@ DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output, | |||
| 477 | output); | 751 | output); |
| 478 | } | 752 | } |
| 479 | 753 | ||
| 754 | Common::Input::DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output, | ||
| 755 | u8 block_id, bool is_last_packet, | ||
| 756 | std::span<const u8> data) { | ||
| 757 | const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data)); | ||
| 758 | NFCRequestState request{ | ||
| 759 | .command_argument = NFCCommand::Mifare, | ||
| 760 | .block_id = block_id, | ||
| 761 | .packet_id = {}, | ||
| 762 | .packet_flag = | ||
| 763 | is_last_packet ? MCUPacketFlag::LastCommandPacket : MCUPacketFlag::MorePacketsRemaining, | ||
| 764 | .data_length = static_cast<u8>(data_size), | ||
| 765 | .raw_data = {}, | ||
| 766 | .crc = {}, | ||
| 767 | }; | ||
| 768 | memcpy(request.raw_data.data(), data.data(), data_size); | ||
| 769 | |||
| 770 | std::array<u8, sizeof(NFCRequestState)> request_data{}; | ||
| 771 | memcpy(request_data.data(), &request, sizeof(NFCRequestState)); | ||
| 772 | request_data[36] = CalculateMCU_CRC8(request_data.data(), 36); | ||
| 773 | return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, MCUSubCommand::ReadDeviceMode, request_data, | ||
| 774 | output); | ||
| 775 | } | ||
| 776 | |||
| 480 | std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& package) const { | 777 | std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& package) const { |
| 481 | const std::size_t header_size = | 778 | const std::size_t header_size = |
| 482 | sizeof(NFCWriteCommandData) + sizeof(NFCWritePackage::number_of_chunks); | 779 | sizeof(NFCWriteCommandData) + sizeof(NFCWritePackage::number_of_chunks); |
| @@ -498,6 +795,48 @@ std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& packag | |||
| 498 | return serialized_data; | 795 | return serialized_data; |
| 499 | } | 796 | } |
| 500 | 797 | ||
| 798 | std::vector<u8> NfcProtocol::SerializeMifareReadPackage(const MifareReadPackage& package) const { | ||
| 799 | const std::size_t header_size = sizeof(MifareCommandData); | ||
| 800 | std::vector<u8> serialized_data(header_size); | ||
| 801 | std::size_t start_index = 0; | ||
| 802 | |||
| 803 | memcpy(serialized_data.data(), &package, header_size); | ||
| 804 | start_index += header_size; | ||
| 805 | |||
| 806 | for (const auto& data_chunk : package.data_chunks) { | ||
| 807 | const std::size_t chunk_size = sizeof(MifareReadChunk); | ||
| 808 | if (data_chunk.command == MifareCmd::None) { | ||
| 809 | continue; | ||
| 810 | } | ||
| 811 | serialized_data.resize(start_index + chunk_size); | ||
| 812 | memcpy(serialized_data.data() + start_index, &data_chunk, chunk_size); | ||
| 813 | start_index += chunk_size; | ||
| 814 | } | ||
| 815 | |||
| 816 | return serialized_data; | ||
| 817 | } | ||
| 818 | |||
| 819 | std::vector<u8> NfcProtocol::SerializeMifareWritePackage(const MifareWritePackage& package) const { | ||
| 820 | const std::size_t header_size = sizeof(MifareCommandData); | ||
| 821 | std::vector<u8> serialized_data(header_size); | ||
| 822 | std::size_t start_index = 0; | ||
| 823 | |||
| 824 | memcpy(serialized_data.data(), &package, header_size); | ||
| 825 | start_index += header_size; | ||
| 826 | |||
| 827 | for (const auto& data_chunk : package.data_chunks) { | ||
| 828 | const std::size_t chunk_size = sizeof(MifareWriteChunk); | ||
| 829 | if (data_chunk.command == MifareCmd::None) { | ||
| 830 | continue; | ||
| 831 | } | ||
| 832 | serialized_data.resize(start_index + chunk_size); | ||
| 833 | memcpy(serialized_data.data() + start_index, &data_chunk, chunk_size); | ||
| 834 | start_index += chunk_size; | ||
| 835 | } | ||
| 836 | |||
| 837 | return serialized_data; | ||
| 838 | } | ||
| 839 | |||
| 501 | NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid, | 840 | NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid, |
| 502 | std::span<const u8> data) const { | 841 | std::span<const u8> data) const { |
| 503 | return { | 842 | return { |
| @@ -527,6 +866,46 @@ NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid, | |||
| 527 | }; | 866 | }; |
| 528 | } | 867 | } |
| 529 | 868 | ||
| 869 | MifareReadPackage NfcProtocol::MakeMifareReadPackage( | ||
| 870 | const MifareUUID& tag_uuid, std::span<const MifareReadChunk> read_request) const { | ||
| 871 | MifareReadPackage package{ | ||
| 872 | .command_data{ | ||
| 873 | .unknown1 = 0xd0, | ||
| 874 | .unknown2 = 0x07, | ||
| 875 | .number_of_short_bytes = static_cast<u8>( | ||
| 876 | ((read_request.size() * sizeof(MifareReadChunk)) + sizeof(MifareUUID)) / 2), | ||
| 877 | .uid = tag_uuid, | ||
| 878 | }, | ||
| 879 | .data_chunks = {}, | ||
| 880 | }; | ||
| 881 | |||
| 882 | for (std::size_t i = 0; i < read_request.size() && i < package.data_chunks.size(); ++i) { | ||
| 883 | package.data_chunks[i] = read_request[i]; | ||
| 884 | } | ||
| 885 | |||
| 886 | return package; | ||
| 887 | } | ||
| 888 | |||
| 889 | MifareWritePackage NfcProtocol::MakeMifareWritePackage( | ||
| 890 | const MifareUUID& tag_uuid, std::span<const MifareWriteChunk> read_request) const { | ||
| 891 | MifareWritePackage package{ | ||
| 892 | .command_data{ | ||
| 893 | .unknown1 = 0xd0, | ||
| 894 | .unknown2 = 0x07, | ||
| 895 | .number_of_short_bytes = static_cast<u8>( | ||
| 896 | ((read_request.size() * sizeof(MifareReadChunk)) + sizeof(MifareUUID) + 2) / 2), | ||
| 897 | .uid = tag_uuid, | ||
| 898 | }, | ||
| 899 | .data_chunks = {}, | ||
| 900 | }; | ||
| 901 | |||
| 902 | for (std::size_t i = 0; i < read_request.size() && i < package.data_chunks.size(); ++i) { | ||
| 903 | package.data_chunks[i] = read_request[i]; | ||
| 904 | } | ||
| 905 | |||
| 906 | return package; | ||
| 907 | } | ||
| 908 | |||
| 530 | NFCDataChunk NfcProtocol::MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const { | 909 | NFCDataChunk NfcProtocol::MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const { |
| 531 | constexpr u8 NFC_PAGE_SIZE = 4; | 910 | constexpr u8 NFC_PAGE_SIZE = 4; |
| 532 | 911 | ||
| @@ -606,4 +985,8 @@ bool NfcProtocol::IsEnabled() const { | |||
| 606 | return is_enabled; | 985 | return is_enabled; |
| 607 | } | 986 | } |
| 608 | 987 | ||
| 988 | bool NfcProtocol::IsPolling() const { | ||
| 989 | return is_polling; | ||
| 990 | } | ||
| 991 | |||
| 609 | } // namespace InputCommon::Joycon | 992 | } // namespace InputCommon::Joycon |
diff --git a/src/input_common/helpers/joycon_protocol/nfc.h b/src/input_common/helpers/joycon_protocol/nfc.h index eb58c427d..22db95170 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.h +++ b/src/input_common/helpers/joycon_protocol/nfc.h | |||
| @@ -13,26 +13,41 @@ | |||
| 13 | #include "input_common/helpers/joycon_protocol/common_protocol.h" | 13 | #include "input_common/helpers/joycon_protocol/common_protocol.h" |
| 14 | #include "input_common/helpers/joycon_protocol/joycon_types.h" | 14 | #include "input_common/helpers/joycon_protocol/joycon_types.h" |
| 15 | 15 | ||
| 16 | namespace Common::Input { | ||
| 17 | enum class DriverResult; | ||
| 18 | } | ||
| 19 | |||
| 16 | namespace InputCommon::Joycon { | 20 | namespace InputCommon::Joycon { |
| 17 | 21 | ||
| 18 | class NfcProtocol final : private JoyconCommonProtocol { | 22 | class NfcProtocol final : private JoyconCommonProtocol { |
| 19 | public: | 23 | public: |
| 20 | explicit NfcProtocol(std::shared_ptr<JoyconHandle> handle); | 24 | explicit NfcProtocol(std::shared_ptr<JoyconHandle> handle); |
| 21 | 25 | ||
| 22 | DriverResult EnableNfc(); | 26 | Common::Input::DriverResult EnableNfc(); |
| 27 | |||
| 28 | Common::Input::DriverResult DisableNfc(); | ||
| 29 | |||
| 30 | Common::Input::DriverResult StartNFCPollingMode(); | ||
| 31 | |||
| 32 | Common::Input::DriverResult StopNFCPollingMode(); | ||
| 23 | 33 | ||
| 24 | DriverResult DisableNfc(); | 34 | Common::Input::DriverResult GetTagInfo(Joycon::TagInfo& tag_info); |
| 25 | 35 | ||
| 26 | DriverResult StartNFCPollingMode(); | 36 | Common::Input::DriverResult ReadAmiibo(std::vector<u8>& data); |
| 27 | 37 | ||
| 28 | DriverResult ScanAmiibo(std::vector<u8>& data); | 38 | Common::Input::DriverResult WriteAmiibo(std::span<const u8> data); |
| 29 | 39 | ||
| 30 | DriverResult WriteAmiibo(std::span<const u8> data); | 40 | Common::Input::DriverResult ReadMifare(std::span<const MifareReadChunk> read_request, |
| 41 | std::span<MifareReadData> out_data); | ||
| 42 | |||
| 43 | Common::Input::DriverResult WriteMifare(std::span<const MifareWriteChunk> write_request); | ||
| 31 | 44 | ||
| 32 | bool HasAmiibo(); | 45 | bool HasAmiibo(); |
| 33 | 46 | ||
| 34 | bool IsEnabled() const; | 47 | bool IsEnabled() const; |
| 35 | 48 | ||
| 49 | bool IsPolling() const; | ||
| 50 | |||
| 36 | private: | 51 | private: |
| 37 | // Number of times the function will be delayed until it outputs valid data | 52 | // Number of times the function will be delayed until it outputs valid data |
| 38 | static constexpr std::size_t AMIIBO_UPDATE_DELAY = 15; | 53 | static constexpr std::size_t AMIIBO_UPDATE_DELAY = 15; |
| @@ -43,39 +58,64 @@ private: | |||
| 43 | TagUUID uuid; | 58 | TagUUID uuid; |
| 44 | }; | 59 | }; |
| 45 | 60 | ||
| 46 | DriverResult WaitUntilNfcIs(NFCStatus status); | 61 | Common::Input::DriverResult WaitUntilNfcIs(NFCStatus status); |
| 62 | |||
| 63 | Common::Input::DriverResult IsTagInRange(TagFoundData& data, std::size_t timeout_limit = 1); | ||
| 47 | 64 | ||
| 48 | DriverResult IsTagInRange(TagFoundData& data, std::size_t timeout_limit = 1); | 65 | Common::Input::DriverResult GetAmiiboData(std::vector<u8>& data); |
| 49 | 66 | ||
| 50 | DriverResult GetAmiiboData(std::vector<u8>& data); | 67 | Common::Input::DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data); |
| 51 | 68 | ||
| 52 | DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data); | 69 | Common::Input::DriverResult GetMifareData(const MifareUUID& tag_uuid, |
| 70 | std::span<const MifareReadChunk> read_request, | ||
| 71 | std::span<MifareReadData> out_data); | ||
| 53 | 72 | ||
| 54 | DriverResult SendStartPollingRequest(MCUCommandResponse& output, | 73 | Common::Input::DriverResult WriteMifareData(const MifareUUID& tag_uuid, |
| 55 | bool is_second_attempt = false); | 74 | std::span<const MifareWriteChunk> write_request); |
| 56 | 75 | ||
| 57 | DriverResult SendStopPollingRequest(MCUCommandResponse& output); | 76 | Common::Input::DriverResult SendStartPollingRequest(MCUCommandResponse& output, |
| 77 | bool is_second_attempt = false); | ||
| 58 | 78 | ||
| 59 | DriverResult SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id); | 79 | Common::Input::DriverResult SendStopPollingRequest(MCUCommandResponse& output); |
| 60 | 80 | ||
| 61 | DriverResult SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages); | 81 | Common::Input::DriverResult SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id); |
| 62 | 82 | ||
| 63 | DriverResult SendWriteAmiiboRequest(MCUCommandResponse& output, const TagUUID& tag_uuid); | 83 | Common::Input::DriverResult SendReadAmiiboRequest(MCUCommandResponse& output, |
| 84 | NFCPages ntag_pages); | ||
| 64 | 85 | ||
| 65 | DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, | 86 | Common::Input::DriverResult SendWriteAmiiboRequest(MCUCommandResponse& output, |
| 66 | bool is_last_packet, std::span<const u8> data); | 87 | const TagUUID& tag_uuid); |
| 88 | |||
| 89 | Common::Input::DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, | ||
| 90 | bool is_last_packet, | ||
| 91 | std::span<const u8> data); | ||
| 92 | |||
| 93 | Common::Input::DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id, | ||
| 94 | bool is_last_packet, | ||
| 95 | std::span<const u8> data); | ||
| 67 | 96 | ||
| 68 | std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const; | 97 | std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const; |
| 69 | 98 | ||
| 99 | std::vector<u8> SerializeMifareReadPackage(const MifareReadPackage& package) const; | ||
| 100 | |||
| 101 | std::vector<u8> SerializeMifareWritePackage(const MifareWritePackage& package) const; | ||
| 102 | |||
| 70 | NFCWritePackage MakeAmiiboWritePackage(const TagUUID& tag_uuid, std::span<const u8> data) const; | 103 | NFCWritePackage MakeAmiiboWritePackage(const TagUUID& tag_uuid, std::span<const u8> data) const; |
| 71 | 104 | ||
| 72 | NFCDataChunk MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const; | 105 | NFCDataChunk MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const; |
| 73 | 106 | ||
| 107 | MifareReadPackage MakeMifareReadPackage(const MifareUUID& tag_uuid, | ||
| 108 | std::span<const MifareReadChunk> read_request) const; | ||
| 109 | |||
| 110 | MifareWritePackage MakeMifareWritePackage(const MifareUUID& tag_uuid, | ||
| 111 | std::span<const MifareWriteChunk> read_request) const; | ||
| 112 | |||
| 74 | NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const; | 113 | NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const; |
| 75 | 114 | ||
| 76 | TagUUID GetTagUUID(std::span<const u8> data) const; | 115 | TagUUID GetTagUUID(std::span<const u8> data) const; |
| 77 | 116 | ||
| 78 | bool is_enabled{}; | 117 | bool is_enabled{}; |
| 118 | bool is_polling{}; | ||
| 79 | std::size_t update_counter{}; | 119 | std::size_t update_counter{}; |
| 80 | }; | 120 | }; |
| 81 | 121 | ||
diff --git a/src/input_common/helpers/joycon_protocol/poller.cpp b/src/input_common/helpers/joycon_protocol/poller.cpp index dca797f7a..1aab9e12a 100644 --- a/src/input_common/helpers/joycon_protocol/poller.cpp +++ b/src/input_common/helpers/joycon_protocol/poller.cpp | |||
| @@ -70,8 +70,8 @@ void JoyconPoller::UpdateColor(const Color& color) { | |||
| 70 | callbacks.on_color_data(color); | 70 | callbacks.on_color_data(color); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | void JoyconPoller::UpdateAmiibo(const std::vector<u8>& amiibo_data) { | 73 | void JoyconPoller::UpdateAmiibo(const Joycon::TagInfo& tag_info) { |
| 74 | callbacks.on_amiibo_data(amiibo_data); | 74 | callbacks.on_amiibo_data(tag_info); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | void JoyconPoller::UpdateCamera(const std::vector<u8>& camera_data, IrsResolution format) { | 77 | void JoyconPoller::UpdateCamera(const std::vector<u8>& camera_data, IrsResolution format) { |
diff --git a/src/input_common/helpers/joycon_protocol/poller.h b/src/input_common/helpers/joycon_protocol/poller.h index 0fa72c6db..3746abe5d 100644 --- a/src/input_common/helpers/joycon_protocol/poller.h +++ b/src/input_common/helpers/joycon_protocol/poller.h | |||
| @@ -36,8 +36,8 @@ public: | |||
| 36 | 36 | ||
| 37 | void UpdateColor(const Color& color); | 37 | void UpdateColor(const Color& color); |
| 38 | void UpdateRing(s16 value, const RingStatus& ring_status); | 38 | void UpdateRing(s16 value, const RingStatus& ring_status); |
| 39 | void UpdateAmiibo(const std::vector<u8>& amiibo_data); | 39 | void UpdateAmiibo(const Joycon::TagInfo& tag_info); |
| 40 | void UpdateCamera(const std::vector<u8>& amiibo_data, IrsResolution format); | 40 | void UpdateCamera(const std::vector<u8>& camera_data, IrsResolution format); |
| 41 | 41 | ||
| 42 | private: | 42 | private: |
| 43 | void UpdateActiveLeftPadInput(const InputReportActive& input, | 43 | void UpdateActiveLeftPadInput(const InputReportActive& input, |
diff --git a/src/input_common/helpers/joycon_protocol/ringcon.cpp b/src/input_common/helpers/joycon_protocol/ringcon.cpp index 190cef812..96414fb67 100644 --- a/src/input_common/helpers/joycon_protocol/ringcon.cpp +++ b/src/input_common/helpers/joycon_protocol/ringcon.cpp | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2022 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/input.h" | ||
| 4 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 5 | #include "input_common/helpers/joycon_protocol/ringcon.h" | 6 | #include "input_common/helpers/joycon_protocol/ringcon.h" |
| 6 | 7 | ||
| @@ -9,18 +10,18 @@ namespace InputCommon::Joycon { | |||
| 9 | RingConProtocol::RingConProtocol(std::shared_ptr<JoyconHandle> handle) | 10 | RingConProtocol::RingConProtocol(std::shared_ptr<JoyconHandle> handle) |
| 10 | : JoyconCommonProtocol(std::move(handle)) {} | 11 | : JoyconCommonProtocol(std::move(handle)) {} |
| 11 | 12 | ||
| 12 | DriverResult RingConProtocol::EnableRingCon() { | 13 | Common::Input::DriverResult RingConProtocol::EnableRingCon() { |
| 13 | LOG_DEBUG(Input, "Enable Ringcon"); | 14 | LOG_DEBUG(Input, "Enable Ringcon"); |
| 14 | ScopedSetBlocking sb(this); | 15 | ScopedSetBlocking sb(this); |
| 15 | DriverResult result{DriverResult::Success}; | 16 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; |
| 16 | 17 | ||
| 17 | if (result == DriverResult::Success) { | 18 | if (result == Common::Input::DriverResult::Success) { |
| 18 | result = SetReportMode(ReportMode::STANDARD_FULL_60HZ); | 19 | result = SetReportMode(ReportMode::STANDARD_FULL_60HZ); |
| 19 | } | 20 | } |
| 20 | if (result == DriverResult::Success) { | 21 | if (result == Common::Input::DriverResult::Success) { |
| 21 | result = EnableMCU(true); | 22 | result = EnableMCU(true); |
| 22 | } | 23 | } |
| 23 | if (result == DriverResult::Success) { | 24 | if (result == Common::Input::DriverResult::Success) { |
| 24 | const MCUConfig config{ | 25 | const MCUConfig config{ |
| 25 | .command = MCUCommand::ConfigureMCU, | 26 | .command = MCUCommand::ConfigureMCU, |
| 26 | .sub_command = MCUSubCommand::SetDeviceMode, | 27 | .sub_command = MCUSubCommand::SetDeviceMode, |
| @@ -33,12 +34,12 @@ DriverResult RingConProtocol::EnableRingCon() { | |||
| 33 | return result; | 34 | return result; |
| 34 | } | 35 | } |
| 35 | 36 | ||
| 36 | DriverResult RingConProtocol::DisableRingCon() { | 37 | Common::Input::DriverResult RingConProtocol::DisableRingCon() { |
| 37 | LOG_DEBUG(Input, "Disable RingCon"); | 38 | LOG_DEBUG(Input, "Disable RingCon"); |
| 38 | ScopedSetBlocking sb(this); | 39 | ScopedSetBlocking sb(this); |
| 39 | DriverResult result{DriverResult::Success}; | 40 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; |
| 40 | 41 | ||
| 41 | if (result == DriverResult::Success) { | 42 | if (result == Common::Input::DriverResult::Success) { |
| 42 | result = EnableMCU(false); | 43 | result = EnableMCU(false); |
| 43 | } | 44 | } |
| 44 | 45 | ||
| @@ -47,29 +48,29 @@ DriverResult RingConProtocol::DisableRingCon() { | |||
| 47 | return result; | 48 | return result; |
| 48 | } | 49 | } |
| 49 | 50 | ||
| 50 | DriverResult RingConProtocol::StartRingconPolling() { | 51 | Common::Input::DriverResult RingConProtocol::StartRingconPolling() { |
| 51 | LOG_DEBUG(Input, "Enable Ringcon"); | 52 | LOG_DEBUG(Input, "Enable Ringcon"); |
| 52 | ScopedSetBlocking sb(this); | 53 | ScopedSetBlocking sb(this); |
| 53 | DriverResult result{DriverResult::Success}; | 54 | Common::Input::DriverResult result{Common::Input::DriverResult::Success}; |
| 54 | bool is_connected = false; | 55 | bool is_connected = false; |
| 55 | 56 | ||
| 56 | if (result == DriverResult::Success) { | 57 | if (result == Common::Input::DriverResult::Success) { |
| 57 | result = IsRingConnected(is_connected); | 58 | result = IsRingConnected(is_connected); |
| 58 | } | 59 | } |
| 59 | if (result == DriverResult::Success && is_connected) { | 60 | if (result == Common::Input::DriverResult::Success && is_connected) { |
| 60 | LOG_INFO(Input, "Ringcon detected"); | 61 | LOG_INFO(Input, "Ringcon detected"); |
| 61 | result = ConfigureRing(); | 62 | result = ConfigureRing(); |
| 62 | } | 63 | } |
| 63 | if (result == DriverResult::Success) { | 64 | if (result == Common::Input::DriverResult::Success) { |
| 64 | is_enabled = true; | 65 | is_enabled = true; |
| 65 | } | 66 | } |
| 66 | 67 | ||
| 67 | return result; | 68 | return result; |
| 68 | } | 69 | } |
| 69 | 70 | ||
| 70 | DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { | 71 | Common::Input::DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { |
| 71 | LOG_DEBUG(Input, "IsRingConnected"); | 72 | LOG_DEBUG(Input, "IsRingConnected"); |
| 72 | constexpr std::size_t max_tries = 28; | 73 | constexpr std::size_t max_tries = 42; |
| 73 | SubCommandResponse output{}; | 74 | SubCommandResponse output{}; |
| 74 | std::size_t tries = 0; | 75 | std::size_t tries = 0; |
| 75 | is_connected = false; | 76 | is_connected = false; |
| @@ -77,20 +78,21 @@ DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { | |||
| 77 | do { | 78 | do { |
| 78 | const auto result = SendSubCommand(SubCommand::GET_EXTERNAL_DEVICE_INFO, {}, output); | 79 | const auto result = SendSubCommand(SubCommand::GET_EXTERNAL_DEVICE_INFO, {}, output); |
| 79 | 80 | ||
| 80 | if (result != DriverResult::Success) { | 81 | if (result != Common::Input::DriverResult::Success && |
| 82 | result != Common::Input::DriverResult::Timeout) { | ||
| 81 | return result; | 83 | return result; |
| 82 | } | 84 | } |
| 83 | 85 | ||
| 84 | if (tries++ >= max_tries) { | 86 | if (tries++ >= max_tries) { |
| 85 | return DriverResult::NoDeviceDetected; | 87 | return Common::Input::DriverResult::NoDeviceDetected; |
| 86 | } | 88 | } |
| 87 | } while (output.external_device_id != ExternalDeviceId::RingController); | 89 | } while (output.external_device_id != ExternalDeviceId::RingController); |
| 88 | 90 | ||
| 89 | is_connected = true; | 91 | is_connected = true; |
| 90 | return DriverResult::Success; | 92 | return Common::Input::DriverResult::Success; |
| 91 | } | 93 | } |
| 92 | 94 | ||
| 93 | DriverResult RingConProtocol::ConfigureRing() { | 95 | Common::Input::DriverResult RingConProtocol::ConfigureRing() { |
| 94 | LOG_DEBUG(Input, "ConfigureRing"); | 96 | LOG_DEBUG(Input, "ConfigureRing"); |
| 95 | 97 | ||
| 96 | static constexpr std::array<u8, 37> ring_config{ | 98 | static constexpr std::array<u8, 37> ring_config{ |
| @@ -98,9 +100,10 @@ DriverResult RingConProtocol::ConfigureRing() { | |||
| 98 | 0x00, 0x00, 0x00, 0x0A, 0x64, 0x0B, 0xE6, 0xA9, 0x22, 0x00, 0x00, 0x04, 0x00, | 100 | 0x00, 0x00, 0x00, 0x0A, 0x64, 0x0B, 0xE6, 0xA9, 0x22, 0x00, 0x00, 0x04, 0x00, |
| 99 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xA8, 0xE1, 0x34, 0x36}; | 101 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xA8, 0xE1, 0x34, 0x36}; |
| 100 | 102 | ||
| 101 | const DriverResult result = SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config); | 103 | const Common::Input::DriverResult result = |
| 104 | SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config); | ||
| 102 | 105 | ||
| 103 | if (result != DriverResult::Success) { | 106 | if (result != Common::Input::DriverResult::Success) { |
| 104 | return result; | 107 | return result; |
| 105 | } | 108 | } |
| 106 | 109 | ||
diff --git a/src/input_common/helpers/joycon_protocol/ringcon.h b/src/input_common/helpers/joycon_protocol/ringcon.h index 6e858f3fc..9f0888de3 100644 --- a/src/input_common/helpers/joycon_protocol/ringcon.h +++ b/src/input_common/helpers/joycon_protocol/ringcon.h | |||
| @@ -13,24 +13,28 @@ | |||
| 13 | #include "input_common/helpers/joycon_protocol/common_protocol.h" | 13 | #include "input_common/helpers/joycon_protocol/common_protocol.h" |
| 14 | #include "input_common/helpers/joycon_protocol/joycon_types.h" | 14 | #include "input_common/helpers/joycon_protocol/joycon_types.h" |
| 15 | 15 | ||
| 16 | namespace Common::Input { | ||
| 17 | enum class DriverResult; | ||
| 18 | } | ||
| 19 | |||
| 16 | namespace InputCommon::Joycon { | 20 | namespace InputCommon::Joycon { |
| 17 | 21 | ||
| 18 | class RingConProtocol final : private JoyconCommonProtocol { | 22 | class RingConProtocol final : private JoyconCommonProtocol { |
| 19 | public: | 23 | public: |
| 20 | explicit RingConProtocol(std::shared_ptr<JoyconHandle> handle); | 24 | explicit RingConProtocol(std::shared_ptr<JoyconHandle> handle); |
| 21 | 25 | ||
| 22 | DriverResult EnableRingCon(); | 26 | Common::Input::DriverResult EnableRingCon(); |
| 23 | 27 | ||
| 24 | DriverResult DisableRingCon(); | 28 | Common::Input::DriverResult DisableRingCon(); |
| 25 | 29 | ||
| 26 | DriverResult StartRingconPolling(); | 30 | Common::Input::DriverResult StartRingconPolling(); |
| 27 | 31 | ||
| 28 | bool IsEnabled() const; | 32 | bool IsEnabled() const; |
| 29 | 33 | ||
| 30 | private: | 34 | private: |
| 31 | DriverResult IsRingConnected(bool& is_connected); | 35 | Common::Input::DriverResult IsRingConnected(bool& is_connected); |
| 32 | 36 | ||
| 33 | DriverResult ConfigureRing(); | 37 | Common::Input::DriverResult ConfigureRing(); |
| 34 | 38 | ||
| 35 | bool is_enabled{}; | 39 | bool is_enabled{}; |
| 36 | }; | 40 | }; |
diff --git a/src/input_common/helpers/joycon_protocol/rumble.cpp b/src/input_common/helpers/joycon_protocol/rumble.cpp index 63b60c946..7647f505e 100644 --- a/src/input_common/helpers/joycon_protocol/rumble.cpp +++ b/src/input_common/helpers/joycon_protocol/rumble.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #include <algorithm> | 4 | #include <algorithm> |
| 5 | #include <cmath> | 5 | #include <cmath> |
| 6 | 6 | ||
| 7 | #include "common/input.h" | ||
| 7 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 8 | #include "input_common/helpers/joycon_protocol/rumble.h" | 9 | #include "input_common/helpers/joycon_protocol/rumble.h" |
| 9 | 10 | ||
| @@ -12,14 +13,14 @@ namespace InputCommon::Joycon { | |||
| 12 | RumbleProtocol::RumbleProtocol(std::shared_ptr<JoyconHandle> handle) | 13 | RumbleProtocol::RumbleProtocol(std::shared_ptr<JoyconHandle> handle) |
| 13 | : JoyconCommonProtocol(std::move(handle)) {} | 14 | : JoyconCommonProtocol(std::move(handle)) {} |
| 14 | 15 | ||
| 15 | DriverResult RumbleProtocol::EnableRumble(bool is_enabled) { | 16 | Common::Input::DriverResult RumbleProtocol::EnableRumble(bool is_enabled) { |
| 16 | LOG_DEBUG(Input, "Enable Rumble"); | 17 | LOG_DEBUG(Input, "Enable Rumble"); |
| 17 | ScopedSetBlocking sb(this); | 18 | ScopedSetBlocking sb(this); |
| 18 | const std::array<u8, 1> buffer{static_cast<u8>(is_enabled ? 1 : 0)}; | 19 | const std::array<u8, 1> buffer{static_cast<u8>(is_enabled ? 1 : 0)}; |
| 19 | return SendSubCommand(SubCommand::ENABLE_VIBRATION, buffer); | 20 | return SendSubCommand(SubCommand::ENABLE_VIBRATION, buffer); |
| 20 | } | 21 | } |
| 21 | 22 | ||
| 22 | DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) { | 23 | Common::Input::DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) { |
| 23 | std::array<u8, sizeof(DefaultVibrationBuffer)> buffer{}; | 24 | std::array<u8, sizeof(DefaultVibrationBuffer)> buffer{}; |
| 24 | 25 | ||
| 25 | if (vibration.high_amplitude <= 0.0f && vibration.low_amplitude <= 0.0f) { | 26 | if (vibration.high_amplitude <= 0.0f && vibration.low_amplitude <= 0.0f) { |
diff --git a/src/input_common/helpers/joycon_protocol/rumble.h b/src/input_common/helpers/joycon_protocol/rumble.h index 6c12b7925..5e50e531a 100644 --- a/src/input_common/helpers/joycon_protocol/rumble.h +++ b/src/input_common/helpers/joycon_protocol/rumble.h | |||
| @@ -13,15 +13,19 @@ | |||
| 13 | #include "input_common/helpers/joycon_protocol/common_protocol.h" | 13 | #include "input_common/helpers/joycon_protocol/common_protocol.h" |
| 14 | #include "input_common/helpers/joycon_protocol/joycon_types.h" | 14 | #include "input_common/helpers/joycon_protocol/joycon_types.h" |
| 15 | 15 | ||
| 16 | namespace Common::Input { | ||
| 17 | enum class DriverResult; | ||
| 18 | } | ||
| 19 | |||
| 16 | namespace InputCommon::Joycon { | 20 | namespace InputCommon::Joycon { |
| 17 | 21 | ||
| 18 | class RumbleProtocol final : private JoyconCommonProtocol { | 22 | class RumbleProtocol final : private JoyconCommonProtocol { |
| 19 | public: | 23 | public: |
| 20 | explicit RumbleProtocol(std::shared_ptr<JoyconHandle> handle); | 24 | explicit RumbleProtocol(std::shared_ptr<JoyconHandle> handle); |
| 21 | 25 | ||
| 22 | DriverResult EnableRumble(bool is_enabled); | 26 | Common::Input::DriverResult EnableRumble(bool is_enabled); |
| 23 | 27 | ||
| 24 | DriverResult SendVibration(const VibrationValue& vibration); | 28 | Common::Input::DriverResult SendVibration(const VibrationValue& vibration); |
| 25 | 29 | ||
| 26 | private: | 30 | private: |
| 27 | u16 EncodeHighFrequency(f32 frequency) const; | 31 | u16 EncodeHighFrequency(f32 frequency) const; |
diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 50b5a3dc8..c2d0cbb34 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h | |||
| @@ -143,12 +143,46 @@ public: | |||
| 143 | return Common::Input::NfcState::NotSupported; | 143 | return Common::Input::NfcState::NotSupported; |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | // Start scanning for nfc tags | ||
| 147 | virtual Common::Input::NfcState StartNfcPolling( | ||
| 148 | [[maybe_unused]] const PadIdentifier& identifier_) { | ||
| 149 | return Common::Input::NfcState::NotSupported; | ||
| 150 | } | ||
| 151 | |||
| 152 | // Start scanning for nfc tags | ||
| 153 | virtual Common::Input::NfcState StopNfcPolling( | ||
| 154 | [[maybe_unused]] const PadIdentifier& identifier_) { | ||
| 155 | return Common::Input::NfcState::NotSupported; | ||
| 156 | } | ||
| 157 | |||
| 158 | // Reads data from amiibo tag | ||
| 159 | virtual Common::Input::NfcState ReadAmiiboData( | ||
| 160 | [[maybe_unused]] const PadIdentifier& identifier_, | ||
| 161 | [[maybe_unused]] std::vector<u8>& out_data) { | ||
| 162 | return Common::Input::NfcState::NotSupported; | ||
| 163 | } | ||
| 164 | |||
| 146 | // Writes data to an nfc tag | 165 | // Writes data to an nfc tag |
| 147 | virtual Common::Input::NfcState WriteNfcData([[maybe_unused]] const PadIdentifier& identifier, | 166 | virtual Common::Input::NfcState WriteNfcData([[maybe_unused]] const PadIdentifier& identifier, |
| 148 | [[maybe_unused]] const std::vector<u8>& data) { | 167 | [[maybe_unused]] const std::vector<u8>& data) { |
| 149 | return Common::Input::NfcState::NotSupported; | 168 | return Common::Input::NfcState::NotSupported; |
| 150 | } | 169 | } |
| 151 | 170 | ||
| 171 | // Reads data from mifare tag | ||
| 172 | virtual Common::Input::NfcState ReadMifareData( | ||
| 173 | [[maybe_unused]] const PadIdentifier& identifier_, | ||
| 174 | [[maybe_unused]] const Common::Input::MifareRequest& request, | ||
| 175 | [[maybe_unused]] Common::Input::MifareRequest& out_data) { | ||
| 176 | return Common::Input::NfcState::NotSupported; | ||
| 177 | } | ||
| 178 | |||
| 179 | // Write data to mifare tag | ||
| 180 | virtual Common::Input::NfcState WriteMifareData( | ||
| 181 | [[maybe_unused]] const PadIdentifier& identifier_, | ||
| 182 | [[maybe_unused]] const Common::Input::MifareRequest& request) { | ||
| 183 | return Common::Input::NfcState::NotSupported; | ||
| 184 | } | ||
| 185 | |||
| 152 | // Returns the engine name | 186 | // Returns the engine name |
| 153 | [[nodiscard]] const std::string& GetEngineName() const; | 187 | [[nodiscard]] const std::string& GetEngineName() const; |
| 154 | 188 | ||
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 380a01542..870e76ab0 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp | |||
| @@ -792,8 +792,7 @@ public: | |||
| 792 | 792 | ||
| 793 | const Common::Input::CallbackStatus status{ | 793 | const Common::Input::CallbackStatus status{ |
| 794 | .type = Common::Input::InputType::Nfc, | 794 | .type = Common::Input::InputType::Nfc, |
| 795 | .nfc_status = nfc_status.state, | 795 | .nfc_status = nfc_status, |
| 796 | .raw_data = nfc_status.data, | ||
| 797 | }; | 796 | }; |
| 798 | 797 | ||
| 799 | TriggerOnChange(status); | 798 | TriggerOnChange(status); |
| @@ -836,10 +835,31 @@ public: | |||
| 836 | return input_engine->SupportsNfc(identifier); | 835 | return input_engine->SupportsNfc(identifier); |
| 837 | } | 836 | } |
| 838 | 837 | ||
| 838 | Common::Input::NfcState StartNfcPolling() { | ||
| 839 | return input_engine->StartNfcPolling(identifier); | ||
| 840 | } | ||
| 841 | |||
| 842 | Common::Input::NfcState StopNfcPolling() { | ||
| 843 | return input_engine->StopNfcPolling(identifier); | ||
| 844 | } | ||
| 845 | |||
| 846 | Common::Input::NfcState ReadAmiiboData(std::vector<u8>& out_data) { | ||
| 847 | return input_engine->ReadAmiiboData(identifier, out_data); | ||
| 848 | } | ||
| 849 | |||
| 839 | Common::Input::NfcState WriteNfcData(const std::vector<u8>& data) override { | 850 | Common::Input::NfcState WriteNfcData(const std::vector<u8>& data) override { |
| 840 | return input_engine->WriteNfcData(identifier, data); | 851 | return input_engine->WriteNfcData(identifier, data); |
| 841 | } | 852 | } |
| 842 | 853 | ||
| 854 | Common::Input::NfcState ReadMifareData(const Common::Input::MifareRequest& request, | ||
| 855 | Common::Input::MifareRequest& out_data) { | ||
| 856 | return input_engine->ReadMifareData(identifier, request, out_data); | ||
| 857 | } | ||
| 858 | |||
| 859 | Common::Input::NfcState WriteMifareData(const Common::Input::MifareRequest& request) { | ||
| 860 | return input_engine->WriteMifareData(identifier, request); | ||
| 861 | } | ||
| 862 | |||
| 843 | private: | 863 | private: |
| 844 | const PadIdentifier identifier; | 864 | const PadIdentifier identifier; |
| 845 | InputEngine* input_engine; | 865 | InputEngine* input_engine; |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp index fd4a61a4d..b795c0179 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp | |||
| @@ -461,7 +461,7 @@ std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, I | |||
| 461 | header += fmt::format("R{},", index); | 461 | header += fmt::format("R{},", index); |
| 462 | } | 462 | } |
| 463 | if (program.local_memory_size > 0) { | 463 | if (program.local_memory_size > 0) { |
| 464 | header += fmt::format("lmem[{}],", program.local_memory_size); | 464 | header += fmt::format("lmem[{}],", Common::DivCeil(program.local_memory_size, 4U)); |
| 465 | } | 465 | } |
| 466 | if (program.info.uses_fswzadd) { | 466 | if (program.info.uses_fswzadd) { |
| 467 | header += "FSWZA[4],FSWZB[4],"; | 467 | header += "FSWZA[4],FSWZB[4],"; |
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp index c3c2281bb..9ff4028c2 100644 --- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp +++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp | |||
| @@ -479,7 +479,7 @@ void EmitContext::DefineGenericOutput(size_t index, u32 invocations) { | |||
| 479 | const u32 remainder{4 - element}; | 479 | const u32 remainder{4 - element}; |
| 480 | const TransformFeedbackVarying* xfb_varying{}; | 480 | const TransformFeedbackVarying* xfb_varying{}; |
| 481 | const size_t xfb_varying_index{base_index + element}; | 481 | const size_t xfb_varying_index{base_index + element}; |
| 482 | if (xfb_varying_index < runtime_info.xfb_varyings.size()) { | 482 | if (xfb_varying_index < runtime_info.xfb_count) { |
| 483 | xfb_varying = &runtime_info.xfb_varyings[xfb_varying_index]; | 483 | xfb_varying = &runtime_info.xfb_varyings[xfb_varying_index]; |
| 484 | xfb_varying = xfb_varying->components > 0 ? xfb_varying : nullptr; | 484 | xfb_varying = xfb_varying->components > 0 ? xfb_varying : nullptr; |
| 485 | } | 485 | } |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 0f86a8004..34592a01f 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp | |||
| @@ -387,7 +387,7 @@ void SetupSignedNanCapabilities(const Profile& profile, const IR::Program& progr | |||
| 387 | } | 387 | } |
| 388 | 388 | ||
| 389 | void SetupTransformFeedbackCapabilities(EmitContext& ctx, Id main_func) { | 389 | void SetupTransformFeedbackCapabilities(EmitContext& ctx, Id main_func) { |
| 390 | if (ctx.runtime_info.xfb_varyings.empty()) { | 390 | if (ctx.runtime_info.xfb_count == 0) { |
| 391 | return; | 391 | return; |
| 392 | } | 392 | } |
| 393 | ctx.AddCapability(spv::Capability::TransformFeedback); | 393 | ctx.AddCapability(spv::Capability::TransformFeedback); |
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index fd15f47ea..bec5db173 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp | |||
| @@ -160,7 +160,7 @@ void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invo | |||
| 160 | const u32 remainder{4 - element}; | 160 | const u32 remainder{4 - element}; |
| 161 | const TransformFeedbackVarying* xfb_varying{}; | 161 | const TransformFeedbackVarying* xfb_varying{}; |
| 162 | const size_t xfb_varying_index{base_attr_index + element}; | 162 | const size_t xfb_varying_index{base_attr_index + element}; |
| 163 | if (xfb_varying_index < ctx.runtime_info.xfb_varyings.size()) { | 163 | if (xfb_varying_index < ctx.runtime_info.xfb_count) { |
| 164 | xfb_varying = &ctx.runtime_info.xfb_varyings[xfb_varying_index]; | 164 | xfb_varying = &ctx.runtime_info.xfb_varyings[xfb_varying_index]; |
| 165 | xfb_varying = xfb_varying->components > 0 ? xfb_varying : nullptr; | 165 | xfb_varying = xfb_varying->components > 0 ? xfb_varying : nullptr; |
| 166 | } | 166 | } |
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp index 5a4195217..70292686f 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | |||
| @@ -424,6 +424,10 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 424 | info.used_constant_buffer_types |= IR::Type::U32 | IR::Type::U32x2; | 424 | info.used_constant_buffer_types |= IR::Type::U32 | IR::Type::U32x2; |
| 425 | info.used_storage_buffer_types |= IR::Type::U32 | IR::Type::U32x2 | IR::Type::U32x4; | 425 | info.used_storage_buffer_types |= IR::Type::U32 | IR::Type::U32x2 | IR::Type::U32x4; |
| 426 | break; | 426 | break; |
| 427 | case IR::Opcode::LoadLocal: | ||
| 428 | case IR::Opcode::WriteLocal: | ||
| 429 | info.uses_local_memory = true; | ||
| 430 | break; | ||
| 427 | default: | 431 | default: |
| 428 | break; | 432 | break; |
| 429 | } | 433 | } |
diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h index 3b63c249f..619c0b138 100644 --- a/src/shader_recompiler/runtime_info.h +++ b/src/shader_recompiler/runtime_info.h | |||
| @@ -84,7 +84,8 @@ struct RuntimeInfo { | |||
| 84 | bool glasm_use_storage_buffers{}; | 84 | bool glasm_use_storage_buffers{}; |
| 85 | 85 | ||
| 86 | /// Transform feedback state for each varying | 86 | /// Transform feedback state for each varying |
| 87 | std::vector<TransformFeedbackVarying> xfb_varyings; | 87 | std::array<TransformFeedbackVarying, 256> xfb_varyings{}; |
| 88 | u32 xfb_count{0}; | ||
| 88 | }; | 89 | }; |
| 89 | 90 | ||
| 90 | } // namespace Shader | 91 | } // namespace Shader |
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index d308db942..b4b4afd37 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h | |||
| @@ -172,6 +172,7 @@ struct Info { | |||
| 172 | bool stores_indexed_attributes{}; | 172 | bool stores_indexed_attributes{}; |
| 173 | 173 | ||
| 174 | bool stores_global_memory{}; | 174 | bool stores_global_memory{}; |
| 175 | bool uses_local_memory{}; | ||
| 175 | 176 | ||
| 176 | bool uses_fp16{}; | 177 | bool uses_fp16{}; |
| 177 | bool uses_fp64{}; | 178 | bool uses_fp64{}; |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index bf6439530..3b2fe01da 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -220,8 +220,8 @@ add_library(video_core STATIC | |||
| 220 | surface.h | 220 | surface.h |
| 221 | texture_cache/accelerated_swizzle.cpp | 221 | texture_cache/accelerated_swizzle.cpp |
| 222 | texture_cache/accelerated_swizzle.h | 222 | texture_cache/accelerated_swizzle.h |
| 223 | texture_cache/decode_bc4.cpp | 223 | texture_cache/decode_bc.cpp |
| 224 | texture_cache/decode_bc4.h | 224 | texture_cache/decode_bc.h |
| 225 | texture_cache/descriptor_table.h | 225 | texture_cache/descriptor_table.h |
| 226 | texture_cache/formatter.cpp | 226 | texture_cache/formatter.cpp |
| 227 | texture_cache/formatter.h | 227 | texture_cache/formatter.h |
| @@ -279,7 +279,7 @@ add_library(video_core STATIC | |||
| 279 | create_target_directory_groups(video_core) | 279 | create_target_directory_groups(video_core) |
| 280 | 280 | ||
| 281 | target_link_libraries(video_core PUBLIC common core) | 281 | target_link_libraries(video_core PUBLIC common core) |
| 282 | target_link_libraries(video_core PUBLIC glad shader_recompiler stb) | 282 | target_link_libraries(video_core PUBLIC glad shader_recompiler stb bc_decoder) |
| 283 | 283 | ||
| 284 | if (YUZU_USE_BUNDLED_FFMPEG AND NOT (WIN32 OR ANDROID)) | 284 | if (YUZU_USE_BUNDLED_FFMPEG AND NOT (WIN32 OR ANDROID)) |
| 285 | add_dependencies(video_core ffmpeg-build) | 285 | add_dependencies(video_core ffmpeg-build) |
| @@ -291,7 +291,7 @@ target_link_options(video_core PRIVATE ${FFmpeg_LDFLAGS}) | |||
| 291 | 291 | ||
| 292 | add_dependencies(video_core host_shaders) | 292 | add_dependencies(video_core host_shaders) |
| 293 | target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) | 293 | target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) |
| 294 | target_link_libraries(video_core PRIVATE sirit Vulkan::Headers) | 294 | target_link_libraries(video_core PRIVATE sirit Vulkan::Headers vma) |
| 295 | 295 | ||
| 296 | if (ENABLE_NSIGHT_AFTERMATH) | 296 | if (ENABLE_NSIGHT_AFTERMATH) |
| 297 | if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK}) | 297 | if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK}) |
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 45977d578..58a45ab67 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h | |||
| @@ -207,7 +207,7 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am | |||
| 207 | if (has_new_downloads) { | 207 | if (has_new_downloads) { |
| 208 | memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount); | 208 | memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount); |
| 209 | } | 209 | } |
| 210 | tmp_buffer.resize(amount); | 210 | tmp_buffer.resize_destructive(amount); |
| 211 | cpu_memory.ReadBlockUnsafe(*cpu_src_address, tmp_buffer.data(), amount); | 211 | cpu_memory.ReadBlockUnsafe(*cpu_src_address, tmp_buffer.data(), amount); |
| 212 | cpu_memory.WriteBlockUnsafe(*cpu_dest_address, tmp_buffer.data(), amount); | 212 | cpu_memory.WriteBlockUnsafe(*cpu_dest_address, tmp_buffer.data(), amount); |
| 213 | return true; | 213 | return true; |
| @@ -1279,7 +1279,7 @@ template <class P> | |||
| 1279 | typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(VAddr cpu_addr, | 1279 | typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(VAddr cpu_addr, |
| 1280 | u32 wanted_size) { | 1280 | u32 wanted_size) { |
| 1281 | static constexpr int STREAM_LEAP_THRESHOLD = 16; | 1281 | static constexpr int STREAM_LEAP_THRESHOLD = 16; |
| 1282 | std::vector<BufferId> overlap_ids; | 1282 | boost::container::small_vector<BufferId, 16> overlap_ids; |
| 1283 | VAddr begin = cpu_addr; | 1283 | VAddr begin = cpu_addr; |
| 1284 | VAddr end = cpu_addr + wanted_size; | 1284 | VAddr end = cpu_addr + wanted_size; |
| 1285 | int stream_score = 0; | 1285 | int stream_score = 0; |
diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h index 63a120f7a..fe6068cfe 100644 --- a/src/video_core/buffer_cache/buffer_cache_base.h +++ b/src/video_core/buffer_cache/buffer_cache_base.h | |||
| @@ -229,7 +229,7 @@ class BufferCache : public VideoCommon::ChannelSetupCaches<BufferCacheChannelInf | |||
| 229 | using OverlapCounter = boost::icl::split_interval_map<VAddr, int>; | 229 | using OverlapCounter = boost::icl::split_interval_map<VAddr, int>; |
| 230 | 230 | ||
| 231 | struct OverlapResult { | 231 | struct OverlapResult { |
| 232 | std::vector<BufferId> ids; | 232 | boost::container::small_vector<BufferId, 16> ids; |
| 233 | VAddr begin; | 233 | VAddr begin; |
| 234 | VAddr end; | 234 | VAddr end; |
| 235 | bool has_stream_leap = false; | 235 | bool has_stream_leap = false; |
| @@ -582,7 +582,7 @@ private: | |||
| 582 | BufferId inline_buffer_id; | 582 | BufferId inline_buffer_id; |
| 583 | 583 | ||
| 584 | std::array<BufferId, ((1ULL << 39) >> CACHING_PAGEBITS)> page_table; | 584 | std::array<BufferId, ((1ULL << 39) >> CACHING_PAGEBITS)> page_table; |
| 585 | std::vector<u8> tmp_buffer; | 585 | Common::ScratchBuffer<u8> tmp_buffer; |
| 586 | }; | 586 | }; |
| 587 | 587 | ||
| 588 | } // namespace VideoCommon | 588 | } // namespace VideoCommon |
diff --git a/src/video_core/cdma_pusher.h b/src/video_core/cdma_pusher.h index 83112dfce..7d660af47 100644 --- a/src/video_core/cdma_pusher.h +++ b/src/video_core/cdma_pusher.h | |||
| @@ -63,7 +63,6 @@ struct ChCommand { | |||
| 63 | }; | 63 | }; |
| 64 | 64 | ||
| 65 | using ChCommandHeaderList = std::vector<ChCommandHeader>; | 65 | using ChCommandHeaderList = std::vector<ChCommandHeader>; |
| 66 | using ChCommandList = std::vector<ChCommand>; | ||
| 67 | 66 | ||
| 68 | struct ThiRegisters { | 67 | struct ThiRegisters { |
| 69 | u32_le increment_syncpt{}; | 68 | u32_le increment_syncpt{}; |
diff --git a/src/video_core/dma_pusher.h b/src/video_core/dma_pusher.h index 1cdb690ed..8a2784cdc 100644 --- a/src/video_core/dma_pusher.h +++ b/src/video_core/dma_pusher.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <array> | 6 | #include <array> |
| 7 | #include <span> | 7 | #include <span> |
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | #include <boost/container/small_vector.hpp> | ||
| 9 | #include <queue> | 10 | #include <queue> |
| 10 | 11 | ||
| 11 | #include "common/bit_field.h" | 12 | #include "common/bit_field.h" |
| @@ -102,11 +103,12 @@ inline CommandHeader BuildCommandHeader(BufferMethods method, u32 arg_count, Sub | |||
| 102 | struct CommandList final { | 103 | struct CommandList final { |
| 103 | CommandList() = default; | 104 | CommandList() = default; |
| 104 | explicit CommandList(std::size_t size) : command_lists(size) {} | 105 | explicit CommandList(std::size_t size) : command_lists(size) {} |
| 105 | explicit CommandList(std::vector<CommandHeader>&& prefetch_command_list_) | 106 | explicit CommandList( |
| 107 | boost::container::small_vector<CommandHeader, 512>&& prefetch_command_list_) | ||
| 106 | : prefetch_command_list{std::move(prefetch_command_list_)} {} | 108 | : prefetch_command_list{std::move(prefetch_command_list_)} {} |
| 107 | 109 | ||
| 108 | std::vector<CommandListHeader> command_lists; | 110 | boost::container::small_vector<CommandListHeader, 512> command_lists; |
| 109 | std::vector<CommandHeader> prefetch_command_list; | 111 | boost::container::small_vector<CommandHeader, 512> prefetch_command_list; |
| 110 | }; | 112 | }; |
| 111 | 113 | ||
| 112 | /** | 114 | /** |
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index ebe5536de..a290d6ea7 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp | |||
| @@ -108,9 +108,11 @@ void MaxwellDMA::Launch() { | |||
| 108 | if (regs.launch_dma.remap_enable != 0 && is_const_a_dst) { | 108 | if (regs.launch_dma.remap_enable != 0 && is_const_a_dst) { |
| 109 | ASSERT(regs.remap_const.component_size_minus_one == 3); | 109 | ASSERT(regs.remap_const.component_size_minus_one == 3); |
| 110 | accelerate.BufferClear(regs.offset_out, regs.line_length_in, regs.remap_consta_value); | 110 | accelerate.BufferClear(regs.offset_out, regs.line_length_in, regs.remap_consta_value); |
| 111 | std::vector<u32> tmp_buffer(regs.line_length_in, regs.remap_consta_value); | 111 | read_buffer.resize_destructive(regs.line_length_in * sizeof(u32)); |
| 112 | std::span<u32> span(reinterpret_cast<u32*>(read_buffer.data()), regs.line_length_in); | ||
| 113 | std::ranges::fill(span, regs.remap_consta_value); | ||
| 112 | memory_manager.WriteBlockUnsafe(regs.offset_out, | 114 | memory_manager.WriteBlockUnsafe(regs.offset_out, |
| 113 | reinterpret_cast<u8*>(tmp_buffer.data()), | 115 | reinterpret_cast<u8*>(read_buffer.data()), |
| 114 | regs.line_length_in * sizeof(u32)); | 116 | regs.line_length_in * sizeof(u32)); |
| 115 | } else { | 117 | } else { |
| 116 | memory_manager.FlushCaching(); | 118 | memory_manager.FlushCaching(); |
| @@ -126,32 +128,33 @@ void MaxwellDMA::Launch() { | |||
| 126 | UNIMPLEMENTED_IF(regs.line_length_in % 16 != 0); | 128 | UNIMPLEMENTED_IF(regs.line_length_in % 16 != 0); |
| 127 | UNIMPLEMENTED_IF(regs.offset_in % 16 != 0); | 129 | UNIMPLEMENTED_IF(regs.offset_in % 16 != 0); |
| 128 | UNIMPLEMENTED_IF(regs.offset_out % 16 != 0); | 130 | UNIMPLEMENTED_IF(regs.offset_out % 16 != 0); |
| 129 | std::vector<u8> tmp_buffer(16); | 131 | read_buffer.resize_destructive(16); |
| 130 | for (u32 offset = 0; offset < regs.line_length_in; offset += 16) { | 132 | for (u32 offset = 0; offset < regs.line_length_in; offset += 16) { |
| 131 | memory_manager.ReadBlockUnsafe( | 133 | memory_manager.ReadBlock( |
| 132 | convert_linear_2_blocklinear_addr(regs.offset_in + offset), | 134 | convert_linear_2_blocklinear_addr(regs.offset_in + offset), |
| 133 | tmp_buffer.data(), tmp_buffer.size()); | 135 | read_buffer.data(), read_buffer.size()); |
| 134 | memory_manager.WriteBlockCached(regs.offset_out + offset, tmp_buffer.data(), | 136 | memory_manager.WriteBlockCached(regs.offset_out + offset, read_buffer.data(), |
| 135 | tmp_buffer.size()); | 137 | read_buffer.size()); |
| 136 | } | 138 | } |
| 137 | } else if (is_src_pitch && !is_dst_pitch) { | 139 | } else if (is_src_pitch && !is_dst_pitch) { |
| 138 | UNIMPLEMENTED_IF(regs.line_length_in % 16 != 0); | 140 | UNIMPLEMENTED_IF(regs.line_length_in % 16 != 0); |
| 139 | UNIMPLEMENTED_IF(regs.offset_in % 16 != 0); | 141 | UNIMPLEMENTED_IF(regs.offset_in % 16 != 0); |
| 140 | UNIMPLEMENTED_IF(regs.offset_out % 16 != 0); | 142 | UNIMPLEMENTED_IF(regs.offset_out % 16 != 0); |
| 141 | std::vector<u8> tmp_buffer(16); | 143 | read_buffer.resize_destructive(16); |
| 142 | for (u32 offset = 0; offset < regs.line_length_in; offset += 16) { | 144 | for (u32 offset = 0; offset < regs.line_length_in; offset += 16) { |
| 143 | memory_manager.ReadBlockUnsafe(regs.offset_in + offset, tmp_buffer.data(), | 145 | memory_manager.ReadBlock(regs.offset_in + offset, read_buffer.data(), |
| 144 | tmp_buffer.size()); | 146 | read_buffer.size()); |
| 145 | memory_manager.WriteBlockCached( | 147 | memory_manager.WriteBlockCached( |
| 146 | convert_linear_2_blocklinear_addr(regs.offset_out + offset), | 148 | convert_linear_2_blocklinear_addr(regs.offset_out + offset), |
| 147 | tmp_buffer.data(), tmp_buffer.size()); | 149 | read_buffer.data(), read_buffer.size()); |
| 148 | } | 150 | } |
| 149 | } else { | 151 | } else { |
| 150 | if (!accelerate.BufferCopy(regs.offset_in, regs.offset_out, regs.line_length_in)) { | 152 | if (!accelerate.BufferCopy(regs.offset_in, regs.offset_out, regs.line_length_in)) { |
| 151 | std::vector<u8> tmp_buffer(regs.line_length_in); | 153 | read_buffer.resize_destructive(regs.line_length_in); |
| 152 | memory_manager.ReadBlockUnsafe(regs.offset_in, tmp_buffer.data(), | 154 | memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), |
| 153 | regs.line_length_in); | 155 | regs.line_length_in, |
| 154 | memory_manager.WriteBlockCached(regs.offset_out, tmp_buffer.data(), | 156 | VideoCommon::CacheType::NoBufferCache); |
| 157 | memory_manager.WriteBlockCached(regs.offset_out, read_buffer.data(), | ||
| 155 | regs.line_length_in); | 158 | regs.line_length_in); |
| 156 | } | 159 | } |
| 157 | } | 160 | } |
| @@ -171,7 +174,8 @@ void MaxwellDMA::CopyBlockLinearToPitch() { | |||
| 171 | src_operand.address = regs.offset_in; | 174 | src_operand.address = regs.offset_in; |
| 172 | 175 | ||
| 173 | DMA::BufferOperand dst_operand; | 176 | DMA::BufferOperand dst_operand; |
| 174 | dst_operand.pitch = regs.pitch_out; | 177 | u32 abs_pitch_out = std::abs(static_cast<s32>(regs.pitch_out)); |
| 178 | dst_operand.pitch = abs_pitch_out; | ||
| 175 | dst_operand.width = regs.line_length_in; | 179 | dst_operand.width = regs.line_length_in; |
| 176 | dst_operand.height = regs.line_count; | 180 | dst_operand.height = regs.line_count; |
| 177 | dst_operand.address = regs.offset_out; | 181 | dst_operand.address = regs.offset_out; |
| @@ -218,7 +222,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() { | |||
| 218 | const size_t src_size = | 222 | const size_t src_size = |
| 219 | CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth); | 223 | CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth); |
| 220 | 224 | ||
| 221 | const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count; | 225 | const size_t dst_size = static_cast<size_t>(abs_pitch_out) * regs.line_count; |
| 222 | read_buffer.resize_destructive(src_size); | 226 | read_buffer.resize_destructive(src_size); |
| 223 | write_buffer.resize_destructive(dst_size); | 227 | write_buffer.resize_destructive(dst_size); |
| 224 | 228 | ||
| @@ -227,7 +231,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() { | |||
| 227 | 231 | ||
| 228 | UnswizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset, | 232 | UnswizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset, |
| 229 | src_params.origin.y, x_elements, regs.line_count, block_height, block_depth, | 233 | src_params.origin.y, x_elements, regs.line_count, block_height, block_depth, |
| 230 | regs.pitch_out); | 234 | abs_pitch_out); |
| 231 | 235 | ||
| 232 | memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size); | 236 | memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size); |
| 233 | } | 237 | } |
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 456f733cf..db385076d 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp | |||
| @@ -193,18 +193,13 @@ struct GPU::Impl { | |||
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | [[nodiscard]] u64 GetTicks() const { | 195 | [[nodiscard]] u64 GetTicks() const { |
| 196 | // This values were reversed engineered by fincs from NVN | 196 | u64 gpu_tick = system.CoreTiming().GetGPUTicks(); |
| 197 | // The gpu clock is reported in units of 385/625 nanoseconds | ||
| 198 | constexpr u64 gpu_ticks_num = 384; | ||
| 199 | constexpr u64 gpu_ticks_den = 625; | ||
| 200 | 197 | ||
| 201 | u64 nanoseconds = system.CoreTiming().GetCPUTimeNs().count(); | ||
| 202 | if (Settings::values.use_fast_gpu_time.GetValue()) { | 198 | if (Settings::values.use_fast_gpu_time.GetValue()) { |
| 203 | nanoseconds /= 256; | 199 | gpu_tick /= 256; |
| 204 | } | 200 | } |
| 205 | const u64 nanoseconds_num = nanoseconds / gpu_ticks_den; | 201 | |
| 206 | const u64 nanoseconds_rem = nanoseconds % gpu_ticks_den; | 202 | return gpu_tick; |
| 207 | return nanoseconds_num * gpu_ticks_num + (nanoseconds_rem * gpu_ticks_num) / gpu_ticks_den; | ||
| 208 | } | 203 | } |
| 209 | 204 | ||
| 210 | [[nodiscard]] bool IsAsync() const { | 205 | [[nodiscard]] bool IsAsync() const { |
diff --git a/src/video_core/host1x/codecs/h264.cpp b/src/video_core/host1x/codecs/h264.cpp index 6ce179167..ce827eb6c 100644 --- a/src/video_core/host1x/codecs/h264.cpp +++ b/src/video_core/host1x/codecs/h264.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #include <array> | 4 | #include <array> |
| 5 | #include <bit> | 5 | #include <bit> |
| 6 | 6 | ||
| 7 | #include "common/scratch_buffer.h" | ||
| 7 | #include "common/settings.h" | 8 | #include "common/settings.h" |
| 8 | #include "video_core/host1x/codecs/h264.h" | 9 | #include "video_core/host1x/codecs/h264.h" |
| 9 | #include "video_core/host1x/host1x.h" | 10 | #include "video_core/host1x/host1x.h" |
| @@ -188,7 +189,8 @@ void H264BitWriter::WriteBit(bool state) { | |||
| 188 | } | 189 | } |
| 189 | 190 | ||
| 190 | void H264BitWriter::WriteScalingList(std::span<const u8> list, s32 start, s32 count) { | 191 | void H264BitWriter::WriteScalingList(std::span<const u8> list, s32 start, s32 count) { |
| 191 | std::vector<u8> scan(count); | 192 | static Common::ScratchBuffer<u8> scan{}; |
| 193 | scan.resize_destructive(count); | ||
| 192 | if (count == 16) { | 194 | if (count == 16) { |
| 193 | std::memcpy(scan.data(), zig_zag_scan.data(), scan.size()); | 195 | std::memcpy(scan.data(), zig_zag_scan.data(), scan.size()); |
| 194 | } else { | 196 | } else { |
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 2442c3c29..e61d9af80 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt | |||
| @@ -33,6 +33,7 @@ set(SHADER_FILES | |||
| 33 | opengl_fidelityfx_fsr.frag | 33 | opengl_fidelityfx_fsr.frag |
| 34 | opengl_fidelityfx_fsr_easu.frag | 34 | opengl_fidelityfx_fsr_easu.frag |
| 35 | opengl_fidelityfx_fsr_rcas.frag | 35 | opengl_fidelityfx_fsr_rcas.frag |
| 36 | opengl_lmem_warmup.comp | ||
| 36 | opengl_present.frag | 37 | opengl_present.frag |
| 37 | opengl_present.vert | 38 | opengl_present.vert |
| 38 | opengl_present_scaleforce.frag | 39 | opengl_present_scaleforce.frag |
diff --git a/src/video_core/host_shaders/opengl_lmem_warmup.comp b/src/video_core/host_shaders/opengl_lmem_warmup.comp new file mode 100644 index 000000000..518268477 --- /dev/null +++ b/src/video_core/host_shaders/opengl_lmem_warmup.comp | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | // This shader is a workaround for a quirk in NVIDIA OpenGL drivers | ||
| 5 | // Shaders using local memory see a great performance benefit if a shader that was dispatched | ||
| 6 | // before it had more local memory allocated. | ||
| 7 | // This shader allocates the maximum local memory allowed on NVIDIA drivers to ensure that | ||
| 8 | // subsequent shaders see the performance boost. | ||
| 9 | |||
| 10 | // NOTE: This shader does no actual meaningful work and returns immediately, | ||
| 11 | // it is simply a means to have the driver expect a shader using lots of local memory. | ||
| 12 | |||
| 13 | #version 450 | ||
| 14 | |||
| 15 | layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; | ||
| 16 | |||
| 17 | layout(location = 0) uniform uint uniform_data; | ||
| 18 | |||
| 19 | layout(binding = 0, rgba8) uniform writeonly restrict image2DArray dest_image; | ||
| 20 | |||
| 21 | #define MAX_LMEM_SIZE 4080 // Size chosen to avoid errors in Nvidia's GLSL compiler | ||
| 22 | #define NUM_LMEM_CONSTANTS 1 | ||
| 23 | #define ARRAY_SIZE MAX_LMEM_SIZE - NUM_LMEM_CONSTANTS | ||
| 24 | |||
| 25 | uint lmem_0[ARRAY_SIZE]; | ||
| 26 | const uvec4 constant_values[NUM_LMEM_CONSTANTS] = uvec4[](uvec4(0)); | ||
| 27 | |||
| 28 | void main() { | ||
| 29 | const uint global_id = gl_GlobalInvocationID.x; | ||
| 30 | if (global_id <= 128) { | ||
| 31 | // Since the shader is called with a dispatch of 1x1x1 | ||
| 32 | // This should always be the case, and this shader will not actually execute | ||
| 33 | return; | ||
| 34 | } | ||
| 35 | for (uint t = 0; t < uniform_data; t++) { | ||
| 36 | const uint offset = (t * uniform_data); | ||
| 37 | lmem_0[offset] = t; | ||
| 38 | } | ||
| 39 | const uint offset = (gl_GlobalInvocationID.y * uniform_data + gl_GlobalInvocationID.x); | ||
| 40 | const uint value = lmem_0[offset]; | ||
| 41 | const uint const_value = constant_values[offset / 4][offset % 4]; | ||
| 42 | const uvec4 color = uvec4(value + const_value); | ||
| 43 | |||
| 44 | // A "side-effect" is needed so the variables don't get optimized out, | ||
| 45 | // but this should never execute so there should be no clobbering of previously bound state. | ||
| 46 | imageStore(dest_image, ivec3(gl_GlobalInvocationID), color); | ||
| 47 | } | ||
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 7b2cde7a7..45141e488 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp | |||
| @@ -111,7 +111,7 @@ GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cp | |||
| 111 | [[maybe_unused]] const auto current_entry_type = GetEntry<false>(current_gpu_addr); | 111 | [[maybe_unused]] const auto current_entry_type = GetEntry<false>(current_gpu_addr); |
| 112 | SetEntry<false>(current_gpu_addr, entry_type); | 112 | SetEntry<false>(current_gpu_addr, entry_type); |
| 113 | if (current_entry_type != entry_type) { | 113 | if (current_entry_type != entry_type) { |
| 114 | rasterizer->ModifyGPUMemory(unique_identifier, gpu_addr, page_size); | 114 | rasterizer->ModifyGPUMemory(unique_identifier, current_gpu_addr, page_size); |
| 115 | } | 115 | } |
| 116 | if constexpr (entry_type == EntryType::Mapped) { | 116 | if constexpr (entry_type == EntryType::Mapped) { |
| 117 | const VAddr current_cpu_addr = cpu_addr + offset; | 117 | const VAddr current_cpu_addr = cpu_addr + offset; |
| @@ -134,7 +134,7 @@ GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr | |||
| 134 | [[maybe_unused]] const auto current_entry_type = GetEntry<true>(current_gpu_addr); | 134 | [[maybe_unused]] const auto current_entry_type = GetEntry<true>(current_gpu_addr); |
| 135 | SetEntry<true>(current_gpu_addr, entry_type); | 135 | SetEntry<true>(current_gpu_addr, entry_type); |
| 136 | if (current_entry_type != entry_type) { | 136 | if (current_entry_type != entry_type) { |
| 137 | rasterizer->ModifyGPUMemory(unique_identifier, gpu_addr, big_page_size); | 137 | rasterizer->ModifyGPUMemory(unique_identifier, current_gpu_addr, big_page_size); |
| 138 | } | 138 | } |
| 139 | if constexpr (entry_type == EntryType::Mapped) { | 139 | if constexpr (entry_type == EntryType::Mapped) { |
| 140 | const VAddr current_cpu_addr = cpu_addr + offset; | 140 | const VAddr current_cpu_addr = cpu_addr + offset; |
| @@ -587,7 +587,7 @@ void MemoryManager::InvalidateRegion(GPUVAddr gpu_addr, size_t size, | |||
| 587 | 587 | ||
| 588 | void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size, | 588 | void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size, |
| 589 | VideoCommon::CacheType which) { | 589 | VideoCommon::CacheType which) { |
| 590 | std::vector<u8> tmp_buffer(size); | 590 | tmp_buffer.resize_destructive(size); |
| 591 | ReadBlock(gpu_src_addr, tmp_buffer.data(), size, which); | 591 | ReadBlock(gpu_src_addr, tmp_buffer.data(), size, which); |
| 592 | 592 | ||
| 593 | // The output block must be flushed in case it has data modified from the GPU. | 593 | // The output block must be flushed in case it has data modified from the GPU. |
| @@ -670,9 +670,9 @@ bool MemoryManager::IsFullyMappedRange(GPUVAddr gpu_addr, std::size_t size) cons | |||
| 670 | return result; | 670 | return result; |
| 671 | } | 671 | } |
| 672 | 672 | ||
| 673 | std::vector<std::pair<GPUVAddr, std::size_t>> MemoryManager::GetSubmappedRange( | 673 | boost::container::small_vector<std::pair<GPUVAddr, std::size_t>, 32> |
| 674 | GPUVAddr gpu_addr, std::size_t size) const { | 674 | MemoryManager::GetSubmappedRange(GPUVAddr gpu_addr, std::size_t size) const { |
| 675 | std::vector<std::pair<GPUVAddr, std::size_t>> result{}; | 675 | boost::container::small_vector<std::pair<GPUVAddr, std::size_t>, 32> result{}; |
| 676 | GetSubmappedRangeImpl<true>(gpu_addr, size, result); | 676 | GetSubmappedRangeImpl<true>(gpu_addr, size, result); |
| 677 | return result; | 677 | return result; |
| 678 | } | 678 | } |
| @@ -680,8 +680,9 @@ std::vector<std::pair<GPUVAddr, std::size_t>> MemoryManager::GetSubmappedRange( | |||
| 680 | template <bool is_gpu_address> | 680 | template <bool is_gpu_address> |
| 681 | void MemoryManager::GetSubmappedRangeImpl( | 681 | void MemoryManager::GetSubmappedRangeImpl( |
| 682 | GPUVAddr gpu_addr, std::size_t size, | 682 | GPUVAddr gpu_addr, std::size_t size, |
| 683 | std::vector<std::pair<std::conditional_t<is_gpu_address, GPUVAddr, VAddr>, std::size_t>>& | 683 | boost::container::small_vector< |
| 684 | result) const { | 684 | std::pair<std::conditional_t<is_gpu_address, GPUVAddr, VAddr>, std::size_t>, 32>& result) |
| 685 | const { | ||
| 685 | std::optional<std::pair<std::conditional_t<is_gpu_address, GPUVAddr, VAddr>, std::size_t>> | 686 | std::optional<std::pair<std::conditional_t<is_gpu_address, GPUVAddr, VAddr>, std::size_t>> |
| 686 | last_segment{}; | 687 | last_segment{}; |
| 687 | std::optional<VAddr> old_page_addr{}; | 688 | std::optional<VAddr> old_page_addr{}; |
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index 794535122..4202c26ff 100644 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h | |||
| @@ -8,10 +8,12 @@ | |||
| 8 | #include <mutex> | 8 | #include <mutex> |
| 9 | #include <optional> | 9 | #include <optional> |
| 10 | #include <vector> | 10 | #include <vector> |
| 11 | #include <boost/container/small_vector.hpp> | ||
| 11 | 12 | ||
| 12 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 13 | #include "common/multi_level_page_table.h" | 14 | #include "common/multi_level_page_table.h" |
| 14 | #include "common/range_map.h" | 15 | #include "common/range_map.h" |
| 16 | #include "common/scratch_buffer.h" | ||
| 15 | #include "common/virtual_buffer.h" | 17 | #include "common/virtual_buffer.h" |
| 16 | #include "video_core/cache_types.h" | 18 | #include "video_core/cache_types.h" |
| 17 | #include "video_core/pte_kind.h" | 19 | #include "video_core/pte_kind.h" |
| @@ -107,8 +109,8 @@ public: | |||
| 107 | * if the region is continuous, a single pair will be returned. If it's unmapped, an empty | 109 | * if the region is continuous, a single pair will be returned. If it's unmapped, an empty |
| 108 | * vector will be returned; | 110 | * vector will be returned; |
| 109 | */ | 111 | */ |
| 110 | std::vector<std::pair<GPUVAddr, std::size_t>> GetSubmappedRange(GPUVAddr gpu_addr, | 112 | boost::container::small_vector<std::pair<GPUVAddr, std::size_t>, 32> GetSubmappedRange( |
| 111 | std::size_t size) const; | 113 | GPUVAddr gpu_addr, std::size_t size) const; |
| 112 | 114 | ||
| 113 | GPUVAddr Map(GPUVAddr gpu_addr, VAddr cpu_addr, std::size_t size, | 115 | GPUVAddr Map(GPUVAddr gpu_addr, VAddr cpu_addr, std::size_t size, |
| 114 | PTEKind kind = PTEKind::INVALID, bool is_big_pages = true); | 116 | PTEKind kind = PTEKind::INVALID, bool is_big_pages = true); |
| @@ -165,7 +167,8 @@ private: | |||
| 165 | template <bool is_gpu_address> | 167 | template <bool is_gpu_address> |
| 166 | void GetSubmappedRangeImpl( | 168 | void GetSubmappedRangeImpl( |
| 167 | GPUVAddr gpu_addr, std::size_t size, | 169 | GPUVAddr gpu_addr, std::size_t size, |
| 168 | std::vector<std::pair<std::conditional_t<is_gpu_address, GPUVAddr, VAddr>, std::size_t>>& | 170 | boost::container::small_vector< |
| 171 | std::pair<std::conditional_t<is_gpu_address, GPUVAddr, VAddr>, std::size_t>, 32>& | ||
| 169 | result) const; | 172 | result) const; |
| 170 | 173 | ||
| 171 | Core::System& system; | 174 | Core::System& system; |
| @@ -215,8 +218,8 @@ private: | |||
| 215 | Common::VirtualBuffer<u32> big_page_table_cpu; | 218 | Common::VirtualBuffer<u32> big_page_table_cpu; |
| 216 | 219 | ||
| 217 | std::vector<u64> big_page_continuous; | 220 | std::vector<u64> big_page_continuous; |
| 218 | std::vector<std::pair<VAddr, std::size_t>> page_stash{}; | 221 | boost::container::small_vector<std::pair<VAddr, std::size_t>, 32> page_stash{}; |
| 219 | std::vector<std::pair<VAddr, std::size_t>> page_stash2{}; | 222 | boost::container::small_vector<std::pair<VAddr, std::size_t>, 32> page_stash2{}; |
| 220 | 223 | ||
| 221 | mutable std::mutex guard; | 224 | mutable std::mutex guard; |
| 222 | 225 | ||
| @@ -226,6 +229,8 @@ private: | |||
| 226 | std::unique_ptr<VideoCommon::InvalidationAccumulator> accumulator; | 229 | std::unique_ptr<VideoCommon::InvalidationAccumulator> accumulator; |
| 227 | 230 | ||
| 228 | static std::atomic<size_t> unique_identifier_generator; | 231 | static std::atomic<size_t> unique_identifier_generator; |
| 232 | |||
| 233 | Common::ScratchBuffer<u8> tmp_buffer; | ||
| 229 | }; | 234 | }; |
| 230 | 235 | ||
| 231 | } // namespace Tegra | 236 | } // namespace Tegra |
diff --git a/src/video_core/renderer_opengl/gl_compute_pipeline.cpp b/src/video_core/renderer_opengl/gl_compute_pipeline.cpp index 3151c0db8..f9ca55c36 100644 --- a/src/video_core/renderer_opengl/gl_compute_pipeline.cpp +++ b/src/video_core/renderer_opengl/gl_compute_pipeline.cpp | |||
| @@ -63,6 +63,7 @@ ComputePipeline::ComputePipeline(const Device& device, TextureCache& texture_cac | |||
| 63 | writes_global_memory = !use_storage_buffers && | 63 | writes_global_memory = !use_storage_buffers && |
| 64 | std::ranges::any_of(info.storage_buffers_descriptors, | 64 | std::ranges::any_of(info.storage_buffers_descriptors, |
| 65 | [](const auto& desc) { return desc.is_written; }); | 65 | [](const auto& desc) { return desc.is_written; }); |
| 66 | uses_local_memory = info.uses_local_memory; | ||
| 66 | if (force_context_flush) { | 67 | if (force_context_flush) { |
| 67 | std::scoped_lock lock{built_mutex}; | 68 | std::scoped_lock lock{built_mutex}; |
| 68 | built_fence.Create(); | 69 | built_fence.Create(); |
diff --git a/src/video_core/renderer_opengl/gl_compute_pipeline.h b/src/video_core/renderer_opengl/gl_compute_pipeline.h index 9bcc72b59..c26b4fa5e 100644 --- a/src/video_core/renderer_opengl/gl_compute_pipeline.h +++ b/src/video_core/renderer_opengl/gl_compute_pipeline.h | |||
| @@ -59,6 +59,10 @@ public: | |||
| 59 | return writes_global_memory; | 59 | return writes_global_memory; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | [[nodiscard]] bool UsesLocalMemory() const noexcept { | ||
| 63 | return uses_local_memory; | ||
| 64 | } | ||
| 65 | |||
| 62 | void SetEngine(Tegra::Engines::KeplerCompute* kepler_compute_, | 66 | void SetEngine(Tegra::Engines::KeplerCompute* kepler_compute_, |
| 63 | Tegra::MemoryManager* gpu_memory_) { | 67 | Tegra::MemoryManager* gpu_memory_) { |
| 64 | kepler_compute = kepler_compute_; | 68 | kepler_compute = kepler_compute_; |
| @@ -84,6 +88,7 @@ private: | |||
| 84 | 88 | ||
| 85 | bool use_storage_buffers{}; | 89 | bool use_storage_buffers{}; |
| 86 | bool writes_global_memory{}; | 90 | bool writes_global_memory{}; |
| 91 | bool uses_local_memory{}; | ||
| 87 | 92 | ||
| 88 | std::mutex built_mutex; | 93 | std::mutex built_mutex; |
| 89 | std::condition_variable built_condvar; | 94 | std::condition_variable built_condvar; |
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index 03d234f2f..33e63c17d 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp | |||
| @@ -194,6 +194,7 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) { | |||
| 194 | has_bool_ref_bug = true; | 194 | has_bool_ref_bug = true; |
| 195 | } | 195 | } |
| 196 | } | 196 | } |
| 197 | has_lmem_perf_bug = is_nvidia; | ||
| 197 | 198 | ||
| 198 | strict_context_required = emu_window.StrictContextRequired(); | 199 | strict_context_required = emu_window.StrictContextRequired(); |
| 199 | // Blocks AMD and Intel OpenGL drivers on Windows from using asynchronous shader compilation. | 200 | // Blocks AMD and Intel OpenGL drivers on Windows from using asynchronous shader compilation. |
diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index ad27264e5..a5a6bbbba 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h | |||
| @@ -192,6 +192,10 @@ public: | |||
| 192 | return supports_conditional_barriers; | 192 | return supports_conditional_barriers; |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | bool HasLmemPerfBug() const { | ||
| 196 | return has_lmem_perf_bug; | ||
| 197 | } | ||
| 198 | |||
| 195 | private: | 199 | private: |
| 196 | static bool TestVariableAoffi(); | 200 | static bool TestVariableAoffi(); |
| 197 | static bool TestPreciseBug(); | 201 | static bool TestPreciseBug(); |
| @@ -238,6 +242,7 @@ private: | |||
| 238 | bool can_report_memory{}; | 242 | bool can_report_memory{}; |
| 239 | bool strict_context_required{}; | 243 | bool strict_context_required{}; |
| 240 | bool supports_conditional_barriers{}; | 244 | bool supports_conditional_barriers{}; |
| 245 | bool has_lmem_perf_bug{}; | ||
| 241 | 246 | ||
| 242 | std::string vendor_name; | 247 | std::string vendor_name; |
| 243 | }; | 248 | }; |
diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp index c58f760b8..23a48c6fe 100644 --- a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp +++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp | |||
| @@ -215,6 +215,7 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c | |||
| 215 | 215 | ||
| 216 | writes_global_memory |= std::ranges::any_of( | 216 | writes_global_memory |= std::ranges::any_of( |
| 217 | info.storage_buffers_descriptors, [](const auto& desc) { return desc.is_written; }); | 217 | info.storage_buffers_descriptors, [](const auto& desc) { return desc.is_written; }); |
| 218 | uses_local_memory |= info.uses_local_memory; | ||
| 218 | } | 219 | } |
| 219 | ASSERT(num_textures <= MAX_TEXTURES); | 220 | ASSERT(num_textures <= MAX_TEXTURES); |
| 220 | ASSERT(num_images <= MAX_IMAGES); | 221 | ASSERT(num_images <= MAX_IMAGES); |
diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.h b/src/video_core/renderer_opengl/gl_graphics_pipeline.h index 7bab3be0a..7b3d7eae8 100644 --- a/src/video_core/renderer_opengl/gl_graphics_pipeline.h +++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.h | |||
| @@ -98,6 +98,10 @@ public: | |||
| 98 | return writes_global_memory; | 98 | return writes_global_memory; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | [[nodiscard]] bool UsesLocalMemory() const noexcept { | ||
| 102 | return uses_local_memory; | ||
| 103 | } | ||
| 104 | |||
| 101 | [[nodiscard]] bool IsBuilt() noexcept; | 105 | [[nodiscard]] bool IsBuilt() noexcept; |
| 102 | 106 | ||
| 103 | template <typename Spec> | 107 | template <typename Spec> |
| @@ -146,6 +150,7 @@ private: | |||
| 146 | 150 | ||
| 147 | bool use_storage_buffers{}; | 151 | bool use_storage_buffers{}; |
| 148 | bool writes_global_memory{}; | 152 | bool writes_global_memory{}; |
| 153 | bool uses_local_memory{}; | ||
| 149 | 154 | ||
| 150 | static constexpr std::size_t XFB_ENTRY_STRIDE = 3; | 155 | static constexpr std::size_t XFB_ENTRY_STRIDE = 3; |
| 151 | GLsizei num_xfb_attribs{}; | 156 | GLsizei num_xfb_attribs{}; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index fc711c44a..edf527f2d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -222,6 +222,9 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) { | |||
| 222 | gpu.TickWork(); | 222 | gpu.TickWork(); |
| 223 | 223 | ||
| 224 | std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; | 224 | std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; |
| 225 | if (pipeline->UsesLocalMemory()) { | ||
| 226 | program_manager.LocalMemoryWarmup(); | ||
| 227 | } | ||
| 225 | pipeline->SetEngine(maxwell3d, gpu_memory); | 228 | pipeline->SetEngine(maxwell3d, gpu_memory); |
| 226 | pipeline->Configure(is_indexed); | 229 | pipeline->Configure(is_indexed); |
| 227 | 230 | ||
| @@ -371,6 +374,9 @@ void RasterizerOpenGL::DispatchCompute() { | |||
| 371 | if (!pipeline) { | 374 | if (!pipeline) { |
| 372 | return; | 375 | return; |
| 373 | } | 376 | } |
| 377 | if (pipeline->UsesLocalMemory()) { | ||
| 378 | program_manager.LocalMemoryWarmup(); | ||
| 379 | } | ||
| 374 | pipeline->SetEngine(kepler_compute, gpu_memory); | 380 | pipeline->SetEngine(kepler_compute, gpu_memory); |
| 375 | pipeline->Configure(); | 381 | pipeline->Configure(); |
| 376 | const auto& qmd{kepler_compute->launch_description}; | 382 | const auto& qmd{kepler_compute->launch_description}; |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 3f077311e..0329ed820 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -85,7 +85,9 @@ Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key, | |||
| 85 | case Shader::Stage::VertexB: | 85 | case Shader::Stage::VertexB: |
| 86 | case Shader::Stage::Geometry: | 86 | case Shader::Stage::Geometry: |
| 87 | if (!use_assembly_shaders && key.xfb_enabled != 0) { | 87 | if (!use_assembly_shaders && key.xfb_enabled != 0) { |
| 88 | info.xfb_varyings = VideoCommon::MakeTransformFeedbackVaryings(key.xfb_state); | 88 | auto [varyings, count] = VideoCommon::MakeTransformFeedbackVaryings(key.xfb_state); |
| 89 | info.xfb_varyings = varyings; | ||
| 90 | info.xfb_count = count; | ||
| 89 | } | 91 | } |
| 90 | break; | 92 | break; |
| 91 | case Shader::Stage::TessellationEval: | 93 | case Shader::Stage::TessellationEval: |
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index 98841ae65..03d4b9d06 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp | |||
| @@ -3,7 +3,9 @@ | |||
| 3 | 3 | ||
| 4 | #include <glad/glad.h> | 4 | #include <glad/glad.h> |
| 5 | 5 | ||
| 6 | #include "video_core/host_shaders/opengl_lmem_warmup_comp.h" | ||
| 6 | #include "video_core/renderer_opengl/gl_shader_manager.h" | 7 | #include "video_core/renderer_opengl/gl_shader_manager.h" |
| 8 | #include "video_core/renderer_opengl/gl_shader_util.h" | ||
| 7 | 9 | ||
| 8 | namespace OpenGL { | 10 | namespace OpenGL { |
| 9 | 11 | ||
| @@ -17,6 +19,10 @@ ProgramManager::ProgramManager(const Device& device) { | |||
| 17 | if (device.UseAssemblyShaders()) { | 19 | if (device.UseAssemblyShaders()) { |
| 18 | glEnable(GL_COMPUTE_PROGRAM_NV); | 20 | glEnable(GL_COMPUTE_PROGRAM_NV); |
| 19 | } | 21 | } |
| 22 | if (device.HasLmemPerfBug()) { | ||
| 23 | lmem_warmup_program = | ||
| 24 | CreateProgram(HostShaders::OPENGL_LMEM_WARMUP_COMP, GL_COMPUTE_SHADER); | ||
| 25 | } | ||
| 20 | } | 26 | } |
| 21 | 27 | ||
| 22 | void ProgramManager::BindComputeProgram(GLuint program) { | 28 | void ProgramManager::BindComputeProgram(GLuint program) { |
| @@ -98,6 +104,13 @@ void ProgramManager::BindAssemblyPrograms(std::span<const OGLAssemblyProgram, NU | |||
| 98 | 104 | ||
| 99 | void ProgramManager::RestoreGuestCompute() {} | 105 | void ProgramManager::RestoreGuestCompute() {} |
| 100 | 106 | ||
| 107 | void ProgramManager::LocalMemoryWarmup() { | ||
| 108 | if (lmem_warmup_program.handle != 0) { | ||
| 109 | BindComputeProgram(lmem_warmup_program.handle); | ||
| 110 | glDispatchCompute(1, 1, 1); | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 101 | void ProgramManager::BindPipeline() { | 114 | void ProgramManager::BindPipeline() { |
| 102 | if (!is_pipeline_bound) { | 115 | if (!is_pipeline_bound) { |
| 103 | is_pipeline_bound = true; | 116 | is_pipeline_bound = true; |
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index 07ffab77f..852d8c88e 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h | |||
| @@ -30,6 +30,8 @@ public: | |||
| 30 | 30 | ||
| 31 | void RestoreGuestCompute(); | 31 | void RestoreGuestCompute(); |
| 32 | 32 | ||
| 33 | void LocalMemoryWarmup(); | ||
| 34 | |||
| 33 | private: | 35 | private: |
| 34 | void BindPipeline(); | 36 | void BindPipeline(); |
| 35 | 37 | ||
| @@ -44,6 +46,7 @@ private: | |||
| 44 | u32 current_stage_mask = 0; | 46 | u32 current_stage_mask = 0; |
| 45 | std::array<GLuint, NUM_STAGES> current_programs{}; | 47 | std::array<GLuint, NUM_STAGES> current_programs{}; |
| 46 | GLuint current_assembly_compute_program = 0; | 48 | GLuint current_assembly_compute_program = 0; |
| 49 | OGLProgram lmem_warmup_program; | ||
| 47 | }; | 50 | }; |
| 48 | 51 | ||
| 49 | } // namespace OpenGL | 52 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index cf2964a3f..28d4b15a0 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp | |||
| @@ -495,6 +495,9 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer, | |||
| 495 | const Region2D& dst_region, const Region2D& src_region, | 495 | const Region2D& dst_region, const Region2D& src_region, |
| 496 | Tegra::Engines::Fermi2D::Filter filter, | 496 | Tegra::Engines::Fermi2D::Filter filter, |
| 497 | Tegra::Engines::Fermi2D::Operation operation) { | 497 | Tegra::Engines::Fermi2D::Operation operation) { |
| 498 | if (!device.IsExtShaderStencilExportSupported()) { | ||
| 499 | return; | ||
| 500 | } | ||
| 498 | ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point); | 501 | ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point); |
| 499 | ASSERT(operation == Tegra::Engines::Fermi2D::Operation::SrcCopy); | 502 | ASSERT(operation == Tegra::Engines::Fermi2D::Operation::SrcCopy); |
| 500 | const BlitImagePipelineKey key{ | 503 | const BlitImagePipelineKey key{ |
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index 9a0b10568..a8540339d 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp | |||
| @@ -259,6 +259,26 @@ FormatInfo SurfaceFormat(const Device& device, FormatType format_type, bool with | |||
| 259 | break; | 259 | break; |
| 260 | } | 260 | } |
| 261 | } | 261 | } |
| 262 | // Transcode on hardware that doesn't support BCn natively | ||
| 263 | if (!device.IsOptimalBcnSupported() && VideoCore::Surface::IsPixelFormatBCn(pixel_format)) { | ||
| 264 | const bool is_srgb = with_srgb && VideoCore::Surface::IsPixelFormatSRGB(pixel_format); | ||
| 265 | if (pixel_format == PixelFormat::BC4_SNORM) { | ||
| 266 | tuple.format = VK_FORMAT_R8_SNORM; | ||
| 267 | } else if (pixel_format == PixelFormat::BC4_UNORM) { | ||
| 268 | tuple.format = VK_FORMAT_R8_UNORM; | ||
| 269 | } else if (pixel_format == PixelFormat::BC5_SNORM) { | ||
| 270 | tuple.format = VK_FORMAT_R8G8_SNORM; | ||
| 271 | } else if (pixel_format == PixelFormat::BC5_UNORM) { | ||
| 272 | tuple.format = VK_FORMAT_R8G8_UNORM; | ||
| 273 | } else if (pixel_format == PixelFormat::BC6H_SFLOAT || | ||
| 274 | pixel_format == PixelFormat::BC6H_UFLOAT) { | ||
| 275 | tuple.format = VK_FORMAT_R16G16B16A16_SFLOAT; | ||
| 276 | } else if (is_srgb) { | ||
| 277 | tuple.format = VK_FORMAT_A8B8G8R8_SRGB_PACK32; | ||
| 278 | } else { | ||
| 279 | tuple.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32; | ||
| 280 | } | ||
| 281 | } | ||
| 262 | const bool attachable = (tuple.usage & Attachable) != 0; | 282 | const bool attachable = (tuple.usage & Attachable) != 0; |
| 263 | const bool storage = (tuple.usage & Storage) != 0; | 283 | const bool storage = (tuple.usage & Storage) != 0; |
| 264 | 284 | ||
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 77128c6e2..454bb66a4 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <fmt/format.h> | 12 | #include <fmt/format.h> |
| 13 | 13 | ||
| 14 | #include "common/logging/log.h" | 14 | #include "common/logging/log.h" |
| 15 | #include "common/polyfill_ranges.h" | ||
| 15 | #include "common/scope_exit.h" | 16 | #include "common/scope_exit.h" |
| 16 | #include "common/settings.h" | 17 | #include "common/settings.h" |
| 17 | #include "common/telemetry.h" | 18 | #include "common/telemetry.h" |
| @@ -65,6 +66,21 @@ std::string BuildCommaSeparatedExtensions( | |||
| 65 | return fmt::format("{}", fmt::join(available_extensions, ",")); | 66 | return fmt::format("{}", fmt::join(available_extensions, ",")); |
| 66 | } | 67 | } |
| 67 | 68 | ||
| 69 | DebugCallback MakeDebugCallback(const vk::Instance& instance, const vk::InstanceDispatch& dld) { | ||
| 70 | if (!Settings::values.renderer_debug) { | ||
| 71 | return DebugCallback{}; | ||
| 72 | } | ||
| 73 | const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld); | ||
| 74 | const auto it = std::ranges::find_if(*properties, [](const auto& prop) { | ||
| 75 | return std::strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, prop.extensionName) == 0; | ||
| 76 | }); | ||
| 77 | if (it != properties->end()) { | ||
| 78 | return CreateDebugUtilsCallback(instance); | ||
| 79 | } else { | ||
| 80 | return CreateDebugReportCallback(instance); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 68 | } // Anonymous namespace | 84 | } // Anonymous namespace |
| 69 | 85 | ||
| 70 | Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld, | 86 | Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld, |
| @@ -87,10 +103,10 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, | |||
| 87 | cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary(context.get())), | 103 | cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary(context.get())), |
| 88 | instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, | 104 | instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, |
| 89 | Settings::values.renderer_debug.GetValue())), | 105 | Settings::values.renderer_debug.GetValue())), |
| 90 | debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), | 106 | debug_callback(MakeDebugCallback(instance, dld)), |
| 91 | surface(CreateSurface(instance, render_window.GetWindowInfo())), | 107 | surface(CreateSurface(instance, render_window.GetWindowInfo())), |
| 92 | device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false), | 108 | device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(), |
| 93 | state_tracker(), scheduler(device, state_tracker), | 109 | scheduler(device, state_tracker), |
| 94 | swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, | 110 | swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, |
| 95 | render_window.GetFramebufferLayout().height, false), | 111 | render_window.GetFramebufferLayout().height, false), |
| 96 | present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, | 112 | present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, |
| @@ -173,7 +189,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||
| 173 | return; | 189 | return; |
| 174 | } | 190 | } |
| 175 | const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; | 191 | const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; |
| 176 | vk::Image staging_image = device.GetLogical().CreateImage(VkImageCreateInfo{ | 192 | vk::Image staging_image = memory_allocator.CreateImage(VkImageCreateInfo{ |
| 177 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 193 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| 178 | .pNext = nullptr, | 194 | .pNext = nullptr, |
| 179 | .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, | 195 | .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, |
| @@ -196,7 +212,6 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||
| 196 | .pQueueFamilyIndices = nullptr, | 212 | .pQueueFamilyIndices = nullptr, |
| 197 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 213 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
| 198 | }); | 214 | }); |
| 199 | const auto image_commit = memory_allocator.Commit(staging_image, MemoryUsage::DeviceLocal); | ||
| 200 | 215 | ||
| 201 | const vk::ImageView dst_view = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | 216 | const vk::ImageView dst_view = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ |
| 202 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 217 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| @@ -234,8 +249,8 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||
| 234 | .queueFamilyIndexCount = 0, | 249 | .queueFamilyIndexCount = 0, |
| 235 | .pQueueFamilyIndices = nullptr, | 250 | .pQueueFamilyIndices = nullptr, |
| 236 | }; | 251 | }; |
| 237 | const vk::Buffer dst_buffer = device.GetLogical().CreateBuffer(dst_buffer_info); | 252 | const vk::Buffer dst_buffer = |
| 238 | MemoryCommit dst_buffer_memory = memory_allocator.Commit(dst_buffer, MemoryUsage::Download); | 253 | memory_allocator.CreateBuffer(dst_buffer_info, MemoryUsage::Download); |
| 239 | 254 | ||
| 240 | scheduler.RequestOutsideRenderPassOperationContext(); | 255 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 241 | scheduler.Record([&](vk::CommandBuffer cmdbuf) { | 256 | scheduler.Record([&](vk::CommandBuffer cmdbuf) { |
| @@ -309,8 +324,9 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||
| 309 | scheduler.Finish(); | 324 | scheduler.Finish(); |
| 310 | 325 | ||
| 311 | // Copy backing image data to the QImage screenshot buffer | 326 | // Copy backing image data to the QImage screenshot buffer |
| 312 | const auto dst_memory_map = dst_buffer_memory.Map(); | 327 | dst_buffer.Invalidate(); |
| 313 | std::memcpy(renderer_settings.screenshot_bits, dst_memory_map.data(), dst_memory_map.size()); | 328 | std::memcpy(renderer_settings.screenshot_bits, dst_buffer.Mapped().data(), |
| 329 | dst_buffer.Mapped().size()); | ||
| 314 | renderer_settings.screenshot_complete_callback(false); | 330 | renderer_settings.screenshot_complete_callback(false); |
| 315 | renderer_settings.screenshot_requested = false; | 331 | renderer_settings.screenshot_requested = false; |
| 316 | } | 332 | } |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index b2e8cbd1b..ca22c0baa 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include <string> | 7 | #include <string> |
| 8 | #include <variant> | ||
| 8 | 9 | ||
| 9 | #include "common/dynamic_library.h" | 10 | #include "common/dynamic_library.h" |
| 10 | #include "video_core/renderer_base.h" | 11 | #include "video_core/renderer_base.h" |
| @@ -33,6 +34,8 @@ class GPU; | |||
| 33 | 34 | ||
| 34 | namespace Vulkan { | 35 | namespace Vulkan { |
| 35 | 36 | ||
| 37 | using DebugCallback = std::variant<vk::DebugUtilsMessenger, vk::DebugReportCallback>; | ||
| 38 | |||
| 36 | Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld, | 39 | Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld, |
| 37 | VkSurfaceKHR surface); | 40 | VkSurfaceKHR surface); |
| 38 | 41 | ||
| @@ -71,7 +74,7 @@ private: | |||
| 71 | vk::InstanceDispatch dld; | 74 | vk::InstanceDispatch dld; |
| 72 | 75 | ||
| 73 | vk::Instance instance; | 76 | vk::Instance instance; |
| 74 | vk::DebugUtilsMessenger debug_callback; | 77 | DebugCallback debug_callback; |
| 75 | vk::SurfaceKHR surface; | 78 | vk::SurfaceKHR surface; |
| 76 | 79 | ||
| 77 | ScreenInfo screen_info; | 80 | ScreenInfo screen_info; |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index acb143fc7..ad3b29f0e 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp | |||
| @@ -162,7 +162,7 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | |||
| 162 | SetUniformData(data, layout); | 162 | SetUniformData(data, layout); |
| 163 | SetVertexData(data, framebuffer, layout); | 163 | SetVertexData(data, framebuffer, layout); |
| 164 | 164 | ||
| 165 | const std::span<u8> mapped_span = buffer_commit.Map(); | 165 | const std::span<u8> mapped_span = buffer.Mapped(); |
| 166 | std::memcpy(mapped_span.data(), &data, sizeof(data)); | 166 | std::memcpy(mapped_span.data(), &data, sizeof(data)); |
| 167 | 167 | ||
| 168 | if (!use_accelerated) { | 168 | if (!use_accelerated) { |
| @@ -1071,14 +1071,9 @@ void BlitScreen::ReleaseRawImages() { | |||
| 1071 | scheduler.Wait(tick); | 1071 | scheduler.Wait(tick); |
| 1072 | } | 1072 | } |
| 1073 | raw_images.clear(); | 1073 | raw_images.clear(); |
| 1074 | raw_buffer_commits.clear(); | ||
| 1075 | |||
| 1076 | aa_image_view.reset(); | 1074 | aa_image_view.reset(); |
| 1077 | aa_image.reset(); | 1075 | aa_image.reset(); |
| 1078 | aa_commit = MemoryCommit{}; | ||
| 1079 | |||
| 1080 | buffer.reset(); | 1076 | buffer.reset(); |
| 1081 | buffer_commit = MemoryCommit{}; | ||
| 1082 | } | 1077 | } |
| 1083 | 1078 | ||
| 1084 | void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { | 1079 | void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { |
| @@ -1094,20 +1089,18 @@ void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer | |||
| 1094 | .pQueueFamilyIndices = nullptr, | 1089 | .pQueueFamilyIndices = nullptr, |
| 1095 | }; | 1090 | }; |
| 1096 | 1091 | ||
| 1097 | buffer = device.GetLogical().CreateBuffer(ci); | 1092 | buffer = memory_allocator.CreateBuffer(ci, MemoryUsage::Upload); |
| 1098 | buffer_commit = memory_allocator.Commit(buffer, MemoryUsage::Upload); | ||
| 1099 | } | 1093 | } |
| 1100 | 1094 | ||
| 1101 | void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | 1095 | void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { |
| 1102 | raw_images.resize(image_count); | 1096 | raw_images.resize(image_count); |
| 1103 | raw_image_views.resize(image_count); | 1097 | raw_image_views.resize(image_count); |
| 1104 | raw_buffer_commits.resize(image_count); | ||
| 1105 | 1098 | ||
| 1106 | const auto create_image = [&](bool used_on_framebuffer = false, u32 up_scale = 1, | 1099 | const auto create_image = [&](bool used_on_framebuffer = false, u32 up_scale = 1, |
| 1107 | u32 down_shift = 0) { | 1100 | u32 down_shift = 0) { |
| 1108 | u32 extra_usages = used_on_framebuffer ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | 1101 | u32 extra_usages = used_on_framebuffer ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
| 1109 | : VK_IMAGE_USAGE_TRANSFER_DST_BIT; | 1102 | : VK_IMAGE_USAGE_TRANSFER_DST_BIT; |
| 1110 | return device.GetLogical().CreateImage(VkImageCreateInfo{ | 1103 | return memory_allocator.CreateImage(VkImageCreateInfo{ |
| 1111 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 1104 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| 1112 | .pNext = nullptr, | 1105 | .pNext = nullptr, |
| 1113 | .flags = 0, | 1106 | .flags = 0, |
| @@ -1130,9 +1123,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | |||
| 1130 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 1123 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
| 1131 | }); | 1124 | }); |
| 1132 | }; | 1125 | }; |
| 1133 | const auto create_commit = [&](vk::Image& image) { | ||
| 1134 | return memory_allocator.Commit(image, MemoryUsage::DeviceLocal); | ||
| 1135 | }; | ||
| 1136 | const auto create_image_view = [&](vk::Image& image, bool used_on_framebuffer = false) { | 1126 | const auto create_image_view = [&](vk::Image& image, bool used_on_framebuffer = false) { |
| 1137 | return device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | 1127 | return device.GetLogical().CreateImageView(VkImageViewCreateInfo{ |
| 1138 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 1128 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| @@ -1161,7 +1151,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | |||
| 1161 | 1151 | ||
| 1162 | for (size_t i = 0; i < image_count; ++i) { | 1152 | for (size_t i = 0; i < image_count; ++i) { |
| 1163 | raw_images[i] = create_image(); | 1153 | raw_images[i] = create_image(); |
| 1164 | raw_buffer_commits[i] = create_commit(raw_images[i]); | ||
| 1165 | raw_image_views[i] = create_image_view(raw_images[i]); | 1154 | raw_image_views[i] = create_image_view(raw_images[i]); |
| 1166 | } | 1155 | } |
| 1167 | 1156 | ||
| @@ -1169,7 +1158,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | |||
| 1169 | const u32 up_scale = Settings::values.resolution_info.up_scale; | 1158 | const u32 up_scale = Settings::values.resolution_info.up_scale; |
| 1170 | const u32 down_shift = Settings::values.resolution_info.down_shift; | 1159 | const u32 down_shift = Settings::values.resolution_info.down_shift; |
| 1171 | aa_image = create_image(true, up_scale, down_shift); | 1160 | aa_image = create_image(true, up_scale, down_shift); |
| 1172 | aa_commit = create_commit(aa_image); | ||
| 1173 | aa_image_view = create_image_view(aa_image, true); | 1161 | aa_image_view = create_image_view(aa_image, true); |
| 1174 | VkExtent2D size{ | 1162 | VkExtent2D size{ |
| 1175 | .width = (up_scale * framebuffer.width) >> down_shift, | 1163 | .width = (up_scale * framebuffer.width) >> down_shift, |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 68ec20253..8365b5668 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h | |||
| @@ -142,13 +142,11 @@ private: | |||
| 142 | vk::Sampler sampler; | 142 | vk::Sampler sampler; |
| 143 | 143 | ||
| 144 | vk::Buffer buffer; | 144 | vk::Buffer buffer; |
| 145 | MemoryCommit buffer_commit; | ||
| 146 | 145 | ||
| 147 | std::vector<u64> resource_ticks; | 146 | std::vector<u64> resource_ticks; |
| 148 | 147 | ||
| 149 | std::vector<vk::Image> raw_images; | 148 | std::vector<vk::Image> raw_images; |
| 150 | std::vector<vk::ImageView> raw_image_views; | 149 | std::vector<vk::ImageView> raw_image_views; |
| 151 | std::vector<MemoryCommit> raw_buffer_commits; | ||
| 152 | 150 | ||
| 153 | vk::DescriptorPool aa_descriptor_pool; | 151 | vk::DescriptorPool aa_descriptor_pool; |
| 154 | vk::DescriptorSetLayout aa_descriptor_set_layout; | 152 | vk::DescriptorSetLayout aa_descriptor_set_layout; |
| @@ -159,7 +157,6 @@ private: | |||
| 159 | vk::DescriptorSets aa_descriptor_sets; | 157 | vk::DescriptorSets aa_descriptor_sets; |
| 160 | vk::Image aa_image; | 158 | vk::Image aa_image; |
| 161 | vk::ImageView aa_image_view; | 159 | vk::ImageView aa_image_view; |
| 162 | MemoryCommit aa_commit; | ||
| 163 | 160 | ||
| 164 | u32 raw_width = 0; | 161 | u32 raw_width = 0; |
| 165 | u32 raw_height = 0; | 162 | u32 raw_height = 0; |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index e30fcb1ed..b72f95235 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp | |||
| @@ -50,7 +50,7 @@ size_t BytesPerIndex(VkIndexType index_type) { | |||
| 50 | } | 50 | } |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | vk::Buffer CreateBuffer(const Device& device, u64 size) { | 53 | vk::Buffer CreateBuffer(const Device& device, const MemoryAllocator& memory_allocator, u64 size) { |
| 54 | VkBufferUsageFlags flags = | 54 | VkBufferUsageFlags flags = |
| 55 | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | | 55 | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | |
| 56 | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | | 56 | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | |
| @@ -60,7 +60,7 @@ vk::Buffer CreateBuffer(const Device& device, u64 size) { | |||
| 60 | if (device.IsExtTransformFeedbackSupported()) { | 60 | if (device.IsExtTransformFeedbackSupported()) { |
| 61 | flags |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; | 61 | flags |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; |
| 62 | } | 62 | } |
| 63 | return device.GetLogical().CreateBuffer({ | 63 | const VkBufferCreateInfo buffer_ci = { |
| 64 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 64 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 65 | .pNext = nullptr, | 65 | .pNext = nullptr, |
| 66 | .flags = 0, | 66 | .flags = 0, |
| @@ -69,7 +69,8 @@ vk::Buffer CreateBuffer(const Device& device, u64 size) { | |||
| 69 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 69 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 70 | .queueFamilyIndexCount = 0, | 70 | .queueFamilyIndexCount = 0, |
| 71 | .pQueueFamilyIndices = nullptr, | 71 | .pQueueFamilyIndices = nullptr, |
| 72 | }); | 72 | }; |
| 73 | return memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal); | ||
| 73 | } | 74 | } |
| 74 | } // Anonymous namespace | 75 | } // Anonymous namespace |
| 75 | 76 | ||
| @@ -79,8 +80,8 @@ Buffer::Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams null_params) | |||
| 79 | Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_, | 80 | Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_, |
| 80 | VAddr cpu_addr_, u64 size_bytes_) | 81 | VAddr cpu_addr_, u64 size_bytes_) |
| 81 | : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(rasterizer_, cpu_addr_, size_bytes_), | 82 | : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(rasterizer_, cpu_addr_, size_bytes_), |
| 82 | device{&runtime.device}, buffer{CreateBuffer(*device, SizeBytes())}, | 83 | device{&runtime.device}, buffer{ |
| 83 | commit{runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal)} { | 84 | CreateBuffer(*device, runtime.memory_allocator, SizeBytes())} { |
| 84 | if (runtime.device.HasDebuggingToolAttached()) { | 85 | if (runtime.device.HasDebuggingToolAttached()) { |
| 85 | buffer.SetObjectNameEXT(fmt::format("Buffer 0x{:x}", CpuAddr()).c_str()); | 86 | buffer.SetObjectNameEXT(fmt::format("Buffer 0x{:x}", CpuAddr()).c_str()); |
| 86 | } | 87 | } |
| @@ -138,7 +139,7 @@ public: | |||
| 138 | const u32 num_first_offset_copies = 4; | 139 | const u32 num_first_offset_copies = 4; |
| 139 | const size_t bytes_per_index = BytesPerIndex(index_type); | 140 | const size_t bytes_per_index = BytesPerIndex(index_type); |
| 140 | const size_t size_bytes = num_triangle_indices * bytes_per_index * num_first_offset_copies; | 141 | const size_t size_bytes = num_triangle_indices * bytes_per_index * num_first_offset_copies; |
| 141 | buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{ | 142 | const VkBufferCreateInfo buffer_ci = { |
| 142 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 143 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 143 | .pNext = nullptr, | 144 | .pNext = nullptr, |
| 144 | .flags = 0, | 145 | .flags = 0, |
| @@ -147,14 +148,21 @@ public: | |||
| 147 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 148 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 148 | .queueFamilyIndexCount = 0, | 149 | .queueFamilyIndexCount = 0, |
| 149 | .pQueueFamilyIndices = nullptr, | 150 | .pQueueFamilyIndices = nullptr, |
| 150 | }); | 151 | }; |
| 152 | buffer = memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal); | ||
| 151 | if (device.HasDebuggingToolAttached()) { | 153 | if (device.HasDebuggingToolAttached()) { |
| 152 | buffer.SetObjectNameEXT("Quad LUT"); | 154 | buffer.SetObjectNameEXT("Quad LUT"); |
| 153 | } | 155 | } |
| 154 | memory_commit = memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal); | ||
| 155 | 156 | ||
| 156 | const StagingBufferRef staging = staging_pool.Request(size_bytes, MemoryUsage::Upload); | 157 | const bool host_visible = buffer.IsHostVisible(); |
| 157 | u8* staging_data = staging.mapped_span.data(); | 158 | const StagingBufferRef staging = [&] { |
| 159 | if (host_visible) { | ||
| 160 | return StagingBufferRef{}; | ||
| 161 | } | ||
| 162 | return staging_pool.Request(size_bytes, MemoryUsage::Upload); | ||
| 163 | }(); | ||
| 164 | |||
| 165 | u8* staging_data = host_visible ? buffer.Mapped().data() : staging.mapped_span.data(); | ||
| 158 | const size_t quad_size = bytes_per_index * 6; | 166 | const size_t quad_size = bytes_per_index * 6; |
| 159 | 167 | ||
| 160 | for (u32 first = 0; first < num_first_offset_copies; ++first) { | 168 | for (u32 first = 0; first < num_first_offset_copies; ++first) { |
| @@ -164,29 +172,33 @@ public: | |||
| 164 | } | 172 | } |
| 165 | } | 173 | } |
| 166 | 174 | ||
| 167 | scheduler.RequestOutsideRenderPassOperationContext(); | 175 | if (!host_visible) { |
| 168 | scheduler.Record([src_buffer = staging.buffer, src_offset = staging.offset, | 176 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 169 | dst_buffer = *buffer, size_bytes](vk::CommandBuffer cmdbuf) { | 177 | scheduler.Record([src_buffer = staging.buffer, src_offset = staging.offset, |
| 170 | const VkBufferCopy copy{ | 178 | dst_buffer = *buffer, size_bytes](vk::CommandBuffer cmdbuf) { |
| 171 | .srcOffset = src_offset, | 179 | const VkBufferCopy copy{ |
| 172 | .dstOffset = 0, | 180 | .srcOffset = src_offset, |
| 173 | .size = size_bytes, | 181 | .dstOffset = 0, |
| 174 | }; | 182 | .size = size_bytes, |
| 175 | const VkBufferMemoryBarrier write_barrier{ | 183 | }; |
| 176 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, | 184 | const VkBufferMemoryBarrier write_barrier{ |
| 177 | .pNext = nullptr, | 185 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, |
| 178 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | 186 | .pNext = nullptr, |
| 179 | .dstAccessMask = VK_ACCESS_INDEX_READ_BIT, | 187 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, |
| 180 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 188 | .dstAccessMask = VK_ACCESS_INDEX_READ_BIT, |
| 181 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 189 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 182 | .buffer = dst_buffer, | 190 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 183 | .offset = 0, | 191 | .buffer = dst_buffer, |
| 184 | .size = size_bytes, | 192 | .offset = 0, |
| 185 | }; | 193 | .size = size_bytes, |
| 186 | cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy); | 194 | }; |
| 187 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, | 195 | cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy); |
| 188 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, write_barrier); | 196 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, |
| 189 | }); | 197 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, write_barrier); |
| 198 | }); | ||
| 199 | } else { | ||
| 200 | buffer.Flush(); | ||
| 201 | } | ||
| 190 | } | 202 | } |
| 191 | 203 | ||
| 192 | void BindBuffer(u32 first) { | 204 | void BindBuffer(u32 first) { |
| @@ -361,7 +373,7 @@ void BufferCacheRuntime::CopyBuffer(VkBuffer dst_buffer, VkBuffer src_buffer, | |||
| 361 | .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, | 373 | .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, |
| 362 | }; | 374 | }; |
| 363 | // Measuring a popular game, this number never exceeds the specified size once data is warmed up | 375 | // Measuring a popular game, this number never exceeds the specified size once data is warmed up |
| 364 | boost::container::small_vector<VkBufferCopy, 3> vk_copies(copies.size()); | 376 | boost::container::small_vector<VkBufferCopy, 8> vk_copies(copies.size()); |
| 365 | std::ranges::transform(copies, vk_copies.begin(), MakeBufferCopy); | 377 | std::ranges::transform(copies, vk_copies.begin(), MakeBufferCopy); |
| 366 | scheduler.RequestOutsideRenderPassOperationContext(); | 378 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 367 | scheduler.Record([src_buffer, dst_buffer, vk_copies, barrier](vk::CommandBuffer cmdbuf) { | 379 | scheduler.Record([src_buffer, dst_buffer, vk_copies, barrier](vk::CommandBuffer cmdbuf) { |
| @@ -578,7 +590,8 @@ void BufferCacheRuntime::ReserveNullBuffer() { | |||
| 578 | .pNext = nullptr, | 590 | .pNext = nullptr, |
| 579 | .flags = 0, | 591 | .flags = 0, |
| 580 | .size = 4, | 592 | .size = 4, |
| 581 | .usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, | 593 | .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | |
| 594 | VK_BUFFER_USAGE_TRANSFER_DST_BIT, | ||
| 582 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 595 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 583 | .queueFamilyIndexCount = 0, | 596 | .queueFamilyIndexCount = 0, |
| 584 | .pQueueFamilyIndices = nullptr, | 597 | .pQueueFamilyIndices = nullptr, |
| @@ -587,11 +600,10 @@ void BufferCacheRuntime::ReserveNullBuffer() { | |||
| 587 | create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; | 600 | create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; |
| 588 | } | 601 | } |
| 589 | create_info.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; | 602 | create_info.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; |
| 590 | null_buffer = device.GetLogical().CreateBuffer(create_info); | 603 | null_buffer = memory_allocator.CreateBuffer(create_info, MemoryUsage::DeviceLocal); |
| 591 | if (device.HasDebuggingToolAttached()) { | 604 | if (device.HasDebuggingToolAttached()) { |
| 592 | null_buffer.SetObjectNameEXT("Null buffer"); | 605 | null_buffer.SetObjectNameEXT("Null buffer"); |
| 593 | } | 606 | } |
| 594 | null_buffer_commit = memory_allocator.Commit(null_buffer, MemoryUsage::DeviceLocal); | ||
| 595 | 607 | ||
| 596 | scheduler.RequestOutsideRenderPassOperationContext(); | 608 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 597 | scheduler.Record([buffer = *null_buffer](vk::CommandBuffer cmdbuf) { | 609 | scheduler.Record([buffer = *null_buffer](vk::CommandBuffer cmdbuf) { |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index cdeef8846..95446c732 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h | |||
| @@ -48,7 +48,6 @@ private: | |||
| 48 | 48 | ||
| 49 | const Device* device{}; | 49 | const Device* device{}; |
| 50 | vk::Buffer buffer; | 50 | vk::Buffer buffer; |
| 51 | MemoryCommit commit; | ||
| 52 | std::vector<BufferView> views; | 51 | std::vector<BufferView> views; |
| 53 | }; | 52 | }; |
| 54 | 53 | ||
| @@ -142,7 +141,6 @@ private: | |||
| 142 | std::shared_ptr<QuadStripIndexBuffer> quad_strip_index_buffer; | 141 | std::shared_ptr<QuadStripIndexBuffer> quad_strip_index_buffer; |
| 143 | 142 | ||
| 144 | vk::Buffer null_buffer; | 143 | vk::Buffer null_buffer; |
| 145 | MemoryCommit null_buffer_commit; | ||
| 146 | 144 | ||
| 147 | std::unique_ptr<Uint8Pass> uint8_pass; | 145 | std::unique_ptr<Uint8Pass> uint8_pass; |
| 148 | QuadIndexedPass quad_index_pass; | 146 | QuadIndexedPass quad_index_pass; |
diff --git a/src/video_core/renderer_vulkan/vk_fsr.cpp b/src/video_core/renderer_vulkan/vk_fsr.cpp index df972cd54..9bcdca2fb 100644 --- a/src/video_core/renderer_vulkan/vk_fsr.cpp +++ b/src/video_core/renderer_vulkan/vk_fsr.cpp | |||
| @@ -205,10 +205,9 @@ void FSR::CreateDescriptorSets() { | |||
| 205 | void FSR::CreateImages() { | 205 | void FSR::CreateImages() { |
| 206 | images.resize(image_count * 2); | 206 | images.resize(image_count * 2); |
| 207 | image_views.resize(image_count * 2); | 207 | image_views.resize(image_count * 2); |
| 208 | buffer_commits.resize(image_count * 2); | ||
| 209 | 208 | ||
| 210 | for (size_t i = 0; i < image_count * 2; ++i) { | 209 | for (size_t i = 0; i < image_count * 2; ++i) { |
| 211 | images[i] = device.GetLogical().CreateImage(VkImageCreateInfo{ | 210 | images[i] = memory_allocator.CreateImage(VkImageCreateInfo{ |
| 212 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 211 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| 213 | .pNext = nullptr, | 212 | .pNext = nullptr, |
| 214 | .flags = 0, | 213 | .flags = 0, |
| @@ -231,7 +230,6 @@ void FSR::CreateImages() { | |||
| 231 | .pQueueFamilyIndices = nullptr, | 230 | .pQueueFamilyIndices = nullptr, |
| 232 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 231 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
| 233 | }); | 232 | }); |
| 234 | buffer_commits[i] = memory_allocator.Commit(images[i], MemoryUsage::DeviceLocal); | ||
| 235 | image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | 233 | image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ |
| 236 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 234 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| 237 | .pNext = nullptr, | 235 | .pNext = nullptr, |
diff --git a/src/video_core/renderer_vulkan/vk_fsr.h b/src/video_core/renderer_vulkan/vk_fsr.h index 5d872861f..8bb9fc23a 100644 --- a/src/video_core/renderer_vulkan/vk_fsr.h +++ b/src/video_core/renderer_vulkan/vk_fsr.h | |||
| @@ -47,7 +47,6 @@ private: | |||
| 47 | vk::Sampler sampler; | 47 | vk::Sampler sampler; |
| 48 | std::vector<vk::Image> images; | 48 | std::vector<vk::Image> images; |
| 49 | std::vector<vk::ImageView> image_views; | 49 | std::vector<vk::ImageView> image_views; |
| 50 | std::vector<MemoryCommit> buffer_commits; | ||
| 51 | }; | 50 | }; |
| 52 | 51 | ||
| 53 | } // namespace Vulkan | 52 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index c1595642e..ad35cacac 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -652,13 +652,14 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { | |||
| 652 | .pNext = nullptr, | 652 | .pNext = nullptr, |
| 653 | .negativeOneToOne = key.state.ndc_minus_one_to_one.Value() != 0 ? VK_TRUE : VK_FALSE, | 653 | .negativeOneToOne = key.state.ndc_minus_one_to_one.Value() != 0 ? VK_TRUE : VK_FALSE, |
| 654 | }; | 654 | }; |
| 655 | const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports); | ||
| 655 | VkPipelineViewportStateCreateInfo viewport_ci{ | 656 | VkPipelineViewportStateCreateInfo viewport_ci{ |
| 656 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, | 657 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, |
| 657 | .pNext = nullptr, | 658 | .pNext = nullptr, |
| 658 | .flags = 0, | 659 | .flags = 0, |
| 659 | .viewportCount = Maxwell::NumViewports, | 660 | .viewportCount = num_viewports, |
| 660 | .pViewports = nullptr, | 661 | .pViewports = nullptr, |
| 661 | .scissorCount = Maxwell::NumViewports, | 662 | .scissorCount = num_viewports, |
| 662 | .pScissors = nullptr, | 663 | .pScissors = nullptr, |
| 663 | }; | 664 | }; |
| 664 | if (device.IsNvViewportSwizzleSupported()) { | 665 | if (device.IsNvViewportSwizzleSupported()) { |
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp index 5eeda08d2..6b288b994 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp | |||
| @@ -75,15 +75,9 @@ void MasterSemaphore::Refresh() { | |||
| 75 | 75 | ||
| 76 | void MasterSemaphore::Wait(u64 tick) { | 76 | void MasterSemaphore::Wait(u64 tick) { |
| 77 | if (!semaphore) { | 77 | if (!semaphore) { |
| 78 | // If we don't support timeline semaphores, use an atomic wait | 78 | // If we don't support timeline semaphores, wait for the value normally |
| 79 | while (true) { | 79 | std::unique_lock lk{free_mutex}; |
| 80 | u64 current_value = gpu_tick.load(std::memory_order_relaxed); | 80 | free_cv.wait(lk, [&] { return gpu_tick.load(std::memory_order_relaxed) >= tick; }); |
| 81 | if (current_value >= tick) { | ||
| 82 | return; | ||
| 83 | } | ||
| 84 | gpu_tick.wait(current_value); | ||
| 85 | } | ||
| 86 | |||
| 87 | return; | 81 | return; |
| 88 | } | 82 | } |
| 89 | 83 | ||
| @@ -198,11 +192,13 @@ void MasterSemaphore::WaitThread(std::stop_token token) { | |||
| 198 | 192 | ||
| 199 | fence.Wait(); | 193 | fence.Wait(); |
| 200 | fence.Reset(); | 194 | fence.Reset(); |
| 201 | gpu_tick.store(host_tick); | ||
| 202 | gpu_tick.notify_all(); | ||
| 203 | 195 | ||
| 204 | std::scoped_lock lock{free_mutex}; | 196 | { |
| 205 | free_queue.push_front(std::move(fence)); | 197 | std::scoped_lock lock{free_mutex}; |
| 198 | free_queue.push_front(std::move(fence)); | ||
| 199 | gpu_tick.store(host_tick); | ||
| 200 | } | ||
| 201 | free_cv.notify_one(); | ||
| 206 | } | 202 | } |
| 207 | } | 203 | } |
| 208 | 204 | ||
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h index 1e7c90215..3f599d7bd 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.h +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h | |||
| @@ -72,6 +72,7 @@ private: | |||
| 72 | std::atomic<u64> current_tick{1}; ///< Current logical tick. | 72 | std::atomic<u64> current_tick{1}; ///< Current logical tick. |
| 73 | std::mutex wait_mutex; | 73 | std::mutex wait_mutex; |
| 74 | std::mutex free_mutex; | 74 | std::mutex free_mutex; |
| 75 | std::condition_variable free_cv; | ||
| 75 | std::condition_variable_any wait_cv; | 76 | std::condition_variable_any wait_cv; |
| 76 | std::queue<Waitable> wait_queue; ///< Queue for the fences to be waited on by the wait thread. | 77 | std::queue<Waitable> wait_queue; ///< Queue for the fences to be waited on by the wait thread. |
| 77 | std::deque<vk::Fence> free_queue; ///< Holds available fences for submission. | 78 | std::deque<vk::Fence> free_queue; ///< Holds available fences for submission. |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 18e040a1b..d600c4e61 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -167,7 +167,10 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program | |||
| 167 | info.fixed_state_point_size = point_size; | 167 | info.fixed_state_point_size = point_size; |
| 168 | } | 168 | } |
| 169 | if (key.state.xfb_enabled) { | 169 | if (key.state.xfb_enabled) { |
| 170 | info.xfb_varyings = VideoCommon::MakeTransformFeedbackVaryings(key.state.xfb_state); | 170 | auto [varyings, count] = |
| 171 | VideoCommon::MakeTransformFeedbackVaryings(key.state.xfb_state); | ||
| 172 | info.xfb_varyings = varyings; | ||
| 173 | info.xfb_count = count; | ||
| 171 | } | 174 | } |
| 172 | info.convert_depth_mode = gl_ndc; | 175 | info.convert_depth_mode = gl_ndc; |
| 173 | } | 176 | } |
| @@ -214,7 +217,10 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program | |||
| 214 | info.fixed_state_point_size = point_size; | 217 | info.fixed_state_point_size = point_size; |
| 215 | } | 218 | } |
| 216 | if (key.state.xfb_enabled != 0) { | 219 | if (key.state.xfb_enabled != 0) { |
| 217 | info.xfb_varyings = VideoCommon::MakeTransformFeedbackVaryings(key.state.xfb_state); | 220 | auto [varyings, count] = |
| 221 | VideoCommon::MakeTransformFeedbackVaryings(key.state.xfb_state); | ||
| 222 | info.xfb_varyings = varyings; | ||
| 223 | info.xfb_count = count; | ||
| 218 | } | 224 | } |
| 219 | info.convert_depth_mode = gl_ndc; | 225 | info.convert_depth_mode = gl_ndc; |
| 220 | break; | 226 | break; |
| @@ -303,7 +309,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device | |||
| 303 | .support_int16 = device.IsShaderInt16Supported(), | 309 | .support_int16 = device.IsShaderInt16Supported(), |
| 304 | .support_int64 = device.IsShaderInt64Supported(), | 310 | .support_int64 = device.IsShaderInt64Supported(), |
| 305 | .support_vertex_instance_id = false, | 311 | .support_vertex_instance_id = false, |
| 306 | .support_float_controls = true, | 312 | .support_float_controls = device.IsKhrShaderFloatControlsSupported(), |
| 307 | .support_separate_denorm_behavior = | 313 | .support_separate_denorm_behavior = |
| 308 | float_control.denormBehaviorIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL, | 314 | float_control.denormBehaviorIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL, |
| 309 | .support_separate_rounding_mode = | 315 | .support_separate_rounding_mode = |
| @@ -319,12 +325,13 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device | |||
| 319 | .support_fp64_signed_zero_nan_preserve = | 325 | .support_fp64_signed_zero_nan_preserve = |
| 320 | float_control.shaderSignedZeroInfNanPreserveFloat64 != VK_FALSE, | 326 | float_control.shaderSignedZeroInfNanPreserveFloat64 != VK_FALSE, |
| 321 | .support_explicit_workgroup_layout = device.IsKhrWorkgroupMemoryExplicitLayoutSupported(), | 327 | .support_explicit_workgroup_layout = device.IsKhrWorkgroupMemoryExplicitLayoutSupported(), |
| 322 | .support_vote = true, | 328 | .support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT), |
| 323 | .support_viewport_index_layer_non_geometry = | 329 | .support_viewport_index_layer_non_geometry = |
| 324 | device.IsExtShaderViewportIndexLayerSupported(), | 330 | device.IsExtShaderViewportIndexLayerSupported(), |
| 325 | .support_viewport_mask = device.IsNvViewportArray2Supported(), | 331 | .support_viewport_mask = device.IsNvViewportArray2Supported(), |
| 326 | .support_typeless_image_loads = device.IsFormatlessImageLoadSupported(), | 332 | .support_typeless_image_loads = device.IsFormatlessImageLoadSupported(), |
| 327 | .support_demote_to_helper_invocation = true, | 333 | .support_demote_to_helper_invocation = |
| 334 | device.IsExtShaderDemoteToHelperInvocationSupported(), | ||
| 328 | .support_int64_atomics = device.IsExtShaderAtomicInt64Supported(), | 335 | .support_int64_atomics = device.IsExtShaderAtomicInt64Supported(), |
| 329 | .support_derivative_control = true, | 336 | .support_derivative_control = true, |
| 330 | .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(), | 337 | .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(), |
| @@ -705,10 +712,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( | |||
| 705 | std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( | 712 | std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( |
| 706 | ShaderPools& pools, const ComputePipelineCacheKey& key, Shader::Environment& env, | 713 | ShaderPools& pools, const ComputePipelineCacheKey& key, Shader::Environment& env, |
| 707 | PipelineStatistics* statistics, bool build_in_parallel) try { | 714 | PipelineStatistics* statistics, bool build_in_parallel) try { |
| 708 | // TODO: Remove this when Intel fixes their shader compiler. | 715 | if (device.HasBrokenCompute()) { |
| 709 | // https://github.com/IGCIT/Intel-GPU-Community-Issue-Tracker-IGCIT/issues/159 | ||
| 710 | if (device.GetDriverID() == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS && | ||
| 711 | !Settings::values.enable_compute_pipelines.GetValue()) { | ||
| 712 | LOG_ERROR(Render_Vulkan, "Skipping 0x{:016x}", key.Hash()); | 716 | LOG_ERROR(Render_Vulkan, "Skipping 0x{:016x}", key.Hash()); |
| 713 | return nullptr; | 717 | return nullptr; |
| 714 | } | 718 | } |
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp index 10ace0420..d681bd22a 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp | |||
| @@ -181,7 +181,7 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_ | |||
| 181 | frame->height = height; | 181 | frame->height = height; |
| 182 | frame->is_srgb = is_srgb; | 182 | frame->is_srgb = is_srgb; |
| 183 | 183 | ||
| 184 | frame->image = dld.CreateImage({ | 184 | frame->image = memory_allocator.CreateImage({ |
| 185 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 185 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| 186 | .pNext = nullptr, | 186 | .pNext = nullptr, |
| 187 | .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, | 187 | .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, |
| @@ -204,8 +204,6 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_ | |||
| 204 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 204 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
| 205 | }); | 205 | }); |
| 206 | 206 | ||
| 207 | frame->image_commit = memory_allocator.Commit(frame->image, MemoryUsage::DeviceLocal); | ||
| 208 | |||
| 209 | frame->image_view = dld.CreateImageView({ | 207 | frame->image_view = dld.CreateImageView({ |
| 210 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 208 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| 211 | .pNext = nullptr, | 209 | .pNext = nullptr, |
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h index 4ac2e2395..83e859416 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.h +++ b/src/video_core/renderer_vulkan/vk_present_manager.h | |||
| @@ -29,7 +29,6 @@ struct Frame { | |||
| 29 | vk::Image image; | 29 | vk::Image image; |
| 30 | vk::ImageView image_view; | 30 | vk::ImageView image_view; |
| 31 | vk::Framebuffer framebuffer; | 31 | vk::Framebuffer framebuffer; |
| 32 | MemoryCommit image_commit; | ||
| 33 | vk::CommandBuffer cmdbuf; | 32 | vk::CommandBuffer cmdbuf; |
| 34 | vk::Semaphore render_ready; | 33 | vk::Semaphore render_ready; |
| 35 | vk::Fence present_done; | 34 | vk::Fence present_done; |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 84e3a30cc..f7c0d939a 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -315,7 +315,14 @@ void RasterizerVulkan::Clear(u32 layer_count) { | |||
| 315 | FlushWork(); | 315 | FlushWork(); |
| 316 | gpu_memory->FlushCaching(); | 316 | gpu_memory->FlushCaching(); |
| 317 | 317 | ||
| 318 | #if ANDROID | ||
| 319 | if (Settings::IsGPULevelHigh()) { | ||
| 320 | // This is problematic on Android, disable on GPU Normal. | ||
| 321 | query_cache.UpdateCounters(); | ||
| 322 | } | ||
| 323 | #else | ||
| 318 | query_cache.UpdateCounters(); | 324 | query_cache.UpdateCounters(); |
| 325 | #endif | ||
| 319 | 326 | ||
| 320 | auto& regs = maxwell3d->regs; | 327 | auto& regs = maxwell3d->regs; |
| 321 | const bool use_color = regs.clear_surface.R || regs.clear_surface.G || regs.clear_surface.B || | 328 | const bool use_color = regs.clear_surface.R || regs.clear_surface.G || regs.clear_surface.B || |
| @@ -925,7 +932,7 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg | |||
| 925 | } | 932 | } |
| 926 | const bool is_rescaling{texture_cache.IsRescaling()}; | 933 | const bool is_rescaling{texture_cache.IsRescaling()}; |
| 927 | const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f; | 934 | const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f; |
| 928 | const std::array viewports{ | 935 | const std::array viewport_list{ |
| 929 | GetViewportState(device, regs, 0, scale), GetViewportState(device, regs, 1, scale), | 936 | GetViewportState(device, regs, 0, scale), GetViewportState(device, regs, 1, scale), |
| 930 | GetViewportState(device, regs, 2, scale), GetViewportState(device, regs, 3, scale), | 937 | GetViewportState(device, regs, 2, scale), GetViewportState(device, regs, 3, scale), |
| 931 | GetViewportState(device, regs, 4, scale), GetViewportState(device, regs, 5, scale), | 938 | GetViewportState(device, regs, 4, scale), GetViewportState(device, regs, 5, scale), |
| @@ -935,7 +942,11 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg | |||
| 935 | GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale), | 942 | GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale), |
| 936 | GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale), | 943 | GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale), |
| 937 | }; | 944 | }; |
| 938 | scheduler.Record([viewports](vk::CommandBuffer cmdbuf) { cmdbuf.SetViewport(0, viewports); }); | 945 | scheduler.Record([this, viewport_list](vk::CommandBuffer cmdbuf) { |
| 946 | const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports); | ||
| 947 | const vk::Span<VkViewport> viewports(viewport_list.data(), num_viewports); | ||
| 948 | cmdbuf.SetViewport(0, viewports); | ||
| 949 | }); | ||
| 939 | } | 950 | } |
| 940 | 951 | ||
| 941 | void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs) { | 952 | void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs) { |
| @@ -948,7 +959,7 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs | |||
| 948 | up_scale = Settings::values.resolution_info.up_scale; | 959 | up_scale = Settings::values.resolution_info.up_scale; |
| 949 | down_shift = Settings::values.resolution_info.down_shift; | 960 | down_shift = Settings::values.resolution_info.down_shift; |
| 950 | } | 961 | } |
| 951 | const std::array scissors{ | 962 | const std::array scissor_list{ |
| 952 | GetScissorState(regs, 0, up_scale, down_shift), | 963 | GetScissorState(regs, 0, up_scale, down_shift), |
| 953 | GetScissorState(regs, 1, up_scale, down_shift), | 964 | GetScissorState(regs, 1, up_scale, down_shift), |
| 954 | GetScissorState(regs, 2, up_scale, down_shift), | 965 | GetScissorState(regs, 2, up_scale, down_shift), |
| @@ -966,7 +977,11 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs | |||
| 966 | GetScissorState(regs, 14, up_scale, down_shift), | 977 | GetScissorState(regs, 14, up_scale, down_shift), |
| 967 | GetScissorState(regs, 15, up_scale, down_shift), | 978 | GetScissorState(regs, 15, up_scale, down_shift), |
| 968 | }; | 979 | }; |
| 969 | scheduler.Record([scissors](vk::CommandBuffer cmdbuf) { cmdbuf.SetScissor(0, scissors); }); | 980 | scheduler.Record([this, scissor_list](vk::CommandBuffer cmdbuf) { |
| 981 | const u32 num_scissors = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports); | ||
| 982 | const vk::Span<VkRect2D> scissors(scissor_list.data(), num_scissors); | ||
| 983 | cmdbuf.SetScissor(0, scissors); | ||
| 984 | }); | ||
| 970 | } | 985 | } |
| 971 | 986 | ||
| 972 | void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) { | 987 | void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) { |
diff --git a/src/video_core/renderer_vulkan/vk_smaa.cpp b/src/video_core/renderer_vulkan/vk_smaa.cpp index f8735189d..5efd7d66e 100644 --- a/src/video_core/renderer_vulkan/vk_smaa.cpp +++ b/src/video_core/renderer_vulkan/vk_smaa.cpp | |||
| @@ -25,9 +25,7 @@ namespace { | |||
| 25 | 25 | ||
| 26 | #define ARRAY_TO_SPAN(a) std::span(a, (sizeof(a) / sizeof(a[0]))) | 26 | #define ARRAY_TO_SPAN(a) std::span(a, (sizeof(a) / sizeof(a[0]))) |
| 27 | 27 | ||
| 28 | std::pair<vk::Image, MemoryCommit> CreateWrappedImage(const Device& device, | 28 | vk::Image CreateWrappedImage(MemoryAllocator& allocator, VkExtent2D dimensions, VkFormat format) { |
| 29 | MemoryAllocator& allocator, | ||
| 30 | VkExtent2D dimensions, VkFormat format) { | ||
| 31 | const VkImageCreateInfo image_ci{ | 29 | const VkImageCreateInfo image_ci{ |
| 32 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 30 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| 33 | .pNext = nullptr, | 31 | .pNext = nullptr, |
| @@ -46,11 +44,7 @@ std::pair<vk::Image, MemoryCommit> CreateWrappedImage(const Device& device, | |||
| 46 | .pQueueFamilyIndices = nullptr, | 44 | .pQueueFamilyIndices = nullptr, |
| 47 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 45 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
| 48 | }; | 46 | }; |
| 49 | 47 | return allocator.CreateImage(image_ci); | |
| 50 | auto image = device.GetLogical().CreateImage(image_ci); | ||
| 51 | auto commit = allocator.Commit(image, Vulkan::MemoryUsage::DeviceLocal); | ||
| 52 | |||
| 53 | return std::make_pair(std::move(image), std::move(commit)); | ||
| 54 | } | 48 | } |
| 55 | 49 | ||
| 56 | void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout, | 50 | void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout, |
| @@ -82,7 +76,7 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo | |||
| 82 | void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler, | 76 | void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler, |
| 83 | vk::Image& image, VkExtent2D dimensions, VkFormat format, | 77 | vk::Image& image, VkExtent2D dimensions, VkFormat format, |
| 84 | std::span<const u8> initial_contents = {}) { | 78 | std::span<const u8> initial_contents = {}) { |
| 85 | auto upload_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{ | 79 | const VkBufferCreateInfo upload_ci = { |
| 86 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 80 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 87 | .pNext = nullptr, | 81 | .pNext = nullptr, |
| 88 | .flags = 0, | 82 | .flags = 0, |
| @@ -91,9 +85,10 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc | |||
| 91 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 85 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 92 | .queueFamilyIndexCount = 0, | 86 | .queueFamilyIndexCount = 0, |
| 93 | .pQueueFamilyIndices = nullptr, | 87 | .pQueueFamilyIndices = nullptr, |
| 94 | }); | 88 | }; |
| 95 | auto upload_commit = allocator.Commit(upload_buffer, MemoryUsage::Upload); | 89 | auto upload_buffer = allocator.CreateBuffer(upload_ci, MemoryUsage::Upload); |
| 96 | std::ranges::copy(initial_contents, upload_commit.Map().begin()); | 90 | std::ranges::copy(initial_contents, upload_buffer.Mapped().begin()); |
| 91 | upload_buffer.Flush(); | ||
| 97 | 92 | ||
| 98 | const std::array<VkBufferImageCopy, 1> regions{{{ | 93 | const std::array<VkBufferImageCopy, 1> regions{{{ |
| 99 | .bufferOffset = 0, | 94 | .bufferOffset = 0, |
| @@ -117,9 +112,6 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc | |||
| 117 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); | 112 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); |
| 118 | }); | 113 | }); |
| 119 | scheduler.Finish(); | 114 | scheduler.Finish(); |
| 120 | |||
| 121 | // This should go out of scope before the commit | ||
| 122 | auto upload_buffer2 = std::move(upload_buffer); | ||
| 123 | } | 115 | } |
| 124 | 116 | ||
| 125 | vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format) { | 117 | vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format) { |
| @@ -531,10 +523,8 @@ void SMAA::CreateImages() { | |||
| 531 | static constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT}; | 523 | static constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT}; |
| 532 | static constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT}; | 524 | static constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT}; |
| 533 | 525 | ||
| 534 | std::tie(m_static_images[Area], m_static_buffer_commits[Area]) = | 526 | m_static_images[Area] = CreateWrappedImage(m_allocator, area_extent, VK_FORMAT_R8G8_UNORM); |
| 535 | CreateWrappedImage(m_device, m_allocator, area_extent, VK_FORMAT_R8G8_UNORM); | 527 | m_static_images[Search] = CreateWrappedImage(m_allocator, search_extent, VK_FORMAT_R8_UNORM); |
| 536 | std::tie(m_static_images[Search], m_static_buffer_commits[Search]) = | ||
| 537 | CreateWrappedImage(m_device, m_allocator, search_extent, VK_FORMAT_R8_UNORM); | ||
| 538 | 528 | ||
| 539 | m_static_image_views[Area] = | 529 | m_static_image_views[Area] = |
| 540 | CreateWrappedImageView(m_device, m_static_images[Area], VK_FORMAT_R8G8_UNORM); | 530 | CreateWrappedImageView(m_device, m_static_images[Area], VK_FORMAT_R8G8_UNORM); |
| @@ -544,12 +534,11 @@ void SMAA::CreateImages() { | |||
| 544 | for (u32 i = 0; i < m_image_count; i++) { | 534 | for (u32 i = 0; i < m_image_count; i++) { |
| 545 | Images& images = m_dynamic_images.emplace_back(); | 535 | Images& images = m_dynamic_images.emplace_back(); |
| 546 | 536 | ||
| 547 | std::tie(images.images[Blend], images.buffer_commits[Blend]) = | 537 | images.images[Blend] = |
| 548 | CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT); | 538 | CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT); |
| 549 | std::tie(images.images[Edges], images.buffer_commits[Edges]) = | 539 | images.images[Edges] = CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16_SFLOAT); |
| 550 | CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16_SFLOAT); | 540 | images.images[Output] = |
| 551 | std::tie(images.images[Output], images.buffer_commits[Output]) = | 541 | CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT); |
| 552 | CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT); | ||
| 553 | 542 | ||
| 554 | images.image_views[Blend] = | 543 | images.image_views[Blend] = |
| 555 | CreateWrappedImageView(m_device, images.images[Blend], VK_FORMAT_R16G16B16A16_SFLOAT); | 544 | CreateWrappedImageView(m_device, images.images[Blend], VK_FORMAT_R16G16B16A16_SFLOAT); |
diff --git a/src/video_core/renderer_vulkan/vk_smaa.h b/src/video_core/renderer_vulkan/vk_smaa.h index 99a369148..0e214258a 100644 --- a/src/video_core/renderer_vulkan/vk_smaa.h +++ b/src/video_core/renderer_vulkan/vk_smaa.h | |||
| @@ -66,13 +66,11 @@ private: | |||
| 66 | std::array<vk::Pipeline, MaxSMAAStage> m_pipelines{}; | 66 | std::array<vk::Pipeline, MaxSMAAStage> m_pipelines{}; |
| 67 | std::array<vk::RenderPass, MaxSMAAStage> m_renderpasses{}; | 67 | std::array<vk::RenderPass, MaxSMAAStage> m_renderpasses{}; |
| 68 | 68 | ||
| 69 | std::array<MemoryCommit, MaxStaticImage> m_static_buffer_commits; | ||
| 70 | std::array<vk::Image, MaxStaticImage> m_static_images{}; | 69 | std::array<vk::Image, MaxStaticImage> m_static_images{}; |
| 71 | std::array<vk::ImageView, MaxStaticImage> m_static_image_views{}; | 70 | std::array<vk::ImageView, MaxStaticImage> m_static_image_views{}; |
| 72 | 71 | ||
| 73 | struct Images { | 72 | struct Images { |
| 74 | vk::DescriptorSets descriptor_sets{}; | 73 | vk::DescriptorSets descriptor_sets{}; |
| 75 | std::array<MemoryCommit, MaxDynamicImage> buffer_commits; | ||
| 76 | std::array<vk::Image, MaxDynamicImage> images{}; | 74 | std::array<vk::Image, MaxDynamicImage> images{}; |
| 77 | std::array<vk::ImageView, MaxDynamicImage> image_views{}; | 75 | std::array<vk::ImageView, MaxDynamicImage> image_views{}; |
| 78 | std::array<vk::Framebuffer, MaxSMAAStage> framebuffers{}; | 76 | std::array<vk::Framebuffer, MaxSMAAStage> framebuffers{}; |
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp index 74ca77216..ce92f66ab 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp | |||
| @@ -30,55 +30,6 @@ constexpr VkDeviceSize MAX_STREAM_BUFFER_REQUEST_SIZE = 8_MiB; | |||
| 30 | constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128_MiB; | 30 | constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128_MiB; |
| 31 | constexpr VkDeviceSize REGION_SIZE = STREAM_BUFFER_SIZE / StagingBufferPool::NUM_SYNCS; | 31 | constexpr VkDeviceSize REGION_SIZE = STREAM_BUFFER_SIZE / StagingBufferPool::NUM_SYNCS; |
| 32 | 32 | ||
| 33 | constexpr VkMemoryPropertyFlags HOST_FLAGS = | ||
| 34 | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | ||
| 35 | constexpr VkMemoryPropertyFlags STREAM_FLAGS = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | HOST_FLAGS; | ||
| 36 | |||
| 37 | bool IsStreamHeap(VkMemoryHeap heap) noexcept { | ||
| 38 | return STREAM_BUFFER_SIZE < (heap.size * 2) / 3; | ||
| 39 | } | ||
| 40 | |||
| 41 | std::optional<u32> FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask, | ||
| 42 | VkMemoryPropertyFlags flags) noexcept { | ||
| 43 | for (u32 type_index = 0; type_index < props.memoryTypeCount; ++type_index) { | ||
| 44 | if (((type_mask >> type_index) & 1) == 0) { | ||
| 45 | // Memory type is incompatible | ||
| 46 | continue; | ||
| 47 | } | ||
| 48 | const VkMemoryType& memory_type = props.memoryTypes[type_index]; | ||
| 49 | if ((memory_type.propertyFlags & flags) != flags) { | ||
| 50 | // Memory type doesn't have the flags we want | ||
| 51 | continue; | ||
| 52 | } | ||
| 53 | if (!IsStreamHeap(props.memoryHeaps[memory_type.heapIndex])) { | ||
| 54 | // Memory heap is not suitable for streaming | ||
| 55 | continue; | ||
| 56 | } | ||
| 57 | // Success! | ||
| 58 | return type_index; | ||
| 59 | } | ||
| 60 | return std::nullopt; | ||
| 61 | } | ||
| 62 | |||
| 63 | u32 FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask, | ||
| 64 | bool try_device_local) { | ||
| 65 | std::optional<u32> type; | ||
| 66 | if (try_device_local) { | ||
| 67 | // Try to find a DEVICE_LOCAL_BIT type, Nvidia and AMD have a dedicated heap for this | ||
| 68 | type = FindMemoryTypeIndex(props, type_mask, STREAM_FLAGS); | ||
| 69 | if (type) { | ||
| 70 | return *type; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | // Otherwise try without the DEVICE_LOCAL_BIT | ||
| 74 | type = FindMemoryTypeIndex(props, type_mask, HOST_FLAGS); | ||
| 75 | if (type) { | ||
| 76 | return *type; | ||
| 77 | } | ||
| 78 | // This should never happen, and in case it does, signal it as an out of memory situation | ||
| 79 | throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY); | ||
| 80 | } | ||
| 81 | |||
| 82 | size_t Region(size_t iterator) noexcept { | 33 | size_t Region(size_t iterator) noexcept { |
| 83 | return iterator / REGION_SIZE; | 34 | return iterator / REGION_SIZE; |
| 84 | } | 35 | } |
| @@ -87,58 +38,26 @@ size_t Region(size_t iterator) noexcept { | |||
| 87 | StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, | 38 | StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, |
| 88 | Scheduler& scheduler_) | 39 | Scheduler& scheduler_) |
| 89 | : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} { | 40 | : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} { |
| 90 | const vk::Device& dev = device.GetLogical(); | 41 | VkBufferCreateInfo stream_ci = { |
| 91 | stream_buffer = dev.CreateBuffer(VkBufferCreateInfo{ | ||
| 92 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 42 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 93 | .pNext = nullptr, | 43 | .pNext = nullptr, |
| 94 | .flags = 0, | 44 | .flags = 0, |
| 95 | .size = STREAM_BUFFER_SIZE, | 45 | .size = STREAM_BUFFER_SIZE, |
| 96 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | | 46 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | |
| 97 | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | | 47 | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, |
| 98 | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT, | ||
| 99 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 48 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 100 | .queueFamilyIndexCount = 0, | 49 | .queueFamilyIndexCount = 0, |
| 101 | .pQueueFamilyIndices = nullptr, | 50 | .pQueueFamilyIndices = nullptr, |
| 102 | }); | ||
| 103 | if (device.HasDebuggingToolAttached()) { | ||
| 104 | stream_buffer.SetObjectNameEXT("Stream Buffer"); | ||
| 105 | } | ||
| 106 | VkMemoryDedicatedRequirements dedicated_reqs{ | ||
| 107 | .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, | ||
| 108 | .pNext = nullptr, | ||
| 109 | .prefersDedicatedAllocation = VK_FALSE, | ||
| 110 | .requiresDedicatedAllocation = VK_FALSE, | ||
| 111 | }; | ||
| 112 | const auto requirements = dev.GetBufferMemoryRequirements(*stream_buffer, &dedicated_reqs); | ||
| 113 | const bool make_dedicated = dedicated_reqs.prefersDedicatedAllocation == VK_TRUE || | ||
| 114 | dedicated_reqs.requiresDedicatedAllocation == VK_TRUE; | ||
| 115 | const VkMemoryDedicatedAllocateInfo dedicated_info{ | ||
| 116 | .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, | ||
| 117 | .pNext = nullptr, | ||
| 118 | .image = nullptr, | ||
| 119 | .buffer = *stream_buffer, | ||
| 120 | }; | 51 | }; |
| 121 | const auto memory_properties = device.GetPhysical().GetMemoryProperties().memoryProperties; | 52 | if (device.IsExtTransformFeedbackSupported()) { |
| 122 | VkMemoryAllocateInfo stream_memory_info{ | 53 | stream_ci.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; |
| 123 | .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | ||
| 124 | .pNext = make_dedicated ? &dedicated_info : nullptr, | ||
| 125 | .allocationSize = requirements.size, | ||
| 126 | .memoryTypeIndex = | ||
| 127 | FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, true), | ||
| 128 | }; | ||
| 129 | stream_memory = dev.TryAllocateMemory(stream_memory_info); | ||
| 130 | if (!stream_memory) { | ||
| 131 | LOG_INFO(Render_Vulkan, "Dynamic memory allocation failed, trying with system memory"); | ||
| 132 | stream_memory_info.memoryTypeIndex = | ||
| 133 | FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, false); | ||
| 134 | stream_memory = dev.AllocateMemory(stream_memory_info); | ||
| 135 | } | 54 | } |
| 136 | 55 | stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream); | |
| 137 | if (device.HasDebuggingToolAttached()) { | 56 | if (device.HasDebuggingToolAttached()) { |
| 138 | stream_memory.SetObjectNameEXT("Stream Buffer Memory"); | 57 | stream_buffer.SetObjectNameEXT("Stream Buffer"); |
| 139 | } | 58 | } |
| 140 | stream_buffer.BindMemory(*stream_memory, 0); | 59 | stream_pointer = stream_buffer.Mapped(); |
| 141 | stream_pointer = stream_memory.Map(0, STREAM_BUFFER_SIZE); | 60 | ASSERT_MSG(!stream_pointer.empty(), "Stream buffer must be host visible!"); |
| 142 | } | 61 | } |
| 143 | 62 | ||
| 144 | StagingBufferPool::~StagingBufferPool() = default; | 63 | StagingBufferPool::~StagingBufferPool() = default; |
| @@ -199,7 +118,7 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) { | |||
| 199 | return StagingBufferRef{ | 118 | return StagingBufferRef{ |
| 200 | .buffer = *stream_buffer, | 119 | .buffer = *stream_buffer, |
| 201 | .offset = static_cast<VkDeviceSize>(offset), | 120 | .offset = static_cast<VkDeviceSize>(offset), |
| 202 | .mapped_span = std::span<u8>(stream_pointer + offset, size), | 121 | .mapped_span = stream_pointer.subspan(offset, size), |
| 203 | .usage{}, | 122 | .usage{}, |
| 204 | .log2_level{}, | 123 | .log2_level{}, |
| 205 | .index{}, | 124 | .index{}, |
| @@ -247,29 +166,29 @@ std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t s | |||
| 247 | StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage, | 166 | StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage, |
| 248 | bool deferred) { | 167 | bool deferred) { |
| 249 | const u32 log2 = Common::Log2Ceil64(size); | 168 | const u32 log2 = Common::Log2Ceil64(size); |
| 250 | vk::Buffer buffer = device.GetLogical().CreateBuffer({ | 169 | VkBufferCreateInfo buffer_ci = { |
| 251 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 170 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 252 | .pNext = nullptr, | 171 | .pNext = nullptr, |
| 253 | .flags = 0, | 172 | .flags = 0, |
| 254 | .size = 1ULL << log2, | 173 | .size = 1ULL << log2, |
| 255 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | | 174 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | |
| 256 | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | | 175 | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | |
| 257 | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | | 176 | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, |
| 258 | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT, | ||
| 259 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 177 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 260 | .queueFamilyIndexCount = 0, | 178 | .queueFamilyIndexCount = 0, |
| 261 | .pQueueFamilyIndices = nullptr, | 179 | .pQueueFamilyIndices = nullptr, |
| 262 | }); | 180 | }; |
| 181 | if (device.IsExtTransformFeedbackSupported()) { | ||
| 182 | buffer_ci.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; | ||
| 183 | } | ||
| 184 | vk::Buffer buffer = memory_allocator.CreateBuffer(buffer_ci, usage); | ||
| 263 | if (device.HasDebuggingToolAttached()) { | 185 | if (device.HasDebuggingToolAttached()) { |
| 264 | ++buffer_index; | 186 | ++buffer_index; |
| 265 | buffer.SetObjectNameEXT(fmt::format("Staging Buffer {}", buffer_index).c_str()); | 187 | buffer.SetObjectNameEXT(fmt::format("Staging Buffer {}", buffer_index).c_str()); |
| 266 | } | 188 | } |
| 267 | MemoryCommit commit = memory_allocator.Commit(buffer, usage); | 189 | const std::span<u8> mapped_span = buffer.Mapped(); |
| 268 | const std::span<u8> mapped_span = IsHostVisible(usage) ? commit.Map() : std::span<u8>{}; | ||
| 269 | |||
| 270 | StagingBuffer& entry = GetCache(usage)[log2].entries.emplace_back(StagingBuffer{ | 190 | StagingBuffer& entry = GetCache(usage)[log2].entries.emplace_back(StagingBuffer{ |
| 271 | .buffer = std::move(buffer), | 191 | .buffer = std::move(buffer), |
| 272 | .commit = std::move(commit), | ||
| 273 | .mapped_span = mapped_span, | 192 | .mapped_span = mapped_span, |
| 274 | .usage = usage, | 193 | .usage = usage, |
| 275 | .log2_level = log2, | 194 | .log2_level = log2, |
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h index 4fd15f11a..5f69f08b1 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h | |||
| @@ -46,7 +46,6 @@ private: | |||
| 46 | 46 | ||
| 47 | struct StagingBuffer { | 47 | struct StagingBuffer { |
| 48 | vk::Buffer buffer; | 48 | vk::Buffer buffer; |
| 49 | MemoryCommit commit; | ||
| 50 | std::span<u8> mapped_span; | 49 | std::span<u8> mapped_span; |
| 51 | MemoryUsage usage; | 50 | MemoryUsage usage; |
| 52 | u32 log2_level; | 51 | u32 log2_level; |
| @@ -97,8 +96,7 @@ private: | |||
| 97 | Scheduler& scheduler; | 96 | Scheduler& scheduler; |
| 98 | 97 | ||
| 99 | vk::Buffer stream_buffer; | 98 | vk::Buffer stream_buffer; |
| 100 | vk::DeviceMemory stream_memory; | 99 | std::span<u8> stream_pointer; |
| 101 | u8* stream_pointer = nullptr; | ||
| 102 | 100 | ||
| 103 | size_t iterator = 0; | 101 | size_t iterator = 0; |
| 104 | size_t used_iterator = 0; | 102 | size_t used_iterator = 0; |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index f025f618b..8385b5509 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -15,7 +15,6 @@ | |||
| 15 | #include "video_core/renderer_vulkan/blit_image.h" | 15 | #include "video_core/renderer_vulkan/blit_image.h" |
| 16 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 16 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| 17 | #include "video_core/renderer_vulkan/vk_compute_pass.h" | 17 | #include "video_core/renderer_vulkan/vk_compute_pass.h" |
| 18 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | ||
| 19 | #include "video_core/renderer_vulkan/vk_render_pass_cache.h" | 18 | #include "video_core/renderer_vulkan/vk_render_pass_cache.h" |
| 20 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 19 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 21 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 20 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| @@ -163,11 +162,12 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 163 | }; | 162 | }; |
| 164 | } | 163 | } |
| 165 | 164 | ||
| 166 | [[nodiscard]] vk::Image MakeImage(const Device& device, const ImageInfo& info) { | 165 | [[nodiscard]] vk::Image MakeImage(const Device& device, const MemoryAllocator& allocator, |
| 166 | const ImageInfo& info) { | ||
| 167 | if (info.type == ImageType::Buffer) { | 167 | if (info.type == ImageType::Buffer) { |
| 168 | return vk::Image{}; | 168 | return vk::Image{}; |
| 169 | } | 169 | } |
| 170 | return device.GetLogical().CreateImage(MakeImageCreateInfo(device, info)); | 170 | return allocator.CreateImage(MakeImageCreateInfo(device, info)); |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | [[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) { | 173 | [[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) { |
| @@ -330,9 +330,9 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 330 | }; | 330 | }; |
| 331 | } | 331 | } |
| 332 | 332 | ||
| 333 | [[maybe_unused]] [[nodiscard]] std::vector<VkBufferCopy> TransformBufferCopies( | 333 | [[maybe_unused]] [[nodiscard]] boost::container::small_vector<VkBufferCopy, 16> |
| 334 | std::span<const VideoCommon::BufferCopy> copies, size_t buffer_offset) { | 334 | TransformBufferCopies(std::span<const VideoCommon::BufferCopy> copies, size_t buffer_offset) { |
| 335 | std::vector<VkBufferCopy> result(copies.size()); | 335 | boost::container::small_vector<VkBufferCopy, 16> result(copies.size()); |
| 336 | std::ranges::transform( | 336 | std::ranges::transform( |
| 337 | copies, result.begin(), [buffer_offset](const VideoCommon::BufferCopy& copy) { | 337 | copies, result.begin(), [buffer_offset](const VideoCommon::BufferCopy& copy) { |
| 338 | return VkBufferCopy{ | 338 | return VkBufferCopy{ |
| @@ -344,7 +344,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 344 | return result; | 344 | return result; |
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | [[nodiscard]] std::vector<VkBufferImageCopy> TransformBufferImageCopies( | 347 | [[nodiscard]] boost::container::small_vector<VkBufferImageCopy, 16> TransformBufferImageCopies( |
| 348 | std::span<const BufferImageCopy> copies, size_t buffer_offset, VkImageAspectFlags aspect_mask) { | 348 | std::span<const BufferImageCopy> copies, size_t buffer_offset, VkImageAspectFlags aspect_mask) { |
| 349 | struct Maker { | 349 | struct Maker { |
| 350 | VkBufferImageCopy operator()(const BufferImageCopy& copy) const { | 350 | VkBufferImageCopy operator()(const BufferImageCopy& copy) const { |
| @@ -377,14 +377,14 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 377 | VkImageAspectFlags aspect_mask; | 377 | VkImageAspectFlags aspect_mask; |
| 378 | }; | 378 | }; |
| 379 | if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { | 379 | if (aspect_mask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { |
| 380 | std::vector<VkBufferImageCopy> result(copies.size() * 2); | 380 | boost::container::small_vector<VkBufferImageCopy, 16> result(copies.size() * 2); |
| 381 | std::ranges::transform(copies, result.begin(), | 381 | std::ranges::transform(copies, result.begin(), |
| 382 | Maker{buffer_offset, VK_IMAGE_ASPECT_DEPTH_BIT}); | 382 | Maker{buffer_offset, VK_IMAGE_ASPECT_DEPTH_BIT}); |
| 383 | std::ranges::transform(copies, result.begin() + copies.size(), | 383 | std::ranges::transform(copies, result.begin() + copies.size(), |
| 384 | Maker{buffer_offset, VK_IMAGE_ASPECT_STENCIL_BIT}); | 384 | Maker{buffer_offset, VK_IMAGE_ASPECT_STENCIL_BIT}); |
| 385 | return result; | 385 | return result; |
| 386 | } else { | 386 | } else { |
| 387 | std::vector<VkBufferImageCopy> result(copies.size()); | 387 | boost::container::small_vector<VkBufferImageCopy, 16> result(copies.size()); |
| 388 | std::ranges::transform(copies, result.begin(), Maker{buffer_offset, aspect_mask}); | 388 | std::ranges::transform(copies, result.begin(), Maker{buffer_offset, aspect_mask}); |
| 389 | return result; | 389 | return result; |
| 390 | } | 390 | } |
| @@ -839,14 +839,14 @@ bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) { | |||
| 839 | 839 | ||
| 840 | VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { | 840 | VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { |
| 841 | const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL); | 841 | const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL); |
| 842 | if (buffer_commits[level]) { | 842 | if (buffers[level]) { |
| 843 | return *buffers[level]; | 843 | return *buffers[level]; |
| 844 | } | 844 | } |
| 845 | const auto new_size = Common::NextPow2(needed_size); | 845 | const auto new_size = Common::NextPow2(needed_size); |
| 846 | static constexpr VkBufferUsageFlags flags = | 846 | static constexpr VkBufferUsageFlags flags = |
| 847 | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | | 847 | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | |
| 848 | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; | 848 | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; |
| 849 | buffers[level] = device.GetLogical().CreateBuffer({ | 849 | const VkBufferCreateInfo temp_ci = { |
| 850 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 850 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 851 | .pNext = nullptr, | 851 | .pNext = nullptr, |
| 852 | .flags = 0, | 852 | .flags = 0, |
| @@ -855,9 +855,8 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { | |||
| 855 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 855 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 856 | .queueFamilyIndexCount = 0, | 856 | .queueFamilyIndexCount = 0, |
| 857 | .pQueueFamilyIndices = nullptr, | 857 | .pQueueFamilyIndices = nullptr, |
| 858 | }); | 858 | }; |
| 859 | buffer_commits[level] = std::make_unique<MemoryCommit>( | 859 | buffers[level] = memory_allocator.CreateBuffer(temp_ci, MemoryUsage::DeviceLocal); |
| 860 | memory_allocator.Commit(buffers[level], MemoryUsage::DeviceLocal)); | ||
| 861 | return *buffers[level]; | 860 | return *buffers[level]; |
| 862 | } | 861 | } |
| 863 | 862 | ||
| @@ -867,8 +866,8 @@ void TextureCacheRuntime::BarrierFeedbackLoop() { | |||
| 867 | 866 | ||
| 868 | void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src, | 867 | void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src, |
| 869 | std::span<const VideoCommon::ImageCopy> copies) { | 868 | std::span<const VideoCommon::ImageCopy> copies) { |
| 870 | std::vector<VkBufferImageCopy> vk_in_copies(copies.size()); | 869 | boost::container::small_vector<VkBufferImageCopy, 16> vk_in_copies(copies.size()); |
| 871 | std::vector<VkBufferImageCopy> vk_out_copies(copies.size()); | 870 | boost::container::small_vector<VkBufferImageCopy, 16> vk_out_copies(copies.size()); |
| 872 | const VkImageAspectFlags src_aspect_mask = src.AspectMask(); | 871 | const VkImageAspectFlags src_aspect_mask = src.AspectMask(); |
| 873 | const VkImageAspectFlags dst_aspect_mask = dst.AspectMask(); | 872 | const VkImageAspectFlags dst_aspect_mask = dst.AspectMask(); |
| 874 | 873 | ||
| @@ -1157,7 +1156,7 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im | |||
| 1157 | 1156 | ||
| 1158 | void TextureCacheRuntime::CopyImage(Image& dst, Image& src, | 1157 | void TextureCacheRuntime::CopyImage(Image& dst, Image& src, |
| 1159 | std::span<const VideoCommon::ImageCopy> copies) { | 1158 | std::span<const VideoCommon::ImageCopy> copies) { |
| 1160 | std::vector<VkImageCopy> vk_copies(copies.size()); | 1159 | boost::container::small_vector<VkImageCopy, 16> vk_copies(copies.size()); |
| 1161 | const VkImageAspectFlags aspect_mask = dst.AspectMask(); | 1160 | const VkImageAspectFlags aspect_mask = dst.AspectMask(); |
| 1162 | ASSERT(aspect_mask == src.AspectMask()); | 1161 | ASSERT(aspect_mask == src.AspectMask()); |
| 1163 | 1162 | ||
| @@ -1266,8 +1265,8 @@ void TextureCacheRuntime::TickFrame() {} | |||
| 1266 | Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu_addr_, | 1265 | Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu_addr_, |
| 1267 | VAddr cpu_addr_) | 1266 | VAddr cpu_addr_) |
| 1268 | : VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime_.scheduler}, | 1267 | : VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime_.scheduler}, |
| 1269 | runtime{&runtime_}, original_image(MakeImage(runtime_.device, info)), | 1268 | runtime{&runtime_}, |
| 1270 | commit(runtime_.memory_allocator.Commit(original_image, MemoryUsage::DeviceLocal)), | 1269 | original_image(MakeImage(runtime_.device, runtime_.memory_allocator, info)), |
| 1271 | aspect_mask(ImageAspectMask(info.format)) { | 1270 | aspect_mask(ImageAspectMask(info.format)) { |
| 1272 | if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) { | 1271 | if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) { |
| 1273 | if (Settings::values.async_astc.GetValue()) { | 1272 | if (Settings::values.async_astc.GetValue()) { |
| @@ -1280,6 +1279,10 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu | |||
| 1280 | flags |= VideoCommon::ImageFlagBits::Converted; | 1279 | flags |= VideoCommon::ImageFlagBits::Converted; |
| 1281 | flags |= VideoCommon::ImageFlagBits::CostlyLoad; | 1280 | flags |= VideoCommon::ImageFlagBits::CostlyLoad; |
| 1282 | } | 1281 | } |
| 1282 | if (IsPixelFormatBCn(info.format) && !runtime->device.IsOptimalBcnSupported()) { | ||
| 1283 | flags |= VideoCommon::ImageFlagBits::Converted; | ||
| 1284 | flags |= VideoCommon::ImageFlagBits::CostlyLoad; | ||
| 1285 | } | ||
| 1283 | if (runtime->device.HasDebuggingToolAttached()) { | 1286 | if (runtime->device.HasDebuggingToolAttached()) { |
| 1284 | original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); | 1287 | original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); |
| 1285 | } | 1288 | } |
| @@ -1332,7 +1335,7 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset, | |||
| 1332 | ScaleDown(true); | 1335 | ScaleDown(true); |
| 1333 | } | 1336 | } |
| 1334 | scheduler->RequestOutsideRenderPassOperationContext(); | 1337 | scheduler->RequestOutsideRenderPassOperationContext(); |
| 1335 | std::vector vk_copies = TransformBufferImageCopies(copies, offset, aspect_mask); | 1338 | auto vk_copies = TransformBufferImageCopies(copies, offset, aspect_mask); |
| 1336 | const VkBuffer src_buffer = buffer; | 1339 | const VkBuffer src_buffer = buffer; |
| 1337 | const VkImage vk_image = *original_image; | 1340 | const VkImage vk_image = *original_image; |
| 1338 | const VkImageAspectFlags vk_aspect_mask = aspect_mask; | 1341 | const VkImageAspectFlags vk_aspect_mask = aspect_mask; |
| @@ -1367,8 +1370,9 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<VkDeviceS | |||
| 1367 | if (is_rescaled) { | 1370 | if (is_rescaled) { |
| 1368 | ScaleDown(); | 1371 | ScaleDown(); |
| 1369 | } | 1372 | } |
| 1370 | boost::container::small_vector<VkBuffer, 1> buffers_vector{}; | 1373 | boost::container::small_vector<VkBuffer, 8> buffers_vector{}; |
| 1371 | boost::container::small_vector<std::vector<VkBufferImageCopy>, 1> vk_copies; | 1374 | boost::container::small_vector<boost::container::small_vector<VkBufferImageCopy, 16>, 8> |
| 1375 | vk_copies; | ||
| 1372 | for (size_t index = 0; index < buffers_span.size(); index++) { | 1376 | for (size_t index = 0; index < buffers_span.size(); index++) { |
| 1373 | buffers_vector.emplace_back(buffers_span[index]); | 1377 | buffers_vector.emplace_back(buffers_span[index]); |
| 1374 | vk_copies.emplace_back( | 1378 | vk_copies.emplace_back( |
| @@ -1467,9 +1471,7 @@ bool Image::ScaleUp(bool ignore) { | |||
| 1467 | auto scaled_info = info; | 1471 | auto scaled_info = info; |
| 1468 | scaled_info.size.width = scaled_width; | 1472 | scaled_info.size.width = scaled_width; |
| 1469 | scaled_info.size.height = scaled_height; | 1473 | scaled_info.size.height = scaled_height; |
| 1470 | scaled_image = MakeImage(runtime->device, scaled_info); | 1474 | scaled_image = MakeImage(runtime->device, runtime->memory_allocator, scaled_info); |
| 1471 | auto& allocator = runtime->memory_allocator; | ||
| 1472 | scaled_commit = MemoryCommit(allocator.Commit(scaled_image, MemoryUsage::DeviceLocal)); | ||
| 1473 | ignore = false; | 1475 | ignore = false; |
| 1474 | } | 1476 | } |
| 1475 | current_image = *scaled_image; | 1477 | current_image = *scaled_image; |
| @@ -1858,7 +1860,7 @@ Framebuffer::~Framebuffer() = default; | |||
| 1858 | void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, | 1860 | void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, |
| 1859 | std::span<ImageView*, NUM_RT> color_buffers, | 1861 | std::span<ImageView*, NUM_RT> color_buffers, |
| 1860 | ImageView* depth_buffer, bool is_rescaled) { | 1862 | ImageView* depth_buffer, bool is_rescaled) { |
| 1861 | std::vector<VkImageView> attachments; | 1863 | boost::container::small_vector<VkImageView, NUM_RT + 1> attachments; |
| 1862 | RenderPassKey renderpass_key{}; | 1864 | RenderPassKey renderpass_key{}; |
| 1863 | s32 num_layers = 1; | 1865 | s32 num_layers = 1; |
| 1864 | 1866 | ||
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index f14525dcb..220943116 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h | |||
| @@ -116,7 +116,6 @@ public: | |||
| 116 | 116 | ||
| 117 | static constexpr size_t indexing_slots = 8 * sizeof(size_t); | 117 | static constexpr size_t indexing_slots = 8 * sizeof(size_t); |
| 118 | std::array<vk::Buffer, indexing_slots> buffers{}; | 118 | std::array<vk::Buffer, indexing_slots> buffers{}; |
| 119 | std::array<std::unique_ptr<MemoryCommit>, indexing_slots> buffer_commits{}; | ||
| 120 | }; | 119 | }; |
| 121 | 120 | ||
| 122 | class Image : public VideoCommon::ImageBase { | 121 | class Image : public VideoCommon::ImageBase { |
| @@ -180,12 +179,10 @@ private: | |||
| 180 | TextureCacheRuntime* runtime{}; | 179 | TextureCacheRuntime* runtime{}; |
| 181 | 180 | ||
| 182 | vk::Image original_image; | 181 | vk::Image original_image; |
| 183 | MemoryCommit commit; | ||
| 184 | std::vector<vk::ImageView> storage_image_views; | 182 | std::vector<vk::ImageView> storage_image_views; |
| 185 | VkImageAspectFlags aspect_mask = 0; | 183 | VkImageAspectFlags aspect_mask = 0; |
| 186 | bool initialized = false; | 184 | bool initialized = false; |
| 187 | vk::Image scaled_image{}; | 185 | vk::Image scaled_image{}; |
| 188 | MemoryCommit scaled_commit{}; | ||
| 189 | VkImage current_image{}; | 186 | VkImage current_image{}; |
| 190 | 187 | ||
| 191 | std::unique_ptr<Framebuffer> scale_framebuffer; | 188 | std::unique_ptr<Framebuffer> scale_framebuffer; |
diff --git a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp index a802d3c49..460d8d59d 100644 --- a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp +++ b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp | |||
| @@ -18,7 +18,7 @@ using namespace Common::Literals; | |||
| 18 | 18 | ||
| 19 | TurboMode::TurboMode(const vk::Instance& instance, const vk::InstanceDispatch& dld) | 19 | TurboMode::TurboMode(const vk::Instance& instance, const vk::InstanceDispatch& dld) |
| 20 | #ifndef ANDROID | 20 | #ifndef ANDROID |
| 21 | : m_device{CreateDevice(instance, dld, VK_NULL_HANDLE)}, m_allocator{m_device, false} | 21 | : m_device{CreateDevice(instance, dld, VK_NULL_HANDLE)}, m_allocator{m_device} |
| 22 | #endif | 22 | #endif |
| 23 | { | 23 | { |
| 24 | { | 24 | { |
| @@ -41,7 +41,7 @@ void TurboMode::Run(std::stop_token stop_token) { | |||
| 41 | auto& dld = m_device.GetLogical(); | 41 | auto& dld = m_device.GetLogical(); |
| 42 | 42 | ||
| 43 | // Allocate buffer. 2MiB should be sufficient. | 43 | // Allocate buffer. 2MiB should be sufficient. |
| 44 | auto buffer = dld.CreateBuffer(VkBufferCreateInfo{ | 44 | const VkBufferCreateInfo buffer_ci = { |
| 45 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 45 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 46 | .pNext = nullptr, | 46 | .pNext = nullptr, |
| 47 | .flags = 0, | 47 | .flags = 0, |
| @@ -50,10 +50,8 @@ void TurboMode::Run(std::stop_token stop_token) { | |||
| 50 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 50 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 51 | .queueFamilyIndexCount = 0, | 51 | .queueFamilyIndexCount = 0, |
| 52 | .pQueueFamilyIndices = nullptr, | 52 | .pQueueFamilyIndices = nullptr, |
| 53 | }); | 53 | }; |
| 54 | 54 | vk::Buffer buffer = m_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal); | |
| 55 | // Commit some device local memory for the buffer. | ||
| 56 | auto commit = m_allocator.Commit(buffer, MemoryUsage::DeviceLocal); | ||
| 57 | 55 | ||
| 58 | // Create the descriptor pool to contain our descriptor. | 56 | // Create the descriptor pool to contain our descriptor. |
| 59 | static constexpr VkDescriptorPoolSize pool_size{ | 57 | static constexpr VkDescriptorPoolSize pool_size{ |
diff --git a/src/video_core/shader_cache.cpp b/src/video_core/shader_cache.cpp index c5213875b..4db948b6d 100644 --- a/src/video_core/shader_cache.cpp +++ b/src/video_core/shader_cache.cpp | |||
| @@ -151,11 +151,9 @@ void ShaderCache::RemovePendingShaders() { | |||
| 151 | marked_for_removal.erase(std::unique(marked_for_removal.begin(), marked_for_removal.end()), | 151 | marked_for_removal.erase(std::unique(marked_for_removal.begin(), marked_for_removal.end()), |
| 152 | marked_for_removal.end()); | 152 | marked_for_removal.end()); |
| 153 | 153 | ||
| 154 | std::vector<ShaderInfo*> removed_shaders; | 154 | boost::container::small_vector<ShaderInfo*, 16> removed_shaders; |
| 155 | removed_shaders.reserve(marked_for_removal.size()); | ||
| 156 | 155 | ||
| 157 | std::scoped_lock lock{lookup_mutex}; | 156 | std::scoped_lock lock{lookup_mutex}; |
| 158 | |||
| 159 | for (Entry* const entry : marked_for_removal) { | 157 | for (Entry* const entry : marked_for_removal) { |
| 160 | removed_shaders.push_back(entry->data); | 158 | removed_shaders.push_back(entry->data); |
| 161 | 159 | ||
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp index cb51529e4..e16cd5e73 100644 --- a/src/video_core/surface.cpp +++ b/src/video_core/surface.cpp | |||
| @@ -269,6 +269,28 @@ bool IsPixelFormatASTC(PixelFormat format) { | |||
| 269 | } | 269 | } |
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | bool IsPixelFormatBCn(PixelFormat format) { | ||
| 273 | switch (format) { | ||
| 274 | case PixelFormat::BC1_RGBA_UNORM: | ||
| 275 | case PixelFormat::BC2_UNORM: | ||
| 276 | case PixelFormat::BC3_UNORM: | ||
| 277 | case PixelFormat::BC4_UNORM: | ||
| 278 | case PixelFormat::BC4_SNORM: | ||
| 279 | case PixelFormat::BC5_UNORM: | ||
| 280 | case PixelFormat::BC5_SNORM: | ||
| 281 | case PixelFormat::BC1_RGBA_SRGB: | ||
| 282 | case PixelFormat::BC2_SRGB: | ||
| 283 | case PixelFormat::BC3_SRGB: | ||
| 284 | case PixelFormat::BC7_UNORM: | ||
| 285 | case PixelFormat::BC6H_UFLOAT: | ||
| 286 | case PixelFormat::BC6H_SFLOAT: | ||
| 287 | case PixelFormat::BC7_SRGB: | ||
| 288 | return true; | ||
| 289 | default: | ||
| 290 | return false; | ||
| 291 | } | ||
| 292 | } | ||
| 293 | |||
| 272 | bool IsPixelFormatSRGB(PixelFormat format) { | 294 | bool IsPixelFormatSRGB(PixelFormat format) { |
| 273 | switch (format) { | 295 | switch (format) { |
| 274 | case PixelFormat::A8B8G8R8_SRGB: | 296 | case PixelFormat::A8B8G8R8_SRGB: |
diff --git a/src/video_core/surface.h b/src/video_core/surface.h index 0225d3287..9b9c4d9bc 100644 --- a/src/video_core/surface.h +++ b/src/video_core/surface.h | |||
| @@ -501,6 +501,8 @@ SurfaceType GetFormatType(PixelFormat pixel_format); | |||
| 501 | 501 | ||
| 502 | bool IsPixelFormatASTC(PixelFormat format); | 502 | bool IsPixelFormatASTC(PixelFormat format); |
| 503 | 503 | ||
| 504 | bool IsPixelFormatBCn(PixelFormat format); | ||
| 505 | |||
| 504 | bool IsPixelFormatSRGB(PixelFormat format); | 506 | bool IsPixelFormatSRGB(PixelFormat format); |
| 505 | 507 | ||
| 506 | bool IsPixelFormatInteger(PixelFormat format); | 508 | bool IsPixelFormatInteger(PixelFormat format); |
diff --git a/src/video_core/texture_cache/decode_bc.cpp b/src/video_core/texture_cache/decode_bc.cpp new file mode 100644 index 000000000..3e26474a3 --- /dev/null +++ b/src/video_core/texture_cache/decode_bc.cpp | |||
| @@ -0,0 +1,129 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | #include <array> | ||
| 6 | #include <span> | ||
| 7 | #include <bc_decoder.h> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "video_core/texture_cache/decode_bc.h" | ||
| 11 | |||
| 12 | namespace VideoCommon { | ||
| 13 | |||
| 14 | namespace { | ||
| 15 | constexpr u32 BLOCK_SIZE = 4; | ||
| 16 | |||
| 17 | using VideoCore::Surface::PixelFormat; | ||
| 18 | |||
| 19 | constexpr bool IsSigned(PixelFormat pixel_format) { | ||
| 20 | switch (pixel_format) { | ||
| 21 | case PixelFormat::BC4_SNORM: | ||
| 22 | case PixelFormat::BC4_UNORM: | ||
| 23 | case PixelFormat::BC5_SNORM: | ||
| 24 | case PixelFormat::BC5_UNORM: | ||
| 25 | case PixelFormat::BC6H_SFLOAT: | ||
| 26 | case PixelFormat::BC6H_UFLOAT: | ||
| 27 | return true; | ||
| 28 | default: | ||
| 29 | return false; | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | constexpr u32 BlockSize(PixelFormat pixel_format) { | ||
| 34 | switch (pixel_format) { | ||
| 35 | case PixelFormat::BC1_RGBA_SRGB: | ||
| 36 | case PixelFormat::BC1_RGBA_UNORM: | ||
| 37 | case PixelFormat::BC4_SNORM: | ||
| 38 | case PixelFormat::BC4_UNORM: | ||
| 39 | return 8; | ||
| 40 | default: | ||
| 41 | return 16; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | } // Anonymous namespace | ||
| 45 | |||
| 46 | u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format) { | ||
| 47 | switch (pixel_format) { | ||
| 48 | case PixelFormat::BC4_SNORM: | ||
| 49 | case PixelFormat::BC4_UNORM: | ||
| 50 | return 1; | ||
| 51 | case PixelFormat::BC5_SNORM: | ||
| 52 | case PixelFormat::BC5_UNORM: | ||
| 53 | return 2; | ||
| 54 | case PixelFormat::BC6H_SFLOAT: | ||
| 55 | case PixelFormat::BC6H_UFLOAT: | ||
| 56 | return 8; | ||
| 57 | default: | ||
| 58 | return 4; | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | template <auto decompress, PixelFormat pixel_format> | ||
| 63 | void DecompressBlocks(std::span<const u8> input, std::span<u8> output, Extent3D extent, | ||
| 64 | bool is_signed = false) { | ||
| 65 | const u32 out_bpp = ConvertedBytesPerBlock(pixel_format); | ||
| 66 | const u32 block_width = std::min(extent.width, BLOCK_SIZE); | ||
| 67 | const u32 block_height = std::min(extent.height, BLOCK_SIZE); | ||
| 68 | const u32 pitch = extent.width * out_bpp; | ||
| 69 | size_t input_offset = 0; | ||
| 70 | size_t output_offset = 0; | ||
| 71 | for (u32 slice = 0; slice < extent.depth; ++slice) { | ||
| 72 | for (u32 y = 0; y < extent.height; y += block_height) { | ||
| 73 | size_t row_offset = 0; | ||
| 74 | for (u32 x = 0; x < extent.width; | ||
| 75 | x += block_width, row_offset += block_width * out_bpp) { | ||
| 76 | const u8* src = input.data() + input_offset; | ||
| 77 | u8* const dst = output.data() + output_offset + row_offset; | ||
| 78 | if constexpr (IsSigned(pixel_format)) { | ||
| 79 | decompress(src, dst, x, y, extent.width, extent.height, is_signed); | ||
| 80 | } else { | ||
| 81 | decompress(src, dst, x, y, extent.width, extent.height); | ||
| 82 | } | ||
| 83 | input_offset += BlockSize(pixel_format); | ||
| 84 | } | ||
| 85 | output_offset += block_height * pitch; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent, | ||
| 91 | VideoCore::Surface::PixelFormat pixel_format) { | ||
| 92 | switch (pixel_format) { | ||
| 93 | case PixelFormat::BC1_RGBA_UNORM: | ||
| 94 | case PixelFormat::BC1_RGBA_SRGB: | ||
| 95 | DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, extent); | ||
| 96 | break; | ||
| 97 | case PixelFormat::BC2_UNORM: | ||
| 98 | case PixelFormat::BC2_SRGB: | ||
| 99 | DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, extent); | ||
| 100 | break; | ||
| 101 | case PixelFormat::BC3_UNORM: | ||
| 102 | case PixelFormat::BC3_SRGB: | ||
| 103 | DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, extent); | ||
| 104 | break; | ||
| 105 | case PixelFormat::BC4_SNORM: | ||
| 106 | case PixelFormat::BC4_UNORM: | ||
| 107 | DecompressBlocks<bcn::DecodeBc4, PixelFormat::BC4_UNORM>( | ||
| 108 | input, output, extent, pixel_format == PixelFormat::BC4_SNORM); | ||
| 109 | break; | ||
| 110 | case PixelFormat::BC5_SNORM: | ||
| 111 | case PixelFormat::BC5_UNORM: | ||
| 112 | DecompressBlocks<bcn::DecodeBc5, PixelFormat::BC5_UNORM>( | ||
| 113 | input, output, extent, pixel_format == PixelFormat::BC5_SNORM); | ||
| 114 | break; | ||
| 115 | case PixelFormat::BC6H_SFLOAT: | ||
| 116 | case PixelFormat::BC6H_UFLOAT: | ||
| 117 | DecompressBlocks<bcn::DecodeBc6, PixelFormat::BC6H_UFLOAT>( | ||
| 118 | input, output, extent, pixel_format == PixelFormat::BC6H_SFLOAT); | ||
| 119 | break; | ||
| 120 | case PixelFormat::BC7_SRGB: | ||
| 121 | case PixelFormat::BC7_UNORM: | ||
| 122 | DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, extent); | ||
| 123 | break; | ||
| 124 | default: | ||
| 125 | LOG_WARNING(HW_GPU, "Unimplemented BCn decompression {}", pixel_format); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | } // namespace VideoCommon | ||
diff --git a/src/video_core/texture_cache/decode_bc4.h b/src/video_core/texture_cache/decode_bc.h index ab2f735be..41d1ec0a3 100644 --- a/src/video_core/texture_cache/decode_bc4.h +++ b/src/video_core/texture_cache/decode_bc.h | |||
| @@ -6,10 +6,14 @@ | |||
| 6 | #include <span> | 6 | #include <span> |
| 7 | 7 | ||
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "video_core/surface.h" | ||
| 9 | #include "video_core/texture_cache/types.h" | 10 | #include "video_core/texture_cache/types.h" |
| 10 | 11 | ||
| 11 | namespace VideoCommon { | 12 | namespace VideoCommon { |
| 12 | 13 | ||
| 13 | void DecompressBC4(std::span<const u8> data, Extent3D extent, std::span<u8> output); | 14 | [[nodiscard]] u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format); |
| 15 | |||
| 16 | void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent, | ||
| 17 | VideoCore::Surface::PixelFormat pixel_format); | ||
| 14 | 18 | ||
| 15 | } // namespace VideoCommon | 19 | } // namespace VideoCommon |
diff --git a/src/video_core/texture_cache/decode_bc4.cpp b/src/video_core/texture_cache/decode_bc4.cpp deleted file mode 100644 index ef98afdca..000000000 --- a/src/video_core/texture_cache/decode_bc4.cpp +++ /dev/null | |||
| @@ -1,96 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | #include <array> | ||
| 6 | #include <span> | ||
| 7 | |||
| 8 | #include "common/assert.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "video_core/texture_cache/decode_bc4.h" | ||
| 11 | #include "video_core/texture_cache/types.h" | ||
| 12 | |||
| 13 | namespace VideoCommon { | ||
| 14 | |||
| 15 | // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_rgtc.txt | ||
| 16 | [[nodiscard]] constexpr u32 DecompressBlock(u64 bits, u32 x, u32 y) { | ||
| 17 | const u32 code_offset = 16 + 3 * (4 * y + x); | ||
| 18 | const u32 code = (bits >> code_offset) & 7; | ||
| 19 | const u32 red0 = (bits >> 0) & 0xff; | ||
| 20 | const u32 red1 = (bits >> 8) & 0xff; | ||
| 21 | if (red0 > red1) { | ||
| 22 | switch (code) { | ||
| 23 | case 0: | ||
| 24 | return red0; | ||
| 25 | case 1: | ||
| 26 | return red1; | ||
| 27 | case 2: | ||
| 28 | return (6 * red0 + 1 * red1) / 7; | ||
| 29 | case 3: | ||
| 30 | return (5 * red0 + 2 * red1) / 7; | ||
| 31 | case 4: | ||
| 32 | return (4 * red0 + 3 * red1) / 7; | ||
| 33 | case 5: | ||
| 34 | return (3 * red0 + 4 * red1) / 7; | ||
| 35 | case 6: | ||
| 36 | return (2 * red0 + 5 * red1) / 7; | ||
| 37 | case 7: | ||
| 38 | return (1 * red0 + 6 * red1) / 7; | ||
| 39 | } | ||
| 40 | } else { | ||
| 41 | switch (code) { | ||
| 42 | case 0: | ||
| 43 | return red0; | ||
| 44 | case 1: | ||
| 45 | return red1; | ||
| 46 | case 2: | ||
| 47 | return (4 * red0 + 1 * red1) / 5; | ||
| 48 | case 3: | ||
| 49 | return (3 * red0 + 2 * red1) / 5; | ||
| 50 | case 4: | ||
| 51 | return (2 * red0 + 3 * red1) / 5; | ||
| 52 | case 5: | ||
| 53 | return (1 * red0 + 4 * red1) / 5; | ||
| 54 | case 6: | ||
| 55 | return 0; | ||
| 56 | case 7: | ||
| 57 | return 0xff; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | return 0; | ||
| 61 | } | ||
| 62 | |||
| 63 | void DecompressBC4(std::span<const u8> input, Extent3D extent, std::span<u8> output) { | ||
| 64 | UNIMPLEMENTED_IF_MSG(extent.width % 4 != 0, "Unaligned width={}", extent.width); | ||
| 65 | UNIMPLEMENTED_IF_MSG(extent.height % 4 != 0, "Unaligned height={}", extent.height); | ||
| 66 | static constexpr u32 BLOCK_SIZE = 4; | ||
| 67 | size_t input_offset = 0; | ||
| 68 | for (u32 slice = 0; slice < extent.depth; ++slice) { | ||
| 69 | for (u32 block_y = 0; block_y < extent.height / 4; ++block_y) { | ||
| 70 | for (u32 block_x = 0; block_x < extent.width / 4; ++block_x) { | ||
| 71 | u64 bits; | ||
| 72 | std::memcpy(&bits, &input[input_offset], sizeof(bits)); | ||
| 73 | input_offset += sizeof(bits); | ||
| 74 | |||
| 75 | for (u32 y = 0; y < BLOCK_SIZE; ++y) { | ||
| 76 | for (u32 x = 0; x < BLOCK_SIZE; ++x) { | ||
| 77 | const u32 linear_z = slice; | ||
| 78 | const u32 linear_y = block_y * BLOCK_SIZE + y; | ||
| 79 | const u32 linear_x = block_x * BLOCK_SIZE + x; | ||
| 80 | const u32 offset_z = linear_z * extent.width * extent.height; | ||
| 81 | const u32 offset_y = linear_y * extent.width; | ||
| 82 | const u32 offset_x = linear_x; | ||
| 83 | const u32 output_offset = (offset_z + offset_y + offset_x) * 4ULL; | ||
| 84 | const u32 color = DecompressBlock(bits, x, y); | ||
| 85 | output[output_offset + 0] = static_cast<u8>(color); | ||
| 86 | output[output_offset + 1] = 0; | ||
| 87 | output[output_offset + 2] = 0; | ||
| 88 | output[output_offset + 3] = 0xff; | ||
| 89 | } | ||
| 90 | } | ||
| 91 | } | ||
| 92 | } | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | } // namespace VideoCommon | ||
diff --git a/src/video_core/texture_cache/image_base.h b/src/video_core/texture_cache/image_base.h index 1b8a17ee8..55d49d017 100644 --- a/src/video_core/texture_cache/image_base.h +++ b/src/video_core/texture_cache/image_base.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <array> | 6 | #include <array> |
| 7 | #include <optional> | 7 | #include <optional> |
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | #include <boost/container/small_vector.hpp> | ||
| 9 | 10 | ||
| 10 | #include "common/common_funcs.h" | 11 | #include "common/common_funcs.h" |
| 11 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| @@ -108,8 +109,8 @@ struct ImageBase { | |||
| 108 | std::vector<ImageViewInfo> image_view_infos; | 109 | std::vector<ImageViewInfo> image_view_infos; |
| 109 | std::vector<ImageViewId> image_view_ids; | 110 | std::vector<ImageViewId> image_view_ids; |
| 110 | 111 | ||
| 111 | std::vector<u32> slice_offsets; | 112 | boost::container::small_vector<u32, 16> slice_offsets; |
| 112 | std::vector<SubresourceBase> slice_subresources; | 113 | boost::container::small_vector<SubresourceBase, 16> slice_subresources; |
| 113 | 114 | ||
| 114 | std::vector<AliasedImage> aliased_images; | 115 | std::vector<AliasedImage> aliased_images; |
| 115 | std::vector<ImageId> overlapping_images; | 116 | std::vector<ImageId> overlapping_images; |
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 4027d860b..8190f3ba1 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -186,6 +186,10 @@ void TextureCache<P>::FillComputeImageViews(std::span<ImageViewInOut> views) { | |||
| 186 | 186 | ||
| 187 | template <class P> | 187 | template <class P> |
| 188 | void TextureCache<P>::CheckFeedbackLoop(std::span<const ImageViewInOut> views) { | 188 | void TextureCache<P>::CheckFeedbackLoop(std::span<const ImageViewInOut> views) { |
| 189 | if (!Settings::values.barrier_feedback_loops.GetValue()) { | ||
| 190 | return; | ||
| 191 | } | ||
| 192 | |||
| 189 | const bool requires_barrier = [&] { | 193 | const bool requires_barrier = [&] { |
| 190 | for (const auto& view : views) { | 194 | for (const auto& view : views) { |
| 191 | if (!view.id) { | 195 | if (!view.id) { |
| @@ -300,7 +304,7 @@ void TextureCache<P>::SynchronizeComputeDescriptors() { | |||
| 300 | } | 304 | } |
| 301 | 305 | ||
| 302 | template <class P> | 306 | template <class P> |
| 303 | bool TextureCache<P>::RescaleRenderTargets(bool is_clear) { | 307 | bool TextureCache<P>::RescaleRenderTargets() { |
| 304 | auto& flags = maxwell3d->dirty.flags; | 308 | auto& flags = maxwell3d->dirty.flags; |
| 305 | u32 scale_rating = 0; | 309 | u32 scale_rating = 0; |
| 306 | bool rescaled = false; | 310 | bool rescaled = false; |
| @@ -338,13 +342,13 @@ bool TextureCache<P>::RescaleRenderTargets(bool is_clear) { | |||
| 338 | ImageViewId& color_buffer_id = render_targets.color_buffer_ids[index]; | 342 | ImageViewId& color_buffer_id = render_targets.color_buffer_ids[index]; |
| 339 | if (flags[Dirty::ColorBuffer0 + index] || force) { | 343 | if (flags[Dirty::ColorBuffer0 + index] || force) { |
| 340 | flags[Dirty::ColorBuffer0 + index] = false; | 344 | flags[Dirty::ColorBuffer0 + index] = false; |
| 341 | BindRenderTarget(&color_buffer_id, FindColorBuffer(index, is_clear)); | 345 | BindRenderTarget(&color_buffer_id, FindColorBuffer(index)); |
| 342 | } | 346 | } |
| 343 | check_rescale(color_buffer_id, tmp_color_images[index]); | 347 | check_rescale(color_buffer_id, tmp_color_images[index]); |
| 344 | } | 348 | } |
| 345 | if (flags[Dirty::ZetaBuffer] || force) { | 349 | if (flags[Dirty::ZetaBuffer] || force) { |
| 346 | flags[Dirty::ZetaBuffer] = false; | 350 | flags[Dirty::ZetaBuffer] = false; |
| 347 | BindRenderTarget(&render_targets.depth_buffer_id, FindDepthBuffer(is_clear)); | 351 | BindRenderTarget(&render_targets.depth_buffer_id, FindDepthBuffer()); |
| 348 | } | 352 | } |
| 349 | check_rescale(render_targets.depth_buffer_id, tmp_depth_image); | 353 | check_rescale(render_targets.depth_buffer_id, tmp_depth_image); |
| 350 | 354 | ||
| @@ -409,7 +413,7 @@ void TextureCache<P>::UpdateRenderTargets(bool is_clear) { | |||
| 409 | return; | 413 | return; |
| 410 | } | 414 | } |
| 411 | 415 | ||
| 412 | const bool rescaled = RescaleRenderTargets(is_clear); | 416 | const bool rescaled = RescaleRenderTargets(); |
| 413 | if (is_rescaling != rescaled) { | 417 | if (is_rescaling != rescaled) { |
| 414 | flags[Dirty::RescaleViewports] = true; | 418 | flags[Dirty::RescaleViewports] = true; |
| 415 | flags[Dirty::RescaleScissors] = true; | 419 | flags[Dirty::RescaleScissors] = true; |
| @@ -522,7 +526,7 @@ void TextureCache<P>::WriteMemory(VAddr cpu_addr, size_t size) { | |||
| 522 | 526 | ||
| 523 | template <class P> | 527 | template <class P> |
| 524 | void TextureCache<P>::DownloadMemory(VAddr cpu_addr, size_t size) { | 528 | void TextureCache<P>::DownloadMemory(VAddr cpu_addr, size_t size) { |
| 525 | std::vector<ImageId> images; | 529 | boost::container::small_vector<ImageId, 16> images; |
| 526 | ForEachImageInRegion(cpu_addr, size, [&images](ImageId image_id, ImageBase& image) { | 530 | ForEachImageInRegion(cpu_addr, size, [&images](ImageId image_id, ImageBase& image) { |
| 527 | if (!image.IsSafeDownload()) { | 531 | if (!image.IsSafeDownload()) { |
| 528 | return; | 532 | return; |
| @@ -575,7 +579,7 @@ std::optional<VideoCore::RasterizerDownloadArea> TextureCache<P>::GetFlushArea(V | |||
| 575 | 579 | ||
| 576 | template <class P> | 580 | template <class P> |
| 577 | void TextureCache<P>::UnmapMemory(VAddr cpu_addr, size_t size) { | 581 | void TextureCache<P>::UnmapMemory(VAddr cpu_addr, size_t size) { |
| 578 | std::vector<ImageId> deleted_images; | 582 | boost::container::small_vector<ImageId, 16> deleted_images; |
| 579 | ForEachImageInRegion(cpu_addr, size, [&](ImageId id, Image&) { deleted_images.push_back(id); }); | 583 | ForEachImageInRegion(cpu_addr, size, [&](ImageId id, Image&) { deleted_images.push_back(id); }); |
| 580 | for (const ImageId id : deleted_images) { | 584 | for (const ImageId id : deleted_images) { |
| 581 | Image& image = slot_images[id]; | 585 | Image& image = slot_images[id]; |
| @@ -589,19 +593,11 @@ void TextureCache<P>::UnmapMemory(VAddr cpu_addr, size_t size) { | |||
| 589 | 593 | ||
| 590 | template <class P> | 594 | template <class P> |
| 591 | void TextureCache<P>::UnmapGPUMemory(size_t as_id, GPUVAddr gpu_addr, size_t size) { | 595 | void TextureCache<P>::UnmapGPUMemory(size_t as_id, GPUVAddr gpu_addr, size_t size) { |
| 592 | std::vector<ImageId> deleted_images; | 596 | boost::container::small_vector<ImageId, 16> deleted_images; |
| 593 | ForEachImageInRegionGPU(as_id, gpu_addr, size, | 597 | ForEachImageInRegionGPU(as_id, gpu_addr, size, |
| 594 | [&](ImageId id, Image&) { deleted_images.push_back(id); }); | 598 | [&](ImageId id, Image&) { deleted_images.push_back(id); }); |
| 595 | for (const ImageId id : deleted_images) { | 599 | for (const ImageId id : deleted_images) { |
| 596 | Image& image = slot_images[id]; | 600 | Image& image = slot_images[id]; |
| 597 | if (True(image.flags & ImageFlagBits::CpuModified)) { | ||
| 598 | return; | ||
| 599 | } | ||
| 600 | image.flags |= ImageFlagBits::CpuModified; | ||
| 601 | if (True(image.flags & ImageFlagBits::Tracked)) { | ||
| 602 | UntrackImage(image, id); | ||
| 603 | } | ||
| 604 | /* | ||
| 605 | if (True(image.flags & ImageFlagBits::Remapped)) { | 601 | if (True(image.flags & ImageFlagBits::Remapped)) { |
| 606 | continue; | 602 | continue; |
| 607 | } | 603 | } |
| @@ -609,7 +605,6 @@ void TextureCache<P>::UnmapGPUMemory(size_t as_id, GPUVAddr gpu_addr, size_t siz | |||
| 609 | if (True(image.flags & ImageFlagBits::Tracked)) { | 605 | if (True(image.flags & ImageFlagBits::Tracked)) { |
| 610 | UntrackImage(image, id); | 606 | UntrackImage(image, id); |
| 611 | } | 607 | } |
| 612 | */ | ||
| 613 | } | 608 | } |
| 614 | } | 609 | } |
| 615 | 610 | ||
| @@ -875,6 +870,10 @@ ImageId TextureCache<P>::DmaImageId(const Tegra::DMA::ImageOperand& operand, boo | |||
| 875 | return NULL_IMAGE_ID; | 870 | return NULL_IMAGE_ID; |
| 876 | } | 871 | } |
| 877 | auto& image = slot_images[image_id]; | 872 | auto& image = slot_images[image_id]; |
| 873 | if (image.info.type == ImageType::e3D) { | ||
| 874 | // Don't accelerate 3D images. | ||
| 875 | return NULL_IMAGE_ID; | ||
| 876 | } | ||
| 878 | if (!is_upload && !image.info.dma_downloaded) { | 877 | if (!is_upload && !image.info.dma_downloaded) { |
| 879 | // Force a full sync. | 878 | // Force a full sync. |
| 880 | image.info.dma_downloaded = true; | 879 | image.info.dma_downloaded = true; |
| @@ -1097,7 +1096,7 @@ ImageId TextureCache<P>::FindImage(const ImageInfo& info, GPUVAddr gpu_addr, | |||
| 1097 | const bool native_bgr = runtime.HasNativeBgr(); | 1096 | const bool native_bgr = runtime.HasNativeBgr(); |
| 1098 | const bool flexible_formats = True(options & RelaxedOptions::Format); | 1097 | const bool flexible_formats = True(options & RelaxedOptions::Format); |
| 1099 | ImageId image_id{}; | 1098 | ImageId image_id{}; |
| 1100 | boost::container::small_vector<ImageId, 1> image_ids; | 1099 | boost::container::small_vector<ImageId, 8> image_ids; |
| 1101 | const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) { | 1100 | const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) { |
| 1102 | if (True(existing_image.flags & ImageFlagBits::Remapped)) { | 1101 | if (True(existing_image.flags & ImageFlagBits::Remapped)) { |
| 1103 | return false; | 1102 | return false; |
| @@ -1618,7 +1617,7 @@ ImageId TextureCache<P>::FindDMAImage(const ImageInfo& info, GPUVAddr gpu_addr) | |||
| 1618 | } | 1617 | } |
| 1619 | } | 1618 | } |
| 1620 | ImageId image_id{}; | 1619 | ImageId image_id{}; |
| 1621 | boost::container::small_vector<ImageId, 1> image_ids; | 1620 | boost::container::small_vector<ImageId, 8> image_ids; |
| 1622 | const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) { | 1621 | const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) { |
| 1623 | if (True(existing_image.flags & ImageFlagBits::Remapped)) { | 1622 | if (True(existing_image.flags & ImageFlagBits::Remapped)) { |
| 1624 | return false; | 1623 | return false; |
| @@ -1678,7 +1677,7 @@ SamplerId TextureCache<P>::FindSampler(const TSCEntry& config) { | |||
| 1678 | } | 1677 | } |
| 1679 | 1678 | ||
| 1680 | template <class P> | 1679 | template <class P> |
| 1681 | ImageViewId TextureCache<P>::FindColorBuffer(size_t index, bool is_clear) { | 1680 | ImageViewId TextureCache<P>::FindColorBuffer(size_t index) { |
| 1682 | const auto& regs = maxwell3d->regs; | 1681 | const auto& regs = maxwell3d->regs; |
| 1683 | if (index >= regs.rt_control.count) { | 1682 | if (index >= regs.rt_control.count) { |
| 1684 | return ImageViewId{}; | 1683 | return ImageViewId{}; |
| @@ -1692,11 +1691,11 @@ ImageViewId TextureCache<P>::FindColorBuffer(size_t index, bool is_clear) { | |||
| 1692 | return ImageViewId{}; | 1691 | return ImageViewId{}; |
| 1693 | } | 1692 | } |
| 1694 | const ImageInfo info(regs.rt[index], regs.anti_alias_samples_mode); | 1693 | const ImageInfo info(regs.rt[index], regs.anti_alias_samples_mode); |
| 1695 | return FindRenderTargetView(info, gpu_addr, is_clear); | 1694 | return FindRenderTargetView(info, gpu_addr); |
| 1696 | } | 1695 | } |
| 1697 | 1696 | ||
| 1698 | template <class P> | 1697 | template <class P> |
| 1699 | ImageViewId TextureCache<P>::FindDepthBuffer(bool is_clear) { | 1698 | ImageViewId TextureCache<P>::FindDepthBuffer() { |
| 1700 | const auto& regs = maxwell3d->regs; | 1699 | const auto& regs = maxwell3d->regs; |
| 1701 | if (!regs.zeta_enable) { | 1700 | if (!regs.zeta_enable) { |
| 1702 | return ImageViewId{}; | 1701 | return ImageViewId{}; |
| @@ -1706,18 +1705,16 @@ ImageViewId TextureCache<P>::FindDepthBuffer(bool is_clear) { | |||
| 1706 | return ImageViewId{}; | 1705 | return ImageViewId{}; |
| 1707 | } | 1706 | } |
| 1708 | const ImageInfo info(regs.zeta, regs.zeta_size, regs.anti_alias_samples_mode); | 1707 | const ImageInfo info(regs.zeta, regs.zeta_size, regs.anti_alias_samples_mode); |
| 1709 | return FindRenderTargetView(info, gpu_addr, is_clear); | 1708 | return FindRenderTargetView(info, gpu_addr); |
| 1710 | } | 1709 | } |
| 1711 | 1710 | ||
| 1712 | template <class P> | 1711 | template <class P> |
| 1713 | ImageViewId TextureCache<P>::FindRenderTargetView(const ImageInfo& info, GPUVAddr gpu_addr, | 1712 | ImageViewId TextureCache<P>::FindRenderTargetView(const ImageInfo& info, GPUVAddr gpu_addr) { |
| 1714 | bool is_clear) { | ||
| 1715 | const auto options = is_clear ? RelaxedOptions::Samples : RelaxedOptions{}; | ||
| 1716 | ImageId image_id{}; | 1713 | ImageId image_id{}; |
| 1717 | bool delete_state = has_deleted_images; | 1714 | bool delete_state = has_deleted_images; |
| 1718 | do { | 1715 | do { |
| 1719 | has_deleted_images = false; | 1716 | has_deleted_images = false; |
| 1720 | image_id = FindOrInsertImage(info, gpu_addr, options); | 1717 | image_id = FindOrInsertImage(info, gpu_addr); |
| 1721 | delete_state |= has_deleted_images; | 1718 | delete_state |= has_deleted_images; |
| 1722 | } while (has_deleted_images); | 1719 | } while (has_deleted_images); |
| 1723 | has_deleted_images = delete_state; | 1720 | has_deleted_images = delete_state; |
| @@ -1940,7 +1937,7 @@ void TextureCache<P>::RegisterImage(ImageId image_id) { | |||
| 1940 | image.map_view_id = map_id; | 1937 | image.map_view_id = map_id; |
| 1941 | return; | 1938 | return; |
| 1942 | } | 1939 | } |
| 1943 | std::vector<ImageViewId> sparse_maps{}; | 1940 | boost::container::small_vector<ImageViewId, 16> sparse_maps; |
| 1944 | ForEachSparseSegment( | 1941 | ForEachSparseSegment( |
| 1945 | image, [this, image_id, &sparse_maps](GPUVAddr gpu_addr, VAddr cpu_addr, size_t size) { | 1942 | image, [this, image_id, &sparse_maps](GPUVAddr gpu_addr, VAddr cpu_addr, size_t size) { |
| 1946 | auto map_id = slot_map_views.insert(gpu_addr, cpu_addr, size, image_id); | 1943 | auto map_id = slot_map_views.insert(gpu_addr, cpu_addr, size, image_id); |
| @@ -2215,7 +2212,7 @@ void TextureCache<P>::MarkModification(ImageBase& image) noexcept { | |||
| 2215 | 2212 | ||
| 2216 | template <class P> | 2213 | template <class P> |
| 2217 | void TextureCache<P>::SynchronizeAliases(ImageId image_id) { | 2214 | void TextureCache<P>::SynchronizeAliases(ImageId image_id) { |
| 2218 | boost::container::small_vector<const AliasedImage*, 1> aliased_images; | 2215 | boost::container::small_vector<const AliasedImage*, 8> aliased_images; |
| 2219 | Image& image = slot_images[image_id]; | 2216 | Image& image = slot_images[image_id]; |
| 2220 | bool any_rescaled = True(image.flags & ImageFlagBits::Rescaled); | 2217 | bool any_rescaled = True(image.flags & ImageFlagBits::Rescaled); |
| 2221 | bool any_modified = True(image.flags & ImageFlagBits::GpuModified); | 2218 | bool any_modified = True(image.flags & ImageFlagBits::GpuModified); |
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index d96ddea9d..e9ec91265 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h | |||
| @@ -56,7 +56,7 @@ struct ImageViewInOut { | |||
| 56 | struct AsyncDecodeContext { | 56 | struct AsyncDecodeContext { |
| 57 | ImageId image_id; | 57 | ImageId image_id; |
| 58 | Common::ScratchBuffer<u8> decoded_data; | 58 | Common::ScratchBuffer<u8> decoded_data; |
| 59 | std::vector<BufferImageCopy> copies; | 59 | boost::container::small_vector<BufferImageCopy, 16> copies; |
| 60 | std::mutex mutex; | 60 | std::mutex mutex; |
| 61 | std::atomic_bool complete; | 61 | std::atomic_bool complete; |
| 62 | }; | 62 | }; |
| @@ -178,9 +178,8 @@ public: | |||
| 178 | void SynchronizeComputeDescriptors(); | 178 | void SynchronizeComputeDescriptors(); |
| 179 | 179 | ||
| 180 | /// Updates the Render Targets if they can be rescaled | 180 | /// Updates the Render Targets if they can be rescaled |
| 181 | /// @param is_clear True when the render targets are being used for clears | ||
| 182 | /// @retval True if the Render Targets have been rescaled. | 181 | /// @retval True if the Render Targets have been rescaled. |
| 183 | bool RescaleRenderTargets(bool is_clear); | 182 | bool RescaleRenderTargets(); |
| 184 | 183 | ||
| 185 | /// Update bound render targets and upload memory if necessary | 184 | /// Update bound render targets and upload memory if necessary |
| 186 | /// @param is_clear True when the render targets are being used for clears | 185 | /// @param is_clear True when the render targets are being used for clears |
| @@ -336,14 +335,13 @@ private: | |||
| 336 | [[nodiscard]] SamplerId FindSampler(const TSCEntry& config); | 335 | [[nodiscard]] SamplerId FindSampler(const TSCEntry& config); |
| 337 | 336 | ||
| 338 | /// Find or create an image view for the given color buffer index | 337 | /// Find or create an image view for the given color buffer index |
| 339 | [[nodiscard]] ImageViewId FindColorBuffer(size_t index, bool is_clear); | 338 | [[nodiscard]] ImageViewId FindColorBuffer(size_t index); |
| 340 | 339 | ||
| 341 | /// Find or create an image view for the depth buffer | 340 | /// Find or create an image view for the depth buffer |
| 342 | [[nodiscard]] ImageViewId FindDepthBuffer(bool is_clear); | 341 | [[nodiscard]] ImageViewId FindDepthBuffer(); |
| 343 | 342 | ||
| 344 | /// Find or create a view for a render target with the given image parameters | 343 | /// Find or create a view for a render target with the given image parameters |
| 345 | [[nodiscard]] ImageViewId FindRenderTargetView(const ImageInfo& info, GPUVAddr gpu_addr, | 344 | [[nodiscard]] ImageViewId FindRenderTargetView(const ImageInfo& info, GPUVAddr gpu_addr); |
| 346 | bool is_clear); | ||
| 347 | 345 | ||
| 348 | /// Iterates over all the images in a region calling func | 346 | /// Iterates over all the images in a region calling func |
| 349 | template <typename Func> | 347 | template <typename Func> |
| @@ -431,7 +429,7 @@ private: | |||
| 431 | 429 | ||
| 432 | std::unordered_map<u64, std::vector<ImageMapId>, Common::IdentityHash<u64>> page_table; | 430 | std::unordered_map<u64, std::vector<ImageMapId>, Common::IdentityHash<u64>> page_table; |
| 433 | std::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>> sparse_page_table; | 431 | std::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>> sparse_page_table; |
| 434 | std::unordered_map<ImageId, std::vector<ImageViewId>> sparse_views; | 432 | std::unordered_map<ImageId, boost::container::small_vector<ImageViewId, 16>> sparse_views; |
| 435 | 433 | ||
| 436 | VAddr virtual_invalid_space{}; | 434 | VAddr virtual_invalid_space{}; |
| 437 | 435 | ||
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index 95a5b47d8..9a618a57a 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp | |||
| @@ -24,7 +24,7 @@ | |||
| 24 | #include "video_core/engines/maxwell_3d.h" | 24 | #include "video_core/engines/maxwell_3d.h" |
| 25 | #include "video_core/memory_manager.h" | 25 | #include "video_core/memory_manager.h" |
| 26 | #include "video_core/surface.h" | 26 | #include "video_core/surface.h" |
| 27 | #include "video_core/texture_cache/decode_bc4.h" | 27 | #include "video_core/texture_cache/decode_bc.h" |
| 28 | #include "video_core/texture_cache/format_lookup_table.h" | 28 | #include "video_core/texture_cache/format_lookup_table.h" |
| 29 | #include "video_core/texture_cache/formatter.h" | 29 | #include "video_core/texture_cache/formatter.h" |
| 30 | #include "video_core/texture_cache/samples_helper.h" | 30 | #include "video_core/texture_cache/samples_helper.h" |
| @@ -61,8 +61,6 @@ using VideoCore::Surface::PixelFormatFromDepthFormat; | |||
| 61 | using VideoCore::Surface::PixelFormatFromRenderTargetFormat; | 61 | using VideoCore::Surface::PixelFormatFromRenderTargetFormat; |
| 62 | using VideoCore::Surface::SurfaceType; | 62 | using VideoCore::Surface::SurfaceType; |
| 63 | 63 | ||
| 64 | constexpr u32 CONVERTED_BYTES_PER_BLOCK = BytesPerBlock(PixelFormat::A8B8G8R8_UNORM); | ||
| 65 | |||
| 66 | struct LevelInfo { | 64 | struct LevelInfo { |
| 67 | Extent3D size; | 65 | Extent3D size; |
| 68 | Extent3D block; | 66 | Extent3D block; |
| @@ -329,13 +327,13 @@ template <u32 GOB_EXTENT> | |||
| 329 | 327 | ||
| 330 | [[nodiscard]] std::optional<SubresourceExtent> ResolveOverlapRightAddress3D( | 328 | [[nodiscard]] std::optional<SubresourceExtent> ResolveOverlapRightAddress3D( |
| 331 | const ImageInfo& new_info, GPUVAddr gpu_addr, const ImageBase& overlap, bool strict_size) { | 329 | const ImageInfo& new_info, GPUVAddr gpu_addr, const ImageBase& overlap, bool strict_size) { |
| 332 | const std::vector<u32> slice_offsets = CalculateSliceOffsets(new_info); | 330 | const auto slice_offsets = CalculateSliceOffsets(new_info); |
| 333 | const u32 diff = static_cast<u32>(overlap.gpu_addr - gpu_addr); | 331 | const u32 diff = static_cast<u32>(overlap.gpu_addr - gpu_addr); |
| 334 | const auto it = std::ranges::find(slice_offsets, diff); | 332 | const auto it = std::ranges::find(slice_offsets, diff); |
| 335 | if (it == slice_offsets.end()) { | 333 | if (it == slice_offsets.end()) { |
| 336 | return std::nullopt; | 334 | return std::nullopt; |
| 337 | } | 335 | } |
| 338 | const std::vector subresources = CalculateSliceSubresources(new_info); | 336 | const auto subresources = CalculateSliceSubresources(new_info); |
| 339 | const SubresourceBase base = subresources[std::distance(slice_offsets.begin(), it)]; | 337 | const SubresourceBase base = subresources[std::distance(slice_offsets.begin(), it)]; |
| 340 | const ImageInfo& info = overlap.info; | 338 | const ImageInfo& info = overlap.info; |
| 341 | if (!IsBlockLinearSizeCompatible(new_info, info, base.level, 0, strict_size)) { | 339 | if (!IsBlockLinearSizeCompatible(new_info, info, base.level, 0, strict_size)) { |
| @@ -612,7 +610,8 @@ u32 CalculateConvertedSizeBytes(const ImageInfo& info) noexcept { | |||
| 612 | } | 610 | } |
| 613 | return output_size; | 611 | return output_size; |
| 614 | } | 612 | } |
| 615 | return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers * CONVERTED_BYTES_PER_BLOCK; | 613 | return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers * |
| 614 | ConvertedBytesPerBlock(info.format); | ||
| 616 | } | 615 | } |
| 617 | 616 | ||
| 618 | u32 CalculateLayerStride(const ImageInfo& info) noexcept { | 617 | u32 CalculateLayerStride(const ImageInfo& info) noexcept { |
| @@ -655,9 +654,9 @@ LevelArray CalculateMipLevelSizes(const ImageInfo& info) noexcept { | |||
| 655 | return sizes; | 654 | return sizes; |
| 656 | } | 655 | } |
| 657 | 656 | ||
| 658 | std::vector<u32> CalculateSliceOffsets(const ImageInfo& info) { | 657 | boost::container::small_vector<u32, 16> CalculateSliceOffsets(const ImageInfo& info) { |
| 659 | ASSERT(info.type == ImageType::e3D); | 658 | ASSERT(info.type == ImageType::e3D); |
| 660 | std::vector<u32> offsets; | 659 | boost::container::small_vector<u32, 16> offsets; |
| 661 | offsets.reserve(NumSlices(info)); | 660 | offsets.reserve(NumSlices(info)); |
| 662 | 661 | ||
| 663 | const LevelInfo level_info = MakeLevelInfo(info); | 662 | const LevelInfo level_info = MakeLevelInfo(info); |
| @@ -679,9 +678,10 @@ std::vector<u32> CalculateSliceOffsets(const ImageInfo& info) { | |||
| 679 | return offsets; | 678 | return offsets; |
| 680 | } | 679 | } |
| 681 | 680 | ||
| 682 | std::vector<SubresourceBase> CalculateSliceSubresources(const ImageInfo& info) { | 681 | boost::container::small_vector<SubresourceBase, 16> CalculateSliceSubresources( |
| 682 | const ImageInfo& info) { | ||
| 683 | ASSERT(info.type == ImageType::e3D); | 683 | ASSERT(info.type == ImageType::e3D); |
| 684 | std::vector<SubresourceBase> subresources; | 684 | boost::container::small_vector<SubresourceBase, 16> subresources; |
| 685 | subresources.reserve(NumSlices(info)); | 685 | subresources.reserve(NumSlices(info)); |
| 686 | for (s32 level = 0; level < info.resources.levels; ++level) { | 686 | for (s32 level = 0; level < info.resources.levels; ++level) { |
| 687 | const s32 depth = AdjustMipSize(info.size.depth, level); | 687 | const s32 depth = AdjustMipSize(info.size.depth, level); |
| @@ -723,8 +723,10 @@ ImageViewType RenderTargetImageViewType(const ImageInfo& info) noexcept { | |||
| 723 | } | 723 | } |
| 724 | } | 724 | } |
| 725 | 725 | ||
| 726 | std::vector<ImageCopy> MakeShrinkImageCopies(const ImageInfo& dst, const ImageInfo& src, | 726 | boost::container::small_vector<ImageCopy, 16> MakeShrinkImageCopies(const ImageInfo& dst, |
| 727 | SubresourceBase base, u32 up_scale, u32 down_shift) { | 727 | const ImageInfo& src, |
| 728 | SubresourceBase base, | ||
| 729 | u32 up_scale, u32 down_shift) { | ||
| 728 | ASSERT(dst.resources.levels >= src.resources.levels); | 730 | ASSERT(dst.resources.levels >= src.resources.levels); |
| 729 | 731 | ||
| 730 | const bool is_dst_3d = dst.type == ImageType::e3D; | 732 | const bool is_dst_3d = dst.type == ImageType::e3D; |
| @@ -733,7 +735,7 @@ std::vector<ImageCopy> MakeShrinkImageCopies(const ImageInfo& dst, const ImageIn | |||
| 733 | ASSERT(src.resources.levels == 1); | 735 | ASSERT(src.resources.levels == 1); |
| 734 | } | 736 | } |
| 735 | const bool both_2d{src.type == ImageType::e2D && dst.type == ImageType::e2D}; | 737 | const bool both_2d{src.type == ImageType::e2D && dst.type == ImageType::e2D}; |
| 736 | std::vector<ImageCopy> copies; | 738 | boost::container::small_vector<ImageCopy, 16> copies; |
| 737 | copies.reserve(src.resources.levels); | 739 | copies.reserve(src.resources.levels); |
| 738 | for (s32 level = 0; level < src.resources.levels; ++level) { | 740 | for (s32 level = 0; level < src.resources.levels; ++level) { |
| 739 | ImageCopy& copy = copies.emplace_back(); | 741 | ImageCopy& copy = copies.emplace_back(); |
| @@ -770,9 +772,10 @@ std::vector<ImageCopy> MakeShrinkImageCopies(const ImageInfo& dst, const ImageIn | |||
| 770 | return copies; | 772 | return copies; |
| 771 | } | 773 | } |
| 772 | 774 | ||
| 773 | std::vector<ImageCopy> MakeReinterpretImageCopies(const ImageInfo& src, u32 up_scale, | 775 | boost::container::small_vector<ImageCopy, 16> MakeReinterpretImageCopies(const ImageInfo& src, |
| 774 | u32 down_shift) { | 776 | u32 up_scale, |
| 775 | std::vector<ImageCopy> copies; | 777 | u32 down_shift) { |
| 778 | boost::container::small_vector<ImageCopy, 16> copies; | ||
| 776 | copies.reserve(src.resources.levels); | 779 | copies.reserve(src.resources.levels); |
| 777 | const bool is_3d = src.type == ImageType::e3D; | 780 | const bool is_3d = src.type == ImageType::e3D; |
| 778 | for (s32 level = 0; level < src.resources.levels; ++level) { | 781 | for (s32 level = 0; level < src.resources.levels; ++level) { |
| @@ -824,9 +827,11 @@ bool IsValidEntry(const Tegra::MemoryManager& gpu_memory, const TICEntry& config | |||
| 824 | return gpu_memory.GpuToCpuAddress(address, guest_size_bytes).has_value(); | 827 | return gpu_memory.GpuToCpuAddress(address, guest_size_bytes).has_value(); |
| 825 | } | 828 | } |
| 826 | 829 | ||
| 827 | std::vector<BufferImageCopy> UnswizzleImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, | 830 | boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::MemoryManager& gpu_memory, |
| 828 | const ImageInfo& info, std::span<const u8> input, | 831 | GPUVAddr gpu_addr, |
| 829 | std::span<u8> output) { | 832 | const ImageInfo& info, |
| 833 | std::span<const u8> input, | ||
| 834 | std::span<u8> output) { | ||
| 830 | const size_t guest_size_bytes = input.size_bytes(); | 835 | const size_t guest_size_bytes = input.size_bytes(); |
| 831 | const u32 bpp_log2 = BytesPerBlockLog2(info.format); | 836 | const u32 bpp_log2 = BytesPerBlockLog2(info.format); |
| 832 | const Extent3D size = info.size; | 837 | const Extent3D size = info.size; |
| @@ -861,7 +866,7 @@ std::vector<BufferImageCopy> UnswizzleImage(Tegra::MemoryManager& gpu_memory, GP | |||
| 861 | info.tile_width_spacing); | 866 | info.tile_width_spacing); |
| 862 | size_t guest_offset = 0; | 867 | size_t guest_offset = 0; |
| 863 | u32 host_offset = 0; | 868 | u32 host_offset = 0; |
| 864 | std::vector<BufferImageCopy> copies(num_levels); | 869 | boost::container::small_vector<BufferImageCopy, 16> copies(num_levels); |
| 865 | 870 | ||
| 866 | for (s32 level = 0; level < num_levels; ++level) { | 871 | for (s32 level = 0; level < num_levels; ++level) { |
| 867 | const Extent3D level_size = AdjustMipSize(size, level); | 872 | const Extent3D level_size = AdjustMipSize(size, level); |
| @@ -939,7 +944,8 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8 | |||
| 939 | tile_size.height, output.subspan(output_offset)); | 944 | tile_size.height, output.subspan(output_offset)); |
| 940 | 945 | ||
| 941 | output_offset += copy.image_extent.width * copy.image_extent.height * | 946 | output_offset += copy.image_extent.width * copy.image_extent.height * |
| 942 | copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK; | 947 | copy.image_subresource.num_layers * |
| 948 | BytesPerBlock(PixelFormat::A8B8G8R8_UNORM); | ||
| 943 | } else if (astc) { | 949 | } else if (astc) { |
| 944 | // BC1 uses 0.5 bytes per texel | 950 | // BC1 uses 0.5 bytes per texel |
| 945 | // BC3 uses 1 byte per texel | 951 | // BC3 uses 1 byte per texel |
| @@ -950,7 +956,8 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8 | |||
| 950 | 956 | ||
| 951 | const u32 plane_dim = copy.image_extent.width * copy.image_extent.height; | 957 | const u32 plane_dim = copy.image_extent.width * copy.image_extent.height; |
| 952 | const u32 level_size = plane_dim * copy.image_extent.depth * | 958 | const u32 level_size = plane_dim * copy.image_extent.depth * |
| 953 | copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK; | 959 | copy.image_subresource.num_layers * |
| 960 | BytesPerBlock(PixelFormat::A8B8G8R8_UNORM); | ||
| 954 | decode_scratch.resize_destructive(level_size); | 961 | decode_scratch.resize_destructive(level_size); |
| 955 | 962 | ||
| 956 | Tegra::Texture::ASTC::Decompress( | 963 | Tegra::Texture::ASTC::Decompress( |
| @@ -970,15 +977,20 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8 | |||
| 970 | bpp_div; | 977 | bpp_div; |
| 971 | output_offset += static_cast<u32>(copy.buffer_size); | 978 | output_offset += static_cast<u32>(copy.buffer_size); |
| 972 | } else { | 979 | } else { |
| 973 | DecompressBC4(input_offset, copy.image_extent, output.subspan(output_offset)); | 980 | const Extent3D image_extent{ |
| 974 | 981 | .width = copy.image_extent.width, | |
| 982 | .height = copy.image_extent.height * copy.image_subresource.num_layers, | ||
| 983 | .depth = copy.image_extent.depth, | ||
| 984 | }; | ||
| 985 | DecompressBCn(input_offset, output.subspan(output_offset), image_extent, info.format); | ||
| 975 | output_offset += copy.image_extent.width * copy.image_extent.height * | 986 | output_offset += copy.image_extent.width * copy.image_extent.height * |
| 976 | copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK; | 987 | copy.image_subresource.num_layers * |
| 988 | ConvertedBytesPerBlock(info.format); | ||
| 977 | } | 989 | } |
| 978 | } | 990 | } |
| 979 | } | 991 | } |
| 980 | 992 | ||
| 981 | std::vector<BufferImageCopy> FullDownloadCopies(const ImageInfo& info) { | 993 | boost::container::small_vector<BufferImageCopy, 16> FullDownloadCopies(const ImageInfo& info) { |
| 982 | const Extent3D size = info.size; | 994 | const Extent3D size = info.size; |
| 983 | const u32 bytes_per_block = BytesPerBlock(info.format); | 995 | const u32 bytes_per_block = BytesPerBlock(info.format); |
| 984 | if (info.type == ImageType::Linear) { | 996 | if (info.type == ImageType::Linear) { |
| @@ -1006,7 +1018,7 @@ std::vector<BufferImageCopy> FullDownloadCopies(const ImageInfo& info) { | |||
| 1006 | 1018 | ||
| 1007 | u32 host_offset = 0; | 1019 | u32 host_offset = 0; |
| 1008 | 1020 | ||
| 1009 | std::vector<BufferImageCopy> copies(num_levels); | 1021 | boost::container::small_vector<BufferImageCopy, 16> copies(num_levels); |
| 1010 | for (s32 level = 0; level < num_levels; ++level) { | 1022 | for (s32 level = 0; level < num_levels; ++level) { |
| 1011 | const Extent3D level_size = AdjustMipSize(size, level); | 1023 | const Extent3D level_size = AdjustMipSize(size, level); |
| 1012 | const u32 num_blocks_per_layer = NumBlocks(level_size, tile_size); | 1024 | const u32 num_blocks_per_layer = NumBlocks(level_size, tile_size); |
| @@ -1042,10 +1054,10 @@ Extent3D MipBlockSize(const ImageInfo& info, u32 level) { | |||
| 1042 | return AdjustMipBlockSize(num_tiles, level_info.block, level); | 1054 | return AdjustMipBlockSize(num_tiles, level_info.block, level); |
| 1043 | } | 1055 | } |
| 1044 | 1056 | ||
| 1045 | std::vector<SwizzleParameters> FullUploadSwizzles(const ImageInfo& info) { | 1057 | boost::container::small_vector<SwizzleParameters, 16> FullUploadSwizzles(const ImageInfo& info) { |
| 1046 | const Extent2D tile_size = DefaultBlockSize(info.format); | 1058 | const Extent2D tile_size = DefaultBlockSize(info.format); |
| 1047 | if (info.type == ImageType::Linear) { | 1059 | if (info.type == ImageType::Linear) { |
| 1048 | return std::vector{SwizzleParameters{ | 1060 | return {SwizzleParameters{ |
| 1049 | .num_tiles = AdjustTileSize(info.size, tile_size), | 1061 | .num_tiles = AdjustTileSize(info.size, tile_size), |
| 1050 | .block = {}, | 1062 | .block = {}, |
| 1051 | .buffer_offset = 0, | 1063 | .buffer_offset = 0, |
| @@ -1057,7 +1069,7 @@ std::vector<SwizzleParameters> FullUploadSwizzles(const ImageInfo& info) { | |||
| 1057 | const s32 num_levels = info.resources.levels; | 1069 | const s32 num_levels = info.resources.levels; |
| 1058 | 1070 | ||
| 1059 | u32 guest_offset = 0; | 1071 | u32 guest_offset = 0; |
| 1060 | std::vector<SwizzleParameters> params(num_levels); | 1072 | boost::container::small_vector<SwizzleParameters, 16> params(num_levels); |
| 1061 | for (s32 level = 0; level < num_levels; ++level) { | 1073 | for (s32 level = 0; level < num_levels; ++level) { |
| 1062 | const Extent3D level_size = AdjustMipSize(size, level); | 1074 | const Extent3D level_size = AdjustMipSize(size, level); |
| 1063 | const Extent3D num_tiles = AdjustTileSize(level_size, tile_size); | 1075 | const Extent3D num_tiles = AdjustTileSize(level_size, tile_size); |
diff --git a/src/video_core/texture_cache/util.h b/src/video_core/texture_cache/util.h index 84aa6880d..ab45a43c4 100644 --- a/src/video_core/texture_cache/util.h +++ b/src/video_core/texture_cache/util.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include <optional> | 6 | #include <optional> |
| 7 | #include <span> | 7 | #include <span> |
| 8 | #include <boost/container/small_vector.hpp> | ||
| 8 | 9 | ||
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 10 | #include "common/scratch_buffer.h" | 11 | #include "common/scratch_buffer.h" |
| @@ -40,9 +41,10 @@ struct OverlapResult { | |||
| 40 | 41 | ||
| 41 | [[nodiscard]] LevelArray CalculateMipLevelSizes(const ImageInfo& info) noexcept; | 42 | [[nodiscard]] LevelArray CalculateMipLevelSizes(const ImageInfo& info) noexcept; |
| 42 | 43 | ||
| 43 | [[nodiscard]] std::vector<u32> CalculateSliceOffsets(const ImageInfo& info); | 44 | [[nodiscard]] boost::container::small_vector<u32, 16> CalculateSliceOffsets(const ImageInfo& info); |
| 44 | 45 | ||
| 45 | [[nodiscard]] std::vector<SubresourceBase> CalculateSliceSubresources(const ImageInfo& info); | 46 | [[nodiscard]] boost::container::small_vector<SubresourceBase, 16> CalculateSliceSubresources( |
| 47 | const ImageInfo& info); | ||
| 46 | 48 | ||
| 47 | [[nodiscard]] u32 CalculateLevelStrideAlignment(const ImageInfo& info, u32 level); | 49 | [[nodiscard]] u32 CalculateLevelStrideAlignment(const ImageInfo& info, u32 level); |
| 48 | 50 | ||
| @@ -51,21 +53,18 @@ struct OverlapResult { | |||
| 51 | 53 | ||
| 52 | [[nodiscard]] ImageViewType RenderTargetImageViewType(const ImageInfo& info) noexcept; | 54 | [[nodiscard]] ImageViewType RenderTargetImageViewType(const ImageInfo& info) noexcept; |
| 53 | 55 | ||
| 54 | [[nodiscard]] std::vector<ImageCopy> MakeShrinkImageCopies(const ImageInfo& dst, | 56 | [[nodiscard]] boost::container::small_vector<ImageCopy, 16> MakeShrinkImageCopies( |
| 55 | const ImageInfo& src, | 57 | const ImageInfo& dst, const ImageInfo& src, SubresourceBase base, u32 up_scale = 1, |
| 56 | SubresourceBase base, u32 up_scale = 1, | 58 | u32 down_shift = 0); |
| 57 | u32 down_shift = 0); | ||
| 58 | 59 | ||
| 59 | [[nodiscard]] std::vector<ImageCopy> MakeReinterpretImageCopies(const ImageInfo& src, | 60 | [[nodiscard]] boost::container::small_vector<ImageCopy, 16> MakeReinterpretImageCopies( |
| 60 | u32 up_scale = 1, | 61 | const ImageInfo& src, u32 up_scale = 1, u32 down_shift = 0); |
| 61 | u32 down_shift = 0); | ||
| 62 | 62 | ||
| 63 | [[nodiscard]] bool IsValidEntry(const Tegra::MemoryManager& gpu_memory, const TICEntry& config); | 63 | [[nodiscard]] bool IsValidEntry(const Tegra::MemoryManager& gpu_memory, const TICEntry& config); |
| 64 | 64 | ||
| 65 | [[nodiscard]] std::vector<BufferImageCopy> UnswizzleImage(Tegra::MemoryManager& gpu_memory, | 65 | [[nodiscard]] boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage( |
| 66 | GPUVAddr gpu_addr, const ImageInfo& info, | 66 | Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const ImageInfo& info, |
| 67 | std::span<const u8> input, | 67 | std::span<const u8> input, std::span<u8> output); |
| 68 | std::span<u8> output); | ||
| 69 | 68 | ||
| 70 | [[nodiscard]] BufferCopy UploadBufferCopy(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, | 69 | [[nodiscard]] BufferCopy UploadBufferCopy(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, |
| 71 | const ImageBase& image, std::span<u8> output); | 70 | const ImageBase& image, std::span<u8> output); |
| @@ -73,13 +72,15 @@ struct OverlapResult { | |||
| 73 | void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8> output, | 72 | void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8> output, |
| 74 | std::span<BufferImageCopy> copies); | 73 | std::span<BufferImageCopy> copies); |
| 75 | 74 | ||
| 76 | [[nodiscard]] std::vector<BufferImageCopy> FullDownloadCopies(const ImageInfo& info); | 75 | [[nodiscard]] boost::container::small_vector<BufferImageCopy, 16> FullDownloadCopies( |
| 76 | const ImageInfo& info); | ||
| 77 | 77 | ||
| 78 | [[nodiscard]] Extent3D MipSize(Extent3D size, u32 level); | 78 | [[nodiscard]] Extent3D MipSize(Extent3D size, u32 level); |
| 79 | 79 | ||
| 80 | [[nodiscard]] Extent3D MipBlockSize(const ImageInfo& info, u32 level); | 80 | [[nodiscard]] Extent3D MipBlockSize(const ImageInfo& info, u32 level); |
| 81 | 81 | ||
| 82 | [[nodiscard]] std::vector<SwizzleParameters> FullUploadSwizzles(const ImageInfo& info); | 82 | [[nodiscard]] boost::container::small_vector<SwizzleParameters, 16> FullUploadSwizzles( |
| 83 | const ImageInfo& info); | ||
| 83 | 84 | ||
| 84 | void SwizzleImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const ImageInfo& info, | 85 | void SwizzleImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const ImageInfo& info, |
| 85 | std::span<const BufferImageCopy> copies, std::span<const u8> memory, | 86 | std::span<const BufferImageCopy> copies, std::span<const u8> memory, |
diff --git a/src/video_core/textures/bcn.cpp b/src/video_core/textures/bcn.cpp index 671212a49..16ddbe320 100644 --- a/src/video_core/textures/bcn.cpp +++ b/src/video_core/textures/bcn.cpp | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | #include <stb_dxt.h> | 4 | #include <stb_dxt.h> |
| 5 | #include <string.h> | 5 | #include <string.h> |
| 6 | |||
| 7 | #include "common/alignment.h" | 6 | #include "common/alignment.h" |
| 8 | #include "video_core/textures/bcn.h" | 7 | #include "video_core/textures/bcn.h" |
| 9 | #include "video_core/textures/workers.h" | 8 | #include "video_core/textures/workers.h" |
diff --git a/src/video_core/textures/bcn.h b/src/video_core/textures/bcn.h index 6464af885..d5d2a16c9 100644 --- a/src/video_core/textures/bcn.h +++ b/src/video_core/textures/bcn.h | |||
| @@ -4,14 +4,13 @@ | |||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <span> | 6 | #include <span> |
| 7 | #include <stdint.h> | 7 | |
| 8 | #include "common/common_types.h" | ||
| 8 | 9 | ||
| 9 | namespace Tegra::Texture::BCN { | 10 | namespace Tegra::Texture::BCN { |
| 10 | 11 | ||
| 11 | void CompressBC1(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth, | 12 | void CompressBC1(std::span<const u8> data, u32 width, u32 height, u32 depth, std::span<u8> output); |
| 12 | std::span<uint8_t> output); | ||
| 13 | 13 | ||
| 14 | void CompressBC3(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth, | 14 | void CompressBC3(std::span<const u8> data, u32 width, u32 height, u32 depth, std::span<u8> output); |
| 15 | std::span<uint8_t> output); | ||
| 16 | 15 | ||
| 17 | } // namespace Tegra::Texture::BCN | 16 | } // namespace Tegra::Texture::BCN |
diff --git a/src/video_core/transform_feedback.cpp b/src/video_core/transform_feedback.cpp index 155599316..1f353d2df 100644 --- a/src/video_core/transform_feedback.cpp +++ b/src/video_core/transform_feedback.cpp | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | namespace VideoCommon { | 14 | namespace VideoCommon { |
| 15 | 15 | ||
| 16 | std::vector<Shader::TransformFeedbackVarying> MakeTransformFeedbackVaryings( | 16 | std::pair<std::array<Shader::TransformFeedbackVarying, 256>, u32> MakeTransformFeedbackVaryings( |
| 17 | const TransformFeedbackState& state) { | 17 | const TransformFeedbackState& state) { |
| 18 | static constexpr std::array VECTORS{ | 18 | static constexpr std::array VECTORS{ |
| 19 | 28U, // gl_Position | 19 | 28U, // gl_Position |
| @@ -62,7 +62,8 @@ std::vector<Shader::TransformFeedbackVarying> MakeTransformFeedbackVaryings( | |||
| 62 | 216U, // gl_TexCoord[6] | 62 | 216U, // gl_TexCoord[6] |
| 63 | 220U, // gl_TexCoord[7] | 63 | 220U, // gl_TexCoord[7] |
| 64 | }; | 64 | }; |
| 65 | std::vector<Shader::TransformFeedbackVarying> xfb(256); | 65 | std::array<Shader::TransformFeedbackVarying, 256> xfb{}; |
| 66 | u32 count{0}; | ||
| 66 | for (size_t buffer = 0; buffer < state.layouts.size(); ++buffer) { | 67 | for (size_t buffer = 0; buffer < state.layouts.size(); ++buffer) { |
| 67 | const auto& locations = state.varyings[buffer]; | 68 | const auto& locations = state.varyings[buffer]; |
| 68 | const auto& layout = state.layouts[buffer]; | 69 | const auto& layout = state.layouts[buffer]; |
| @@ -103,11 +104,12 @@ std::vector<Shader::TransformFeedbackVarying> MakeTransformFeedbackVaryings( | |||
| 103 | } | 104 | } |
| 104 | } | 105 | } |
| 105 | xfb[attribute] = varying; | 106 | xfb[attribute] = varying; |
| 107 | count = std::max(count, attribute); | ||
| 106 | highest = std::max(highest, (base_offset + varying.components) * 4); | 108 | highest = std::max(highest, (base_offset + varying.components) * 4); |
| 107 | } | 109 | } |
| 108 | UNIMPLEMENTED_IF(highest != layout.stride); | 110 | UNIMPLEMENTED_IF(highest != layout.stride); |
| 109 | } | 111 | } |
| 110 | return xfb; | 112 | return {xfb, count + 1}; |
| 111 | } | 113 | } |
| 112 | 114 | ||
| 113 | } // namespace VideoCommon | 115 | } // namespace VideoCommon |
diff --git a/src/video_core/transform_feedback.h b/src/video_core/transform_feedback.h index d13eb16c3..401b1352a 100644 --- a/src/video_core/transform_feedback.h +++ b/src/video_core/transform_feedback.h | |||
| @@ -24,7 +24,7 @@ struct TransformFeedbackState { | |||
| 24 | varyings; | 24 | varyings; |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | std::vector<Shader::TransformFeedbackVarying> MakeTransformFeedbackVaryings( | 27 | std::pair<std::array<Shader::TransformFeedbackVarying, 256>, u32> MakeTransformFeedbackVaryings( |
| 28 | const TransformFeedbackState& state); | 28 | const TransformFeedbackState& state); |
| 29 | 29 | ||
| 30 | } // namespace VideoCommon | 30 | } // namespace VideoCommon |
diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.cpp b/src/video_core/vulkan_common/vulkan_debug_callback.cpp index 9de484c29..67e8065a4 100644 --- a/src/video_core/vulkan_common/vulkan_debug_callback.cpp +++ b/src/video_core/vulkan_common/vulkan_debug_callback.cpp | |||
| @@ -7,10 +7,10 @@ | |||
| 7 | 7 | ||
| 8 | namespace Vulkan { | 8 | namespace Vulkan { |
| 9 | namespace { | 9 | namespace { |
| 10 | VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, | 10 | VkBool32 DebugUtilCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, |
| 11 | VkDebugUtilsMessageTypeFlagsEXT type, | 11 | VkDebugUtilsMessageTypeFlagsEXT type, |
| 12 | const VkDebugUtilsMessengerCallbackDataEXT* data, | 12 | const VkDebugUtilsMessengerCallbackDataEXT* data, |
| 13 | [[maybe_unused]] void* user_data) { | 13 | [[maybe_unused]] void* user_data) { |
| 14 | // Skip logging known false-positive validation errors | 14 | // Skip logging known false-positive validation errors |
| 15 | switch (static_cast<u32>(data->messageIdNumber)) { | 15 | switch (static_cast<u32>(data->messageIdNumber)) { |
| 16 | #ifdef ANDROID | 16 | #ifdef ANDROID |
| @@ -62,9 +62,26 @@ VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, | |||
| 62 | } | 62 | } |
| 63 | return VK_FALSE; | 63 | return VK_FALSE; |
| 64 | } | 64 | } |
| 65 | |||
| 66 | VkBool32 DebugReportCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, | ||
| 67 | uint64_t object, size_t location, int32_t messageCode, | ||
| 68 | const char* pLayerPrefix, const char* pMessage, void* pUserData) { | ||
| 69 | const VkDebugReportFlagBitsEXT severity = static_cast<VkDebugReportFlagBitsEXT>(flags); | ||
| 70 | const std::string_view message{pMessage}; | ||
| 71 | if (severity & VK_DEBUG_REPORT_ERROR_BIT_EXT) { | ||
| 72 | LOG_CRITICAL(Render_Vulkan, "{}", message); | ||
| 73 | } else if (severity & VK_DEBUG_REPORT_WARNING_BIT_EXT) { | ||
| 74 | LOG_WARNING(Render_Vulkan, "{}", message); | ||
| 75 | } else if (severity & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { | ||
| 76 | LOG_INFO(Render_Vulkan, "{}", message); | ||
| 77 | } else if (severity & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { | ||
| 78 | LOG_DEBUG(Render_Vulkan, "{}", message); | ||
| 79 | } | ||
| 80 | return VK_FALSE; | ||
| 81 | } | ||
| 65 | } // Anonymous namespace | 82 | } // Anonymous namespace |
| 66 | 83 | ||
| 67 | vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance) { | 84 | vk::DebugUtilsMessenger CreateDebugUtilsCallback(const vk::Instance& instance) { |
| 68 | return instance.CreateDebugUtilsMessenger(VkDebugUtilsMessengerCreateInfoEXT{ | 85 | return instance.CreateDebugUtilsMessenger(VkDebugUtilsMessengerCreateInfoEXT{ |
| 69 | .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, | 86 | .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, |
| 70 | .pNext = nullptr, | 87 | .pNext = nullptr, |
| @@ -76,7 +93,18 @@ vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance) { | |||
| 76 | .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | | 93 | .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | |
| 77 | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | | 94 | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | |
| 78 | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, | 95 | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, |
| 79 | .pfnUserCallback = Callback, | 96 | .pfnUserCallback = DebugUtilCallback, |
| 97 | .pUserData = nullptr, | ||
| 98 | }); | ||
| 99 | } | ||
| 100 | |||
| 101 | vk::DebugReportCallback CreateDebugReportCallback(const vk::Instance& instance) { | ||
| 102 | return instance.CreateDebugReportCallback({ | ||
| 103 | .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, | ||
| 104 | .pNext = nullptr, | ||
| 105 | .flags = VK_DEBUG_REPORT_DEBUG_BIT_EXT | VK_DEBUG_REPORT_INFORMATION_BIT_EXT | | ||
| 106 | VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT, | ||
| 107 | .pfnCallback = DebugReportCallback, | ||
| 80 | .pUserData = nullptr, | 108 | .pUserData = nullptr, |
| 81 | }); | 109 | }); |
| 82 | } | 110 | } |
diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.h b/src/video_core/vulkan_common/vulkan_debug_callback.h index 71b1f69ec..a8af7b406 100644 --- a/src/video_core/vulkan_common/vulkan_debug_callback.h +++ b/src/video_core/vulkan_common/vulkan_debug_callback.h | |||
| @@ -7,6 +7,8 @@ | |||
| 7 | 7 | ||
| 8 | namespace Vulkan { | 8 | namespace Vulkan { |
| 9 | 9 | ||
| 10 | vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance); | 10 | vk::DebugUtilsMessenger CreateDebugUtilsCallback(const vk::Instance& instance); |
| 11 | |||
| 12 | vk::DebugReportCallback CreateDebugReportCallback(const vk::Instance& instance); | ||
| 11 | 13 | ||
| 12 | } // namespace Vulkan | 14 | } // namespace Vulkan |
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index dcedf4425..421e71e5a 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp | |||
| @@ -22,6 +22,8 @@ | |||
| 22 | #include <adrenotools/bcenabler.h> | 22 | #include <adrenotools/bcenabler.h> |
| 23 | #endif | 23 | #endif |
| 24 | 24 | ||
| 25 | #include <vk_mem_alloc.h> | ||
| 26 | |||
| 25 | namespace Vulkan { | 27 | namespace Vulkan { |
| 26 | using namespace Common::Literals; | 28 | using namespace Common::Literals; |
| 27 | namespace { | 29 | namespace { |
| @@ -316,6 +318,7 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical, | |||
| 316 | std::vector<const char*> ExtensionListForVulkan( | 318 | std::vector<const char*> ExtensionListForVulkan( |
| 317 | const std::set<std::string, std::less<>>& extensions) { | 319 | const std::set<std::string, std::less<>>& extensions) { |
| 318 | std::vector<const char*> output; | 320 | std::vector<const char*> output; |
| 321 | output.reserve(extensions.size()); | ||
| 319 | for (const auto& extension : extensions) { | 322 | for (const auto& extension : extensions) { |
| 320 | output.push_back(extension.c_str()); | 323 | output.push_back(extension.c_str()); |
| 321 | } | 324 | } |
| @@ -346,7 +349,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 346 | const bool is_s8gen2 = device_id == 0x43050a01; | 349 | const bool is_s8gen2 = device_id == 0x43050a01; |
| 347 | const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY; | 350 | const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY; |
| 348 | 351 | ||
| 349 | if ((is_mvk || is_qualcomm || is_turnip) && !is_suitable) { | 352 | if ((is_mvk || is_qualcomm || is_turnip || is_arm) && !is_suitable) { |
| 350 | LOG_WARNING(Render_Vulkan, "Unsuitable driver, continuing anyway"); | 353 | LOG_WARNING(Render_Vulkan, "Unsuitable driver, continuing anyway"); |
| 351 | } else if (!is_suitable) { | 354 | } else if (!is_suitable) { |
| 352 | throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER); | 355 | throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER); |
| @@ -525,6 +528,14 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 525 | } | 528 | } |
| 526 | 529 | ||
| 527 | sets_per_pool = 64; | 530 | sets_per_pool = 64; |
| 531 | if (extensions.extended_dynamic_state3 && is_amd_driver && | ||
| 532 | properties.properties.driverVersion >= VK_MAKE_API_VERSION(0, 2, 0, 270)) { | ||
| 533 | LOG_WARNING(Render_Vulkan, | ||
| 534 | "AMD drivers after 23.5.2 have broken extendedDynamicState3ColorBlendEquation"); | ||
| 535 | features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable = false; | ||
| 536 | features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation = false; | ||
| 537 | dynamic_state3_blending = false; | ||
| 538 | } | ||
| 528 | if (is_amd_driver) { | 539 | if (is_amd_driver) { |
| 529 | // AMD drivers need a higher amount of Sets per Pool in certain circumstances like in XC2. | 540 | // AMD drivers need a higher amount of Sets per Pool in certain circumstances like in XC2. |
| 530 | sets_per_pool = 96; | 541 | sets_per_pool = 96; |
| @@ -562,6 +573,9 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 562 | LOG_WARNING(Render_Vulkan, "Intel proprietary drivers do not support MSAA image blits"); | 573 | LOG_WARNING(Render_Vulkan, "Intel proprietary drivers do not support MSAA image blits"); |
| 563 | cant_blit_msaa = true; | 574 | cant_blit_msaa = true; |
| 564 | } | 575 | } |
| 576 | has_broken_compute = | ||
| 577 | CheckBrokenCompute(properties.driver.driverID, properties.properties.driverVersion) && | ||
| 578 | !Settings::values.enable_compute_pipelines.GetValue(); | ||
| 565 | if (is_intel_anv || (is_qualcomm && !is_s8gen2)) { | 579 | if (is_intel_anv || (is_qualcomm && !is_s8gen2)) { |
| 566 | LOG_WARNING(Render_Vulkan, "Driver does not support native BGR format"); | 580 | LOG_WARNING(Render_Vulkan, "Driver does not support native BGR format"); |
| 567 | must_emulate_bgr565 = true; | 581 | must_emulate_bgr565 = true; |
| @@ -592,9 +606,31 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 592 | 606 | ||
| 593 | graphics_queue = logical.GetQueue(graphics_family); | 607 | graphics_queue = logical.GetQueue(graphics_family); |
| 594 | present_queue = logical.GetQueue(present_family); | 608 | present_queue = logical.GetQueue(present_family); |
| 609 | |||
| 610 | VmaVulkanFunctions functions{}; | ||
| 611 | functions.vkGetInstanceProcAddr = dld.vkGetInstanceProcAddr; | ||
| 612 | functions.vkGetDeviceProcAddr = dld.vkGetDeviceProcAddr; | ||
| 613 | |||
| 614 | const VmaAllocatorCreateInfo allocator_info = { | ||
| 615 | .flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT, | ||
| 616 | .physicalDevice = physical, | ||
| 617 | .device = *logical, | ||
| 618 | .preferredLargeHeapBlockSize = 0, | ||
| 619 | .pAllocationCallbacks = nullptr, | ||
| 620 | .pDeviceMemoryCallbacks = nullptr, | ||
| 621 | .pHeapSizeLimit = nullptr, | ||
| 622 | .pVulkanFunctions = &functions, | ||
| 623 | .instance = instance, | ||
| 624 | .vulkanApiVersion = VK_API_VERSION_1_1, | ||
| 625 | .pTypeExternalMemoryHandleTypes = nullptr, | ||
| 626 | }; | ||
| 627 | |||
| 628 | vk::Check(vmaCreateAllocator(&allocator_info, &allocator)); | ||
| 595 | } | 629 | } |
| 596 | 630 | ||
| 597 | Device::~Device() = default; | 631 | Device::~Device() { |
| 632 | vmaDestroyAllocator(allocator); | ||
| 633 | } | ||
| 598 | 634 | ||
| 599 | VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, | 635 | VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, |
| 600 | FormatType format_type) const { | 636 | FormatType format_type) const { |
| @@ -877,6 +913,10 @@ bool Device::GetSuitability(bool requires_swapchain) { | |||
| 877 | properties.driver.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; | 913 | properties.driver.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; |
| 878 | SetNext(next, properties.driver); | 914 | SetNext(next, properties.driver); |
| 879 | 915 | ||
| 916 | // Retrieve subgroup properties. | ||
| 917 | properties.subgroup_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES; | ||
| 918 | SetNext(next, properties.subgroup_properties); | ||
| 919 | |||
| 880 | // Retrieve relevant extension properties. | 920 | // Retrieve relevant extension properties. |
| 881 | if (extensions.shader_float_controls) { | 921 | if (extensions.shader_float_controls) { |
| 882 | properties.float_controls.sType = | 922 | properties.float_controls.sType = |
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 8c7e44fcb..1f17265d5 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h | |||
| @@ -10,9 +10,12 @@ | |||
| 10 | #include <vector> | 10 | #include <vector> |
| 11 | 11 | ||
| 12 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | #include "common/logging/log.h" | ||
| 13 | #include "common/settings.h" | 14 | #include "common/settings.h" |
| 14 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 15 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 15 | 16 | ||
| 17 | VK_DEFINE_HANDLE(VmaAllocator) | ||
| 18 | |||
| 16 | // Define all features which may be used by the implementation here. | 19 | // Define all features which may be used by the implementation here. |
| 17 | // Vulkan version in the macro describes the minimum version required for feature availability. | 20 | // Vulkan version in the macro describes the minimum version required for feature availability. |
| 18 | // If the Vulkan version is lower than the required version, the named extension is required. | 21 | // If the Vulkan version is lower than the required version, the named extension is required. |
| @@ -198,6 +201,11 @@ public: | |||
| 198 | return dld; | 201 | return dld; |
| 199 | } | 202 | } |
| 200 | 203 | ||
| 204 | /// Returns the VMA allocator. | ||
| 205 | VmaAllocator GetAllocator() const { | ||
| 206 | return allocator; | ||
| 207 | } | ||
| 208 | |||
| 201 | /// Returns the logical device. | 209 | /// Returns the logical device. |
| 202 | const vk::Device& GetLogical() const { | 210 | const vk::Device& GetLogical() const { |
| 203 | return logical; | 211 | return logical; |
| @@ -285,6 +293,11 @@ public: | |||
| 285 | return features.features.textureCompressionASTC_LDR; | 293 | return features.features.textureCompressionASTC_LDR; |
| 286 | } | 294 | } |
| 287 | 295 | ||
| 296 | /// Returns true if BCn is natively supported. | ||
| 297 | bool IsOptimalBcnSupported() const { | ||
| 298 | return features.features.textureCompressionBC; | ||
| 299 | } | ||
| 300 | |||
| 288 | /// Returns true if descriptor aliasing is natively supported. | 301 | /// Returns true if descriptor aliasing is natively supported. |
| 289 | bool IsDescriptorAliasingSupported() const { | 302 | bool IsDescriptorAliasingSupported() const { |
| 290 | return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY; | 303 | return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY; |
| @@ -315,6 +328,11 @@ public: | |||
| 315 | return properties.subgroup_size_control.requiredSubgroupSizeStages & stage; | 328 | return properties.subgroup_size_control.requiredSubgroupSizeStages & stage; |
| 316 | } | 329 | } |
| 317 | 330 | ||
| 331 | /// Returns true if the device supports the provided subgroup feature. | ||
| 332 | bool IsSubgroupFeatureSupported(VkSubgroupFeatureFlagBits feature) const { | ||
| 333 | return properties.subgroup_properties.supportedOperations & feature; | ||
| 334 | } | ||
| 335 | |||
| 318 | /// Returns the maximum number of push descriptors. | 336 | /// Returns the maximum number of push descriptors. |
| 319 | u32 MaxPushDescriptors() const { | 337 | u32 MaxPushDescriptors() const { |
| 320 | return properties.push_descriptor.maxPushDescriptors; | 338 | return properties.push_descriptor.maxPushDescriptors; |
| @@ -380,6 +398,11 @@ public: | |||
| 380 | return extensions.swapchain_mutable_format; | 398 | return extensions.swapchain_mutable_format; |
| 381 | } | 399 | } |
| 382 | 400 | ||
| 401 | /// Returns true if VK_KHR_shader_float_controls is enabled. | ||
| 402 | bool IsKhrShaderFloatControlsSupported() const { | ||
| 403 | return extensions.shader_float_controls; | ||
| 404 | } | ||
| 405 | |||
| 383 | /// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout. | 406 | /// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout. |
| 384 | bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const { | 407 | bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const { |
| 385 | return extensions.workgroup_memory_explicit_layout; | 408 | return extensions.workgroup_memory_explicit_layout; |
| @@ -405,6 +428,11 @@ public: | |||
| 405 | return extensions.sampler_filter_minmax; | 428 | return extensions.sampler_filter_minmax; |
| 406 | } | 429 | } |
| 407 | 430 | ||
| 431 | /// Returns true if the device supports VK_EXT_shader_stencil_export. | ||
| 432 | bool IsExtShaderStencilExportSupported() const { | ||
| 433 | return extensions.shader_stencil_export; | ||
| 434 | } | ||
| 435 | |||
| 408 | /// Returns true if the device supports VK_EXT_depth_range_unrestricted. | 436 | /// Returns true if the device supports VK_EXT_depth_range_unrestricted. |
| 409 | bool IsExtDepthRangeUnrestrictedSupported() const { | 437 | bool IsExtDepthRangeUnrestrictedSupported() const { |
| 410 | return extensions.depth_range_unrestricted; | 438 | return extensions.depth_range_unrestricted; |
| @@ -474,9 +502,9 @@ public: | |||
| 474 | return extensions.vertex_input_dynamic_state; | 502 | return extensions.vertex_input_dynamic_state; |
| 475 | } | 503 | } |
| 476 | 504 | ||
| 477 | /// Returns true if the device supports VK_EXT_shader_stencil_export. | 505 | /// Returns true if the device supports VK_EXT_shader_demote_to_helper_invocation |
| 478 | bool IsExtShaderStencilExportSupported() const { | 506 | bool IsExtShaderDemoteToHelperInvocationSupported() const { |
| 479 | return extensions.shader_stencil_export; | 507 | return extensions.shader_demote_to_helper_invocation; |
| 480 | } | 508 | } |
| 481 | 509 | ||
| 482 | /// Returns true if the device supports VK_EXT_conservative_rasterization. | 510 | /// Returns true if the device supports VK_EXT_conservative_rasterization. |
| @@ -510,12 +538,17 @@ public: | |||
| 510 | if (extensions.spirv_1_4) { | 538 | if (extensions.spirv_1_4) { |
| 511 | return 0x00010400U; | 539 | return 0x00010400U; |
| 512 | } | 540 | } |
| 513 | return 0x00010000U; | 541 | return 0x00010300U; |
| 514 | } | 542 | } |
| 515 | 543 | ||
| 516 | /// Returns true when a known debugging tool is attached. | 544 | /// Returns true when a known debugging tool is attached. |
| 517 | bool HasDebuggingToolAttached() const { | 545 | bool HasDebuggingToolAttached() const { |
| 518 | return has_renderdoc || has_nsight_graphics || Settings::values.renderer_debug.GetValue(); | 546 | return has_renderdoc || has_nsight_graphics; |
| 547 | } | ||
| 548 | |||
| 549 | /// @returns True if compute pipelines can cause crashing. | ||
| 550 | bool HasBrokenCompute() const { | ||
| 551 | return has_broken_compute; | ||
| 519 | } | 552 | } |
| 520 | 553 | ||
| 521 | /// Returns true when the device does not properly support cube compatibility. | 554 | /// Returns true when the device does not properly support cube compatibility. |
| @@ -575,10 +608,30 @@ public: | |||
| 575 | return properties.properties.limits.maxVertexInputBindings; | 608 | return properties.properties.limits.maxVertexInputBindings; |
| 576 | } | 609 | } |
| 577 | 610 | ||
| 611 | u32 GetMaxViewports() const { | ||
| 612 | return properties.properties.limits.maxViewports; | ||
| 613 | } | ||
| 614 | |||
| 578 | bool SupportsConditionalBarriers() const { | 615 | bool SupportsConditionalBarriers() const { |
| 579 | return supports_conditional_barriers; | 616 | return supports_conditional_barriers; |
| 580 | } | 617 | } |
| 581 | 618 | ||
| 619 | [[nodiscard]] static constexpr bool CheckBrokenCompute(VkDriverId driver_id, | ||
| 620 | u32 driver_version) { | ||
| 621 | if (driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) { | ||
| 622 | const u32 major = VK_API_VERSION_MAJOR(driver_version); | ||
| 623 | const u32 minor = VK_API_VERSION_MINOR(driver_version); | ||
| 624 | const u32 patch = VK_API_VERSION_PATCH(driver_version); | ||
| 625 | if (major == 0 && minor == 405 && patch < 286) { | ||
| 626 | LOG_WARNING( | ||
| 627 | Render_Vulkan, | ||
| 628 | "Intel proprietary drivers 0.405.0 until 0.405.286 have broken compute"); | ||
| 629 | return true; | ||
| 630 | } | ||
| 631 | } | ||
| 632 | return false; | ||
| 633 | } | ||
| 634 | |||
| 582 | private: | 635 | private: |
| 583 | /// Checks if the physical device is suitable and configures the object state | 636 | /// Checks if the physical device is suitable and configures the object state |
| 584 | /// with all necessary info about its properties. | 637 | /// with all necessary info about its properties. |
| @@ -608,6 +661,7 @@ private: | |||
| 608 | 661 | ||
| 609 | private: | 662 | private: |
| 610 | VkInstance instance; ///< Vulkan instance. | 663 | VkInstance instance; ///< Vulkan instance. |
| 664 | VmaAllocator allocator; ///< VMA allocator. | ||
| 611 | vk::DeviceDispatch dld; ///< Device function pointers. | 665 | vk::DeviceDispatch dld; ///< Device function pointers. |
| 612 | vk::PhysicalDevice physical; ///< Physical device. | 666 | vk::PhysicalDevice physical; ///< Physical device. |
| 613 | vk::Device logical; ///< Logical device. | 667 | vk::Device logical; ///< Logical device. |
| @@ -650,6 +704,7 @@ private: | |||
| 650 | 704 | ||
| 651 | struct Properties { | 705 | struct Properties { |
| 652 | VkPhysicalDeviceDriverProperties driver{}; | 706 | VkPhysicalDeviceDriverProperties driver{}; |
| 707 | VkPhysicalDeviceSubgroupProperties subgroup_properties{}; | ||
| 653 | VkPhysicalDeviceFloatControlsProperties float_controls{}; | 708 | VkPhysicalDeviceFloatControlsProperties float_controls{}; |
| 654 | VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor{}; | 709 | VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor{}; |
| 655 | VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{}; | 710 | VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{}; |
| @@ -672,6 +727,7 @@ private: | |||
| 672 | bool is_integrated{}; ///< Is GPU an iGPU. | 727 | bool is_integrated{}; ///< Is GPU an iGPU. |
| 673 | bool is_virtual{}; ///< Is GPU a virtual GPU. | 728 | bool is_virtual{}; ///< Is GPU a virtual GPU. |
| 674 | bool is_non_gpu{}; ///< Is SoftwareRasterizer, FPGA, non-GPU device. | 729 | bool is_non_gpu{}; ///< Is SoftwareRasterizer, FPGA, non-GPU device. |
| 730 | bool has_broken_compute{}; ///< Compute shaders can cause crashes | ||
| 675 | bool has_broken_cube_compatibility{}; ///< Has broken cube compatibility bit | 731 | bool has_broken_cube_compatibility{}; ///< Has broken cube compatibility bit |
| 676 | bool has_renderdoc{}; ///< Has RenderDoc attached | 732 | bool has_renderdoc{}; ///< Has RenderDoc attached |
| 677 | bool has_nsight_graphics{}; ///< Has Nsight Graphics attached | 733 | bool has_nsight_graphics{}; ///< Has Nsight Graphics attached |
diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp index b6d83e446..7624a9b32 100644 --- a/src/video_core/vulkan_common/vulkan_instance.cpp +++ b/src/video_core/vulkan_common/vulkan_instance.cpp | |||
| @@ -31,10 +31,34 @@ | |||
| 31 | 31 | ||
| 32 | namespace Vulkan { | 32 | namespace Vulkan { |
| 33 | namespace { | 33 | namespace { |
| 34 | |||
| 35 | [[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld, | ||
| 36 | std::span<const char* const> extensions) { | ||
| 37 | const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld); | ||
| 38 | if (!properties) { | ||
| 39 | LOG_ERROR(Render_Vulkan, "Failed to query extension properties"); | ||
| 40 | return false; | ||
| 41 | } | ||
| 42 | for (const char* extension : extensions) { | ||
| 43 | const auto it = std::ranges::find_if(*properties, [extension](const auto& prop) { | ||
| 44 | return std::strcmp(extension, prop.extensionName) == 0; | ||
| 45 | }); | ||
| 46 | if (it == properties->end()) { | ||
| 47 | LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension); | ||
| 48 | return false; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | return true; | ||
| 52 | } | ||
| 53 | |||
| 34 | [[nodiscard]] std::vector<const char*> RequiredExtensions( | 54 | [[nodiscard]] std::vector<const char*> RequiredExtensions( |
| 35 | Core::Frontend::WindowSystemType window_type, bool enable_validation) { | 55 | const vk::InstanceDispatch& dld, Core::Frontend::WindowSystemType window_type, |
| 56 | bool enable_validation) { | ||
| 36 | std::vector<const char*> extensions; | 57 | std::vector<const char*> extensions; |
| 37 | extensions.reserve(6); | 58 | extensions.reserve(6); |
| 59 | #ifdef __APPLE__ | ||
| 60 | extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); | ||
| 61 | #endif | ||
| 38 | switch (window_type) { | 62 | switch (window_type) { |
| 39 | case Core::Frontend::WindowSystemType::Headless: | 63 | case Core::Frontend::WindowSystemType::Headless: |
| 40 | break; | 64 | break; |
| @@ -66,35 +90,14 @@ namespace { | |||
| 66 | extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); | 90 | extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); |
| 67 | } | 91 | } |
| 68 | if (enable_validation) { | 92 | if (enable_validation) { |
| 69 | extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); | 93 | const bool debug_utils = |
| 94 | AreExtensionsSupported(dld, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME}); | ||
| 95 | extensions.push_back(debug_utils ? VK_EXT_DEBUG_UTILS_EXTENSION_NAME | ||
| 96 | : VK_EXT_DEBUG_REPORT_EXTENSION_NAME); | ||
| 70 | } | 97 | } |
| 71 | extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); | ||
| 72 | |||
| 73 | #ifdef __APPLE__ | ||
| 74 | extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); | ||
| 75 | #endif | ||
| 76 | return extensions; | 98 | return extensions; |
| 77 | } | 99 | } |
| 78 | 100 | ||
| 79 | [[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld, | ||
| 80 | std::span<const char* const> extensions) { | ||
| 81 | const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld); | ||
| 82 | if (!properties) { | ||
| 83 | LOG_ERROR(Render_Vulkan, "Failed to query extension properties"); | ||
| 84 | return false; | ||
| 85 | } | ||
| 86 | for (const char* extension : extensions) { | ||
| 87 | const auto it = std::ranges::find_if(*properties, [extension](const auto& prop) { | ||
| 88 | return std::strcmp(extension, prop.extensionName) == 0; | ||
| 89 | }); | ||
| 90 | if (it == properties->end()) { | ||
| 91 | LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension); | ||
| 92 | return false; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | return true; | ||
| 96 | } | ||
| 97 | |||
| 98 | [[nodiscard]] std::vector<const char*> Layers(bool enable_validation) { | 101 | [[nodiscard]] std::vector<const char*> Layers(bool enable_validation) { |
| 99 | std::vector<const char*> layers; | 102 | std::vector<const char*> layers; |
| 100 | if (enable_validation) { | 103 | if (enable_validation) { |
| @@ -138,7 +141,8 @@ vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceD | |||
| 138 | LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers"); | 141 | LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers"); |
| 139 | throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); | 142 | throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); |
| 140 | } | 143 | } |
| 141 | const std::vector<const char*> extensions = RequiredExtensions(window_type, enable_validation); | 144 | const std::vector<const char*> extensions = |
| 145 | RequiredExtensions(dld, window_type, enable_validation); | ||
| 142 | if (!AreExtensionsSupported(dld, extensions)) { | 146 | if (!AreExtensionsSupported(dld, extensions)) { |
| 143 | throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); | 147 | throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); |
| 144 | } | 148 | } |
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index e28a556f8..a2ef0efa4 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | #include <optional> | 6 | #include <optional> |
| 7 | #include <vector> | 7 | #include <vector> |
| 8 | 8 | ||
| 9 | #include <glad/glad.h> | ||
| 10 | |||
| 11 | #include "common/alignment.h" | 9 | #include "common/alignment.h" |
| 12 | #include "common/assert.h" | 10 | #include "common/assert.h" |
| 13 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| @@ -17,6 +15,8 @@ | |||
| 17 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | 15 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" |
| 18 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 16 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 19 | 17 | ||
| 18 | #include <vk_mem_alloc.h> | ||
| 19 | |||
| 20 | namespace Vulkan { | 20 | namespace Vulkan { |
| 21 | namespace { | 21 | namespace { |
| 22 | struct Range { | 22 | struct Range { |
| @@ -49,22 +49,45 @@ struct Range { | |||
| 49 | case MemoryUsage::Download: | 49 | case MemoryUsage::Download: |
| 50 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | | 50 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | |
| 51 | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; | 51 | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; |
| 52 | case MemoryUsage::Stream: | ||
| 53 | return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | | ||
| 54 | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | ||
| 52 | } | 55 | } |
| 53 | ASSERT_MSG(false, "Invalid memory usage={}", usage); | 56 | ASSERT_MSG(false, "Invalid memory usage={}", usage); |
| 54 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | 57 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; |
| 55 | } | 58 | } |
| 56 | 59 | ||
| 57 | constexpr VkExportMemoryAllocateInfo EXPORT_ALLOCATE_INFO{ | 60 | [[nodiscard]] VkMemoryPropertyFlags MemoryUsagePreferedVmaFlags(MemoryUsage usage) { |
| 58 | .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, | 61 | return usage != MemoryUsage::DeviceLocal ? VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
| 59 | .pNext = nullptr, | 62 | : VkMemoryPropertyFlagBits{}; |
| 60 | #ifdef _WIN32 | 63 | } |
| 61 | .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, | 64 | |
| 62 | #elif __unix__ | 65 | [[nodiscard]] VmaAllocationCreateFlags MemoryUsageVmaFlags(MemoryUsage usage) { |
| 63 | .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, | 66 | switch (usage) { |
| 64 | #else | 67 | case MemoryUsage::Upload: |
| 65 | .handleTypes = 0, | 68 | case MemoryUsage::Stream: |
| 66 | #endif | 69 | return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; |
| 67 | }; | 70 | case MemoryUsage::Download: |
| 71 | return VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; | ||
| 72 | case MemoryUsage::DeviceLocal: | ||
| 73 | return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | | ||
| 74 | VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT; | ||
| 75 | } | ||
| 76 | return {}; | ||
| 77 | } | ||
| 78 | |||
| 79 | [[nodiscard]] VmaMemoryUsage MemoryUsageVma(MemoryUsage usage) { | ||
| 80 | switch (usage) { | ||
| 81 | case MemoryUsage::DeviceLocal: | ||
| 82 | case MemoryUsage::Stream: | ||
| 83 | return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; | ||
| 84 | case MemoryUsage::Upload: | ||
| 85 | case MemoryUsage::Download: | ||
| 86 | return VMA_MEMORY_USAGE_AUTO_PREFER_HOST; | ||
| 87 | } | ||
| 88 | return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; | ||
| 89 | } | ||
| 90 | |||
| 68 | } // Anonymous namespace | 91 | } // Anonymous namespace |
| 69 | 92 | ||
| 70 | class MemoryAllocation { | 93 | class MemoryAllocation { |
| @@ -74,14 +97,6 @@ public: | |||
| 74 | : allocator{allocator_}, memory{std::move(memory_)}, allocation_size{allocation_size_}, | 97 | : allocator{allocator_}, memory{std::move(memory_)}, allocation_size{allocation_size_}, |
| 75 | property_flags{properties}, shifted_memory_type{1U << type} {} | 98 | property_flags{properties}, shifted_memory_type{1U << type} {} |
| 76 | 99 | ||
| 77 | #if defined(_WIN32) || defined(__unix__) | ||
| 78 | ~MemoryAllocation() { | ||
| 79 | if (owning_opengl_handle != 0) { | ||
| 80 | glDeleteMemoryObjectsEXT(1, &owning_opengl_handle); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | #endif | ||
| 84 | |||
| 85 | MemoryAllocation& operator=(const MemoryAllocation&) = delete; | 100 | MemoryAllocation& operator=(const MemoryAllocation&) = delete; |
| 86 | MemoryAllocation(const MemoryAllocation&) = delete; | 101 | MemoryAllocation(const MemoryAllocation&) = delete; |
| 87 | 102 | ||
| @@ -120,31 +135,6 @@ public: | |||
| 120 | return memory_mapped_span; | 135 | return memory_mapped_span; |
| 121 | } | 136 | } |
| 122 | 137 | ||
| 123 | #ifdef _WIN32 | ||
| 124 | [[nodiscard]] u32 ExportOpenGLHandle() { | ||
| 125 | if (!owning_opengl_handle) { | ||
| 126 | glCreateMemoryObjectsEXT(1, &owning_opengl_handle); | ||
| 127 | glImportMemoryWin32HandleEXT(owning_opengl_handle, allocation_size, | ||
| 128 | GL_HANDLE_TYPE_OPAQUE_WIN32_EXT, | ||
| 129 | memory.GetMemoryWin32HandleKHR()); | ||
| 130 | } | ||
| 131 | return owning_opengl_handle; | ||
| 132 | } | ||
| 133 | #elif __unix__ | ||
| 134 | [[nodiscard]] u32 ExportOpenGLHandle() { | ||
| 135 | if (!owning_opengl_handle) { | ||
| 136 | glCreateMemoryObjectsEXT(1, &owning_opengl_handle); | ||
| 137 | glImportMemoryFdEXT(owning_opengl_handle, allocation_size, GL_HANDLE_TYPE_OPAQUE_FD_EXT, | ||
| 138 | memory.GetMemoryFdKHR()); | ||
| 139 | } | ||
| 140 | return owning_opengl_handle; | ||
| 141 | } | ||
| 142 | #else | ||
| 143 | [[nodiscard]] u32 ExportOpenGLHandle() { | ||
| 144 | return 0; | ||
| 145 | } | ||
| 146 | #endif | ||
| 147 | |||
| 148 | /// Returns whether this allocation is compatible with the arguments. | 138 | /// Returns whether this allocation is compatible with the arguments. |
| 149 | [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { | 139 | [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { |
| 150 | return (flags & property_flags) == flags && (type_mask & shifted_memory_type) != 0; | 140 | return (flags & property_flags) == flags && (type_mask & shifted_memory_type) != 0; |
| @@ -182,9 +172,6 @@ private: | |||
| 182 | const u32 shifted_memory_type; ///< Shifted Vulkan memory type. | 172 | const u32 shifted_memory_type; ///< Shifted Vulkan memory type. |
| 183 | std::vector<Range> commits; ///< All commit ranges done from this allocation. | 173 | std::vector<Range> commits; ///< All commit ranges done from this allocation. |
| 184 | std::span<u8> memory_mapped_span; ///< Memory mapped span. Empty if not queried before. | 174 | std::span<u8> memory_mapped_span; ///< Memory mapped span. Empty if not queried before. |
| 185 | #if defined(_WIN32) || defined(__unix__) | ||
| 186 | u32 owning_opengl_handle{}; ///< Owning OpenGL memory object handle. | ||
| 187 | #endif | ||
| 188 | }; | 175 | }; |
| 189 | 176 | ||
| 190 | MemoryCommit::MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, | 177 | MemoryCommit::MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, |
| @@ -216,24 +203,70 @@ std::span<u8> MemoryCommit::Map() { | |||
| 216 | return span; | 203 | return span; |
| 217 | } | 204 | } |
| 218 | 205 | ||
| 219 | u32 MemoryCommit::ExportOpenGLHandle() const { | ||
| 220 | return allocation->ExportOpenGLHandle(); | ||
| 221 | } | ||
| 222 | |||
| 223 | void MemoryCommit::Release() { | 206 | void MemoryCommit::Release() { |
| 224 | if (allocation) { | 207 | if (allocation) { |
| 225 | allocation->Free(begin); | 208 | allocation->Free(begin); |
| 226 | } | 209 | } |
| 227 | } | 210 | } |
| 228 | 211 | ||
| 229 | MemoryAllocator::MemoryAllocator(const Device& device_, bool export_allocations_) | 212 | MemoryAllocator::MemoryAllocator(const Device& device_) |
| 230 | : device{device_}, properties{device_.GetPhysical().GetMemoryProperties().memoryProperties}, | 213 | : device{device_}, allocator{device.GetAllocator()}, |
| 231 | export_allocations{export_allocations_}, | 214 | properties{device_.GetPhysical().GetMemoryProperties().memoryProperties}, |
| 232 | buffer_image_granularity{ | 215 | buffer_image_granularity{ |
| 233 | device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {} | 216 | device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {} |
| 234 | 217 | ||
| 235 | MemoryAllocator::~MemoryAllocator() = default; | 218 | MemoryAllocator::~MemoryAllocator() = default; |
| 236 | 219 | ||
| 220 | vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const { | ||
| 221 | const VmaAllocationCreateInfo alloc_ci = { | ||
| 222 | .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT, | ||
| 223 | .usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, | ||
| 224 | .requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, | ||
| 225 | .preferredFlags = 0, | ||
| 226 | .memoryTypeBits = 0, | ||
| 227 | .pool = VK_NULL_HANDLE, | ||
| 228 | .pUserData = nullptr, | ||
| 229 | .priority = 0.f, | ||
| 230 | }; | ||
| 231 | |||
| 232 | VkImage handle{}; | ||
| 233 | VmaAllocation allocation{}; | ||
| 234 | |||
| 235 | vk::Check(vmaCreateImage(allocator, &ci, &alloc_ci, &handle, &allocation, nullptr)); | ||
| 236 | |||
| 237 | return vk::Image(handle, *device.GetLogical(), allocator, allocation, | ||
| 238 | device.GetDispatchLoader()); | ||
| 239 | } | ||
| 240 | |||
| 241 | vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const { | ||
| 242 | const VmaAllocationCreateInfo alloc_ci = { | ||
| 243 | .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT | | ||
| 244 | MemoryUsageVmaFlags(usage), | ||
| 245 | .usage = MemoryUsageVma(usage), | ||
| 246 | .requiredFlags = 0, | ||
| 247 | .preferredFlags = MemoryUsagePreferedVmaFlags(usage), | ||
| 248 | .memoryTypeBits = 0, | ||
| 249 | .pool = VK_NULL_HANDLE, | ||
| 250 | .pUserData = nullptr, | ||
| 251 | .priority = 0.f, | ||
| 252 | }; | ||
| 253 | |||
| 254 | VkBuffer handle{}; | ||
| 255 | VmaAllocationInfo alloc_info{}; | ||
| 256 | VmaAllocation allocation{}; | ||
| 257 | VkMemoryPropertyFlags property_flags{}; | ||
| 258 | |||
| 259 | vk::Check(vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info)); | ||
| 260 | vmaGetAllocationMemoryProperties(allocator, allocation, &property_flags); | ||
| 261 | |||
| 262 | u8* data = reinterpret_cast<u8*>(alloc_info.pMappedData); | ||
| 263 | const std::span<u8> mapped_data = data ? std::span<u8>{data, ci.size} : std::span<u8>{}; | ||
| 264 | const bool is_coherent = property_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | ||
| 265 | |||
| 266 | return vk::Buffer(handle, *device.GetLogical(), allocator, allocation, mapped_data, is_coherent, | ||
| 267 | device.GetDispatchLoader()); | ||
| 268 | } | ||
| 269 | |||
| 237 | MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { | 270 | MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { |
| 238 | // Find the fastest memory flags we can afford with the current requirements | 271 | // Find the fastest memory flags we can afford with the current requirements |
| 239 | const u32 type_mask = requirements.memoryTypeBits; | 272 | const u32 type_mask = requirements.memoryTypeBits; |
| @@ -253,25 +286,11 @@ MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, M | |||
| 253 | return TryCommit(requirements, flags).value(); | 286 | return TryCommit(requirements, flags).value(); |
| 254 | } | 287 | } |
| 255 | 288 | ||
| 256 | MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage) { | ||
| 257 | auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), usage); | ||
| 258 | buffer.BindMemory(commit.Memory(), commit.Offset()); | ||
| 259 | return commit; | ||
| 260 | } | ||
| 261 | |||
| 262 | MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) { | ||
| 263 | VkMemoryRequirements requirements = device.GetLogical().GetImageMemoryRequirements(*image); | ||
| 264 | requirements.size = Common::AlignUp(requirements.size, buffer_image_granularity); | ||
| 265 | auto commit = Commit(requirements, usage); | ||
| 266 | image.BindMemory(commit.Memory(), commit.Offset()); | ||
| 267 | return commit; | ||
| 268 | } | ||
| 269 | |||
| 270 | bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { | 289 | bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { |
| 271 | const u32 type = FindType(flags, type_mask).value(); | 290 | const u32 type = FindType(flags, type_mask).value(); |
| 272 | vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ | 291 | vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ |
| 273 | .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | 292 | .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, |
| 274 | .pNext = export_allocations ? &EXPORT_ALLOCATE_INFO : nullptr, | 293 | .pNext = nullptr, |
| 275 | .allocationSize = size, | 294 | .allocationSize = size, |
| 276 | .memoryTypeIndex = type, | 295 | .memoryTypeIndex = type, |
| 277 | }); | 296 | }); |
| @@ -342,16 +361,4 @@ std::optional<u32> MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 ty | |||
| 342 | return std::nullopt; | 361 | return std::nullopt; |
| 343 | } | 362 | } |
| 344 | 363 | ||
| 345 | bool IsHostVisible(MemoryUsage usage) noexcept { | ||
| 346 | switch (usage) { | ||
| 347 | case MemoryUsage::DeviceLocal: | ||
| 348 | return false; | ||
| 349 | case MemoryUsage::Upload: | ||
| 350 | case MemoryUsage::Download: | ||
| 351 | return true; | ||
| 352 | } | ||
| 353 | ASSERT_MSG(false, "Invalid memory usage={}", usage); | ||
| 354 | return false; | ||
| 355 | } | ||
| 356 | |||
| 357 | } // namespace Vulkan | 364 | } // namespace Vulkan |
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h index a5bff03fe..f449bc8d0 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.h +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h | |||
| @@ -9,6 +9,8 @@ | |||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 10 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 11 | 11 | ||
| 12 | VK_DEFINE_HANDLE(VmaAllocator) | ||
| 13 | |||
| 12 | namespace Vulkan { | 14 | namespace Vulkan { |
| 13 | 15 | ||
| 14 | class Device; | 16 | class Device; |
| @@ -17,9 +19,11 @@ class MemoryAllocation; | |||
| 17 | 19 | ||
| 18 | /// Hints and requirements for the backing memory type of a commit | 20 | /// Hints and requirements for the backing memory type of a commit |
| 19 | enum class MemoryUsage { | 21 | enum class MemoryUsage { |
| 20 | DeviceLocal, ///< Hints device local usages, fastest memory type to read and write from the GPU | 22 | DeviceLocal, ///< Requests device local host visible buffer, falling back to device local |
| 23 | ///< memory. | ||
| 21 | Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads | 24 | Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads |
| 22 | Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks | 25 | Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks |
| 26 | Stream, ///< Requests device local host visible buffer, falling back host memory. | ||
| 23 | }; | 27 | }; |
| 24 | 28 | ||
| 25 | /// Ownership handle of a memory commitment. | 29 | /// Ownership handle of a memory commitment. |
| @@ -41,9 +45,6 @@ public: | |||
| 41 | /// It will map the backing allocation if it hasn't been mapped before. | 45 | /// It will map the backing allocation if it hasn't been mapped before. |
| 42 | std::span<u8> Map(); | 46 | std::span<u8> Map(); |
| 43 | 47 | ||
| 44 | /// Returns an non-owning OpenGL handle, creating one if it doesn't exist. | ||
| 45 | u32 ExportOpenGLHandle() const; | ||
| 46 | |||
| 47 | /// Returns the Vulkan memory handler. | 48 | /// Returns the Vulkan memory handler. |
| 48 | VkDeviceMemory Memory() const { | 49 | VkDeviceMemory Memory() const { |
| 49 | return memory; | 50 | return memory; |
| @@ -74,16 +75,19 @@ public: | |||
| 74 | * Construct memory allocator | 75 | * Construct memory allocator |
| 75 | * | 76 | * |
| 76 | * @param device_ Device to allocate from | 77 | * @param device_ Device to allocate from |
| 77 | * @param export_allocations_ True when allocations have to be exported | ||
| 78 | * | 78 | * |
| 79 | * @throw vk::Exception on failure | 79 | * @throw vk::Exception on failure |
| 80 | */ | 80 | */ |
| 81 | explicit MemoryAllocator(const Device& device_, bool export_allocations_); | 81 | explicit MemoryAllocator(const Device& device_); |
| 82 | ~MemoryAllocator(); | 82 | ~MemoryAllocator(); |
| 83 | 83 | ||
| 84 | MemoryAllocator& operator=(const MemoryAllocator&) = delete; | 84 | MemoryAllocator& operator=(const MemoryAllocator&) = delete; |
| 85 | MemoryAllocator(const MemoryAllocator&) = delete; | 85 | MemoryAllocator(const MemoryAllocator&) = delete; |
| 86 | 86 | ||
| 87 | vk::Image CreateImage(const VkImageCreateInfo& ci) const; | ||
| 88 | |||
| 89 | vk::Buffer CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const; | ||
| 90 | |||
| 87 | /** | 91 | /** |
| 88 | * Commits a memory with the specified requirements. | 92 | * Commits a memory with the specified requirements. |
| 89 | * | 93 | * |
| @@ -97,9 +101,6 @@ public: | |||
| 97 | /// Commits memory required by the buffer and binds it. | 101 | /// Commits memory required by the buffer and binds it. |
| 98 | MemoryCommit Commit(const vk::Buffer& buffer, MemoryUsage usage); | 102 | MemoryCommit Commit(const vk::Buffer& buffer, MemoryUsage usage); |
| 99 | 103 | ||
| 100 | /// Commits memory required by the image and binds it. | ||
| 101 | MemoryCommit Commit(const vk::Image& image, MemoryUsage usage); | ||
| 102 | |||
| 103 | private: | 104 | private: |
| 104 | /// Tries to allocate a chunk of memory. | 105 | /// Tries to allocate a chunk of memory. |
| 105 | bool TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size); | 106 | bool TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size); |
| @@ -117,15 +118,12 @@ private: | |||
| 117 | /// Returns index to the fastest memory type compatible with the passed requirements. | 118 | /// Returns index to the fastest memory type compatible with the passed requirements. |
| 118 | std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; | 119 | std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; |
| 119 | 120 | ||
| 120 | const Device& device; ///< Device handle. | 121 | const Device& device; ///< Device handle. |
| 121 | const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. | 122 | VmaAllocator allocator; ///< Vma allocator. |
| 122 | const bool export_allocations; ///< True when memory allocations have to be exported. | 123 | const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. |
| 123 | std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations. | 124 | std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations. |
| 124 | VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers | 125 | VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers |
| 125 | // and optimal images | 126 | // and optimal images |
| 126 | }; | 127 | }; |
| 127 | 128 | ||
| 128 | /// Returns true when a memory usage is guaranteed to be host visible. | ||
| 129 | bool IsHostVisible(MemoryUsage usage) noexcept; | ||
| 130 | |||
| 131 | } // namespace Vulkan | 129 | } // namespace Vulkan |
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 336f53700..2fa29793a 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp | |||
| @@ -12,6 +12,8 @@ | |||
| 12 | 12 | ||
| 13 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 13 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 14 | 14 | ||
| 15 | #include <vk_mem_alloc.h> | ||
| 16 | |||
| 15 | namespace Vulkan::vk { | 17 | namespace Vulkan::vk { |
| 16 | 18 | ||
| 17 | namespace { | 19 | namespace { |
| @@ -257,7 +259,9 @@ bool Load(VkInstance instance, InstanceDispatch& dld) noexcept { | |||
| 257 | // These functions may fail to load depending on the enabled extensions. | 259 | // These functions may fail to load depending on the enabled extensions. |
| 258 | // Don't return a failure on these. | 260 | // Don't return a failure on these. |
| 259 | X(vkCreateDebugUtilsMessengerEXT); | 261 | X(vkCreateDebugUtilsMessengerEXT); |
| 262 | X(vkCreateDebugReportCallbackEXT); | ||
| 260 | X(vkDestroyDebugUtilsMessengerEXT); | 263 | X(vkDestroyDebugUtilsMessengerEXT); |
| 264 | X(vkDestroyDebugReportCallbackEXT); | ||
| 261 | X(vkDestroySurfaceKHR); | 265 | X(vkDestroySurfaceKHR); |
| 262 | X(vkGetPhysicalDeviceFeatures2); | 266 | X(vkGetPhysicalDeviceFeatures2); |
| 263 | X(vkGetPhysicalDeviceProperties2); | 267 | X(vkGetPhysicalDeviceProperties2); |
| @@ -479,6 +483,11 @@ void Destroy(VkInstance instance, VkDebugUtilsMessengerEXT handle, | |||
| 479 | dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr); | 483 | dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr); |
| 480 | } | 484 | } |
| 481 | 485 | ||
| 486 | void Destroy(VkInstance instance, VkDebugReportCallbackEXT handle, | ||
| 487 | const InstanceDispatch& dld) noexcept { | ||
| 488 | dld.vkDestroyDebugReportCallbackEXT(instance, handle, nullptr); | ||
| 489 | } | ||
| 490 | |||
| 482 | void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept { | 491 | void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept { |
| 483 | dld.vkDestroySurfaceKHR(instance, handle, nullptr); | 492 | dld.vkDestroySurfaceKHR(instance, handle, nullptr); |
| 484 | } | 493 | } |
| @@ -547,24 +556,47 @@ DebugUtilsMessenger Instance::CreateDebugUtilsMessenger( | |||
| 547 | return DebugUtilsMessenger(object, handle, *dld); | 556 | return DebugUtilsMessenger(object, handle, *dld); |
| 548 | } | 557 | } |
| 549 | 558 | ||
| 550 | void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { | 559 | DebugReportCallback Instance::CreateDebugReportCallback( |
| 551 | Check(dld->vkBindBufferMemory(owner, handle, memory, offset)); | 560 | const VkDebugReportCallbackCreateInfoEXT& create_info) const { |
| 561 | VkDebugReportCallbackEXT object; | ||
| 562 | Check(dld->vkCreateDebugReportCallbackEXT(handle, &create_info, nullptr, &object)); | ||
| 563 | return DebugReportCallback(object, handle, *dld); | ||
| 552 | } | 564 | } |
| 553 | 565 | ||
| 554 | void Buffer::SetObjectNameEXT(const char* name) const { | 566 | void Image::SetObjectNameEXT(const char* name) const { |
| 555 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name); | 567 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name); |
| 556 | } | 568 | } |
| 557 | 569 | ||
| 558 | void BufferView::SetObjectNameEXT(const char* name) const { | 570 | void Image::Release() const noexcept { |
| 559 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name); | 571 | if (handle) { |
| 572 | vmaDestroyImage(allocator, handle, allocation); | ||
| 573 | } | ||
| 560 | } | 574 | } |
| 561 | 575 | ||
| 562 | void Image::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { | 576 | void Buffer::Flush() const { |
| 563 | Check(dld->vkBindImageMemory(owner, handle, memory, offset)); | 577 | if (!is_coherent) { |
| 578 | vmaFlushAllocation(allocator, allocation, 0, VK_WHOLE_SIZE); | ||
| 579 | } | ||
| 564 | } | 580 | } |
| 565 | 581 | ||
| 566 | void Image::SetObjectNameEXT(const char* name) const { | 582 | void Buffer::Invalidate() const { |
| 567 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name); | 583 | if (!is_coherent) { |
| 584 | vmaInvalidateAllocation(allocator, allocation, 0, VK_WHOLE_SIZE); | ||
| 585 | } | ||
| 586 | } | ||
| 587 | |||
| 588 | void Buffer::SetObjectNameEXT(const char* name) const { | ||
| 589 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name); | ||
| 590 | } | ||
| 591 | |||
| 592 | void Buffer::Release() const noexcept { | ||
| 593 | if (handle) { | ||
| 594 | vmaDestroyBuffer(allocator, handle, allocation); | ||
| 595 | } | ||
| 596 | } | ||
| 597 | |||
| 598 | void BufferView::SetObjectNameEXT(const char* name) const { | ||
| 599 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name); | ||
| 568 | } | 600 | } |
| 569 | 601 | ||
| 570 | void ImageView::SetObjectNameEXT(const char* name) const { | 602 | void ImageView::SetObjectNameEXT(const char* name) const { |
| @@ -701,24 +733,12 @@ Queue Device::GetQueue(u32 family_index) const noexcept { | |||
| 701 | return Queue(queue, *dld); | 733 | return Queue(queue, *dld); |
| 702 | } | 734 | } |
| 703 | 735 | ||
| 704 | Buffer Device::CreateBuffer(const VkBufferCreateInfo& ci) const { | ||
| 705 | VkBuffer object; | ||
| 706 | Check(dld->vkCreateBuffer(handle, &ci, nullptr, &object)); | ||
| 707 | return Buffer(object, handle, *dld); | ||
| 708 | } | ||
| 709 | |||
| 710 | BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const { | 736 | BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const { |
| 711 | VkBufferView object; | 737 | VkBufferView object; |
| 712 | Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object)); | 738 | Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object)); |
| 713 | return BufferView(object, handle, *dld); | 739 | return BufferView(object, handle, *dld); |
| 714 | } | 740 | } |
| 715 | 741 | ||
| 716 | Image Device::CreateImage(const VkImageCreateInfo& ci) const { | ||
| 717 | VkImage object; | ||
| 718 | Check(dld->vkCreateImage(handle, &ci, nullptr, &object)); | ||
| 719 | return Image(object, handle, *dld); | ||
| 720 | } | ||
| 721 | |||
| 722 | ImageView Device::CreateImageView(const VkImageViewCreateInfo& ci) const { | 742 | ImageView Device::CreateImageView(const VkImageViewCreateInfo& ci) const { |
| 723 | VkImageView object; | 743 | VkImageView object; |
| 724 | Check(dld->vkCreateImageView(handle, &ci, nullptr, &object)); | 744 | Check(dld->vkCreateImageView(handle, &ci, nullptr, &object)); |
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 4ff328a21..b5e70fcd4 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h | |||
| @@ -32,6 +32,9 @@ | |||
| 32 | #pragma warning(disable : 26812) // Disable prefer enum class over enum | 32 | #pragma warning(disable : 26812) // Disable prefer enum class over enum |
| 33 | #endif | 33 | #endif |
| 34 | 34 | ||
| 35 | VK_DEFINE_HANDLE(VmaAllocator) | ||
| 36 | VK_DEFINE_HANDLE(VmaAllocation) | ||
| 37 | |||
| 35 | namespace Vulkan::vk { | 38 | namespace Vulkan::vk { |
| 36 | 39 | ||
| 37 | /** | 40 | /** |
| @@ -161,8 +164,10 @@ struct InstanceDispatch { | |||
| 161 | PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties{}; | 164 | PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties{}; |
| 162 | 165 | ||
| 163 | PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT{}; | 166 | PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT{}; |
| 167 | PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT{}; | ||
| 164 | PFN_vkCreateDevice vkCreateDevice{}; | 168 | PFN_vkCreateDevice vkCreateDevice{}; |
| 165 | PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT{}; | 169 | PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT{}; |
| 170 | PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT{}; | ||
| 166 | PFN_vkDestroyDevice vkDestroyDevice{}; | 171 | PFN_vkDestroyDevice vkDestroyDevice{}; |
| 167 | PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR{}; | 172 | PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR{}; |
| 168 | PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties{}; | 173 | PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties{}; |
| @@ -363,6 +368,7 @@ void Destroy(VkDevice, VkSwapchainKHR, const DeviceDispatch&) noexcept; | |||
| 363 | void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept; | 368 | void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept; |
| 364 | void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept; | 369 | void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept; |
| 365 | void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept; | 370 | void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept; |
| 371 | void Destroy(VkInstance, VkDebugReportCallbackEXT, const InstanceDispatch&) noexcept; | ||
| 366 | void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept; | 372 | void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept; |
| 367 | 373 | ||
| 368 | VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept; | 374 | VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept; |
| @@ -578,6 +584,7 @@ private: | |||
| 578 | }; | 584 | }; |
| 579 | 585 | ||
| 580 | using DebugUtilsMessenger = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>; | 586 | using DebugUtilsMessenger = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>; |
| 587 | using DebugReportCallback = Handle<VkDebugReportCallbackEXT, VkInstance, InstanceDispatch>; | ||
| 581 | using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>; | 588 | using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>; |
| 582 | using DescriptorUpdateTemplate = Handle<VkDescriptorUpdateTemplate, VkDevice, DeviceDispatch>; | 589 | using DescriptorUpdateTemplate = Handle<VkDescriptorUpdateTemplate, VkDevice, DeviceDispatch>; |
| 583 | using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>; | 590 | using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>; |
| @@ -610,12 +617,149 @@ public: | |||
| 610 | DebugUtilsMessenger CreateDebugUtilsMessenger( | 617 | DebugUtilsMessenger CreateDebugUtilsMessenger( |
| 611 | const VkDebugUtilsMessengerCreateInfoEXT& create_info) const; | 618 | const VkDebugUtilsMessengerCreateInfoEXT& create_info) const; |
| 612 | 619 | ||
| 620 | /// Creates a debug report callback. | ||
| 621 | /// @throw Exception on creation failure. | ||
| 622 | DebugReportCallback CreateDebugReportCallback( | ||
| 623 | const VkDebugReportCallbackCreateInfoEXT& create_info) const; | ||
| 624 | |||
| 613 | /// Returns dispatch table. | 625 | /// Returns dispatch table. |
| 614 | const InstanceDispatch& Dispatch() const noexcept { | 626 | const InstanceDispatch& Dispatch() const noexcept { |
| 615 | return *dld; | 627 | return *dld; |
| 616 | } | 628 | } |
| 617 | }; | 629 | }; |
| 618 | 630 | ||
| 631 | class Image { | ||
| 632 | public: | ||
| 633 | explicit Image(VkImage handle_, VkDevice owner_, VmaAllocator allocator_, | ||
| 634 | VmaAllocation allocation_, const DeviceDispatch& dld_) noexcept | ||
| 635 | : handle{handle_}, owner{owner_}, allocator{allocator_}, | ||
| 636 | allocation{allocation_}, dld{&dld_} {} | ||
| 637 | Image() = default; | ||
| 638 | |||
| 639 | Image(const Image&) = delete; | ||
| 640 | Image& operator=(const Image&) = delete; | ||
| 641 | |||
| 642 | Image(Image&& rhs) noexcept | ||
| 643 | : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, allocator{rhs.allocator}, | ||
| 644 | allocation{rhs.allocation}, dld{rhs.dld} {} | ||
| 645 | |||
| 646 | Image& operator=(Image&& rhs) noexcept { | ||
| 647 | Release(); | ||
| 648 | handle = std::exchange(rhs.handle, nullptr); | ||
| 649 | owner = rhs.owner; | ||
| 650 | allocator = rhs.allocator; | ||
| 651 | allocation = rhs.allocation; | ||
| 652 | dld = rhs.dld; | ||
| 653 | return *this; | ||
| 654 | } | ||
| 655 | |||
| 656 | ~Image() noexcept { | ||
| 657 | Release(); | ||
| 658 | } | ||
| 659 | |||
| 660 | VkImage operator*() const noexcept { | ||
| 661 | return handle; | ||
| 662 | } | ||
| 663 | |||
| 664 | void reset() noexcept { | ||
| 665 | Release(); | ||
| 666 | handle = nullptr; | ||
| 667 | } | ||
| 668 | |||
| 669 | explicit operator bool() const noexcept { | ||
| 670 | return handle != nullptr; | ||
| 671 | } | ||
| 672 | |||
| 673 | void SetObjectNameEXT(const char* name) const; | ||
| 674 | |||
| 675 | private: | ||
| 676 | void Release() const noexcept; | ||
| 677 | |||
| 678 | VkImage handle = nullptr; | ||
| 679 | VkDevice owner = nullptr; | ||
| 680 | VmaAllocator allocator = nullptr; | ||
| 681 | VmaAllocation allocation = nullptr; | ||
| 682 | const DeviceDispatch* dld = nullptr; | ||
| 683 | }; | ||
| 684 | |||
| 685 | class Buffer { | ||
| 686 | public: | ||
| 687 | explicit Buffer(VkBuffer handle_, VkDevice owner_, VmaAllocator allocator_, | ||
| 688 | VmaAllocation allocation_, std::span<u8> mapped_, bool is_coherent_, | ||
| 689 | const DeviceDispatch& dld_) noexcept | ||
| 690 | : handle{handle_}, owner{owner_}, allocator{allocator_}, | ||
| 691 | allocation{allocation_}, mapped{mapped_}, is_coherent{is_coherent_}, dld{&dld_} {} | ||
| 692 | Buffer() = default; | ||
| 693 | |||
| 694 | Buffer(const Buffer&) = delete; | ||
| 695 | Buffer& operator=(const Buffer&) = delete; | ||
| 696 | |||
| 697 | Buffer(Buffer&& rhs) noexcept | ||
| 698 | : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, allocator{rhs.allocator}, | ||
| 699 | allocation{rhs.allocation}, mapped{rhs.mapped}, | ||
| 700 | is_coherent{rhs.is_coherent}, dld{rhs.dld} {} | ||
| 701 | |||
| 702 | Buffer& operator=(Buffer&& rhs) noexcept { | ||
| 703 | Release(); | ||
| 704 | handle = std::exchange(rhs.handle, nullptr); | ||
| 705 | owner = rhs.owner; | ||
| 706 | allocator = rhs.allocator; | ||
| 707 | allocation = rhs.allocation; | ||
| 708 | mapped = rhs.mapped; | ||
| 709 | is_coherent = rhs.is_coherent; | ||
| 710 | dld = rhs.dld; | ||
| 711 | return *this; | ||
| 712 | } | ||
| 713 | |||
| 714 | ~Buffer() noexcept { | ||
| 715 | Release(); | ||
| 716 | } | ||
| 717 | |||
| 718 | VkBuffer operator*() const noexcept { | ||
| 719 | return handle; | ||
| 720 | } | ||
| 721 | |||
| 722 | void reset() noexcept { | ||
| 723 | Release(); | ||
| 724 | handle = nullptr; | ||
| 725 | } | ||
| 726 | |||
| 727 | explicit operator bool() const noexcept { | ||
| 728 | return handle != nullptr; | ||
| 729 | } | ||
| 730 | |||
| 731 | /// Returns the host mapped memory, an empty span otherwise. | ||
| 732 | std::span<u8> Mapped() noexcept { | ||
| 733 | return mapped; | ||
| 734 | } | ||
| 735 | |||
| 736 | std::span<const u8> Mapped() const noexcept { | ||
| 737 | return mapped; | ||
| 738 | } | ||
| 739 | |||
| 740 | /// Returns true if the buffer is mapped to the host. | ||
| 741 | bool IsHostVisible() const noexcept { | ||
| 742 | return !mapped.empty(); | ||
| 743 | } | ||
| 744 | |||
| 745 | void Flush() const; | ||
| 746 | |||
| 747 | void Invalidate() const; | ||
| 748 | |||
| 749 | void SetObjectNameEXT(const char* name) const; | ||
| 750 | |||
| 751 | private: | ||
| 752 | void Release() const noexcept; | ||
| 753 | |||
| 754 | VkBuffer handle = nullptr; | ||
| 755 | VkDevice owner = nullptr; | ||
| 756 | VmaAllocator allocator = nullptr; | ||
| 757 | VmaAllocation allocation = nullptr; | ||
| 758 | std::span<u8> mapped = {}; | ||
| 759 | bool is_coherent = false; | ||
| 760 | const DeviceDispatch* dld = nullptr; | ||
| 761 | }; | ||
| 762 | |||
| 619 | class Queue { | 763 | class Queue { |
| 620 | public: | 764 | public: |
| 621 | /// Construct an empty queue handle. | 765 | /// Construct an empty queue handle. |
| @@ -639,17 +783,6 @@ private: | |||
| 639 | const DeviceDispatch* dld = nullptr; | 783 | const DeviceDispatch* dld = nullptr; |
| 640 | }; | 784 | }; |
| 641 | 785 | ||
| 642 | class Buffer : public Handle<VkBuffer, VkDevice, DeviceDispatch> { | ||
| 643 | using Handle<VkBuffer, VkDevice, DeviceDispatch>::Handle; | ||
| 644 | |||
| 645 | public: | ||
| 646 | /// Attaches a memory allocation. | ||
| 647 | void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; | ||
| 648 | |||
| 649 | /// Set object name. | ||
| 650 | void SetObjectNameEXT(const char* name) const; | ||
| 651 | }; | ||
| 652 | |||
| 653 | class BufferView : public Handle<VkBufferView, VkDevice, DeviceDispatch> { | 786 | class BufferView : public Handle<VkBufferView, VkDevice, DeviceDispatch> { |
| 654 | using Handle<VkBufferView, VkDevice, DeviceDispatch>::Handle; | 787 | using Handle<VkBufferView, VkDevice, DeviceDispatch>::Handle; |
| 655 | 788 | ||
| @@ -658,17 +791,6 @@ public: | |||
| 658 | void SetObjectNameEXT(const char* name) const; | 791 | void SetObjectNameEXT(const char* name) const; |
| 659 | }; | 792 | }; |
| 660 | 793 | ||
| 661 | class Image : public Handle<VkImage, VkDevice, DeviceDispatch> { | ||
| 662 | using Handle<VkImage, VkDevice, DeviceDispatch>::Handle; | ||
| 663 | |||
| 664 | public: | ||
| 665 | /// Attaches a memory allocation. | ||
| 666 | void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; | ||
| 667 | |||
| 668 | /// Set object name. | ||
| 669 | void SetObjectNameEXT(const char* name) const; | ||
| 670 | }; | ||
| 671 | |||
| 672 | class ImageView : public Handle<VkImageView, VkDevice, DeviceDispatch> { | 794 | class ImageView : public Handle<VkImageView, VkDevice, DeviceDispatch> { |
| 673 | using Handle<VkImageView, VkDevice, DeviceDispatch>::Handle; | 795 | using Handle<VkImageView, VkDevice, DeviceDispatch>::Handle; |
| 674 | 796 | ||
| @@ -840,12 +962,8 @@ public: | |||
| 840 | 962 | ||
| 841 | Queue GetQueue(u32 family_index) const noexcept; | 963 | Queue GetQueue(u32 family_index) const noexcept; |
| 842 | 964 | ||
| 843 | Buffer CreateBuffer(const VkBufferCreateInfo& ci) const; | ||
| 844 | |||
| 845 | BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; | 965 | BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; |
| 846 | 966 | ||
| 847 | Image CreateImage(const VkImageCreateInfo& ci) const; | ||
| 848 | |||
| 849 | ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; | 967 | ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; |
| 850 | 968 | ||
| 851 | Semaphore CreateSemaphore() const; | 969 | Semaphore CreateSemaphore() const; |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 733c296e4..fe98e3605 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -98,6 +98,9 @@ add_executable(yuzu | |||
| 98 | configuration/configure_input_profile_dialog.cpp | 98 | configuration/configure_input_profile_dialog.cpp |
| 99 | configuration/configure_input_profile_dialog.h | 99 | configuration/configure_input_profile_dialog.h |
| 100 | configuration/configure_input_profile_dialog.ui | 100 | configuration/configure_input_profile_dialog.ui |
| 101 | configuration/configure_mouse_panning.cpp | ||
| 102 | configuration/configure_mouse_panning.h | ||
| 103 | configuration/configure_mouse_panning.ui | ||
| 101 | configuration/configure_motion_touch.cpp | 104 | configuration/configure_motion_touch.cpp |
| 102 | configuration/configure_motion_touch.h | 105 | configuration/configure_motion_touch.h |
| 103 | configuration/configure_motion_touch.ui | 106 | configuration/configure_motion_touch.ui |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index cc6b6a25a..bdd1497b5 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -105,14 +105,12 @@ void EmuThread::run() { | |||
| 105 | std::unique_lock lk{m_should_run_mutex}; | 105 | std::unique_lock lk{m_should_run_mutex}; |
| 106 | if (m_should_run) { | 106 | if (m_should_run) { |
| 107 | m_system.Run(); | 107 | m_system.Run(); |
| 108 | m_is_running.store(true); | 108 | m_stopped.Reset(); |
| 109 | m_is_running.notify_all(); | ||
| 110 | 109 | ||
| 111 | Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] { return !m_should_run; }); | 110 | Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] { return !m_should_run; }); |
| 112 | } else { | 111 | } else { |
| 113 | m_system.Pause(); | 112 | m_system.Pause(); |
| 114 | m_is_running.store(false); | 113 | m_stopped.Set(); |
| 115 | m_is_running.notify_all(); | ||
| 116 | 114 | ||
| 117 | EmulationPaused(lk); | 115 | EmulationPaused(lk); |
| 118 | Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] { return m_should_run; }); | 116 | Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] { return m_should_run; }); |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index b7b9d4141..87b23df12 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <atomic> | ||
| 7 | #include <condition_variable> | 6 | #include <condition_variable> |
| 8 | #include <cstddef> | 7 | #include <cstddef> |
| 9 | #include <memory> | 8 | #include <memory> |
| @@ -88,7 +87,7 @@ public: | |||
| 88 | 87 | ||
| 89 | // Wait until paused, if pausing. | 88 | // Wait until paused, if pausing. |
| 90 | if (!should_run) { | 89 | if (!should_run) { |
| 91 | m_is_running.wait(true); | 90 | m_stopped.Wait(); |
| 92 | } | 91 | } |
| 93 | } | 92 | } |
| 94 | 93 | ||
| @@ -97,7 +96,7 @@ public: | |||
| 97 | * @return True if the emulation thread is running, otherwise false | 96 | * @return True if the emulation thread is running, otherwise false |
| 98 | */ | 97 | */ |
| 99 | bool IsRunning() const { | 98 | bool IsRunning() const { |
| 100 | return m_is_running.load() || m_should_run; | 99 | return m_should_run; |
| 101 | } | 100 | } |
| 102 | 101 | ||
| 103 | /** | 102 | /** |
| @@ -118,7 +117,7 @@ private: | |||
| 118 | std::stop_source m_stop_source; | 117 | std::stop_source m_stop_source; |
| 119 | std::mutex m_should_run_mutex; | 118 | std::mutex m_should_run_mutex; |
| 120 | std::condition_variable_any m_should_run_cv; | 119 | std::condition_variable_any m_should_run_cv; |
| 121 | std::atomic<bool> m_is_running{false}; | 120 | Common::Event m_stopped; |
| 122 | bool m_should_run{true}; | 121 | bool m_should_run{true}; |
| 123 | 122 | ||
| 124 | signals: | 123 | signals: |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index bac9dff90..29467d380 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -351,6 +351,10 @@ void Config::ReadPlayerValue(std::size_t player_index) { | |||
| 351 | player_motions = default_param; | 351 | player_motions = default_param; |
| 352 | } | 352 | } |
| 353 | } | 353 | } |
| 354 | |||
| 355 | if (player_index == 0) { | ||
| 356 | ReadMousePanningValues(); | ||
| 357 | } | ||
| 354 | } | 358 | } |
| 355 | 359 | ||
| 356 | void Config::ReadDebugValues() { | 360 | void Config::ReadDebugValues() { |
| @@ -471,6 +475,7 @@ void Config::ReadControlValues() { | |||
| 471 | ReadKeyboardValues(); | 475 | ReadKeyboardValues(); |
| 472 | ReadMouseValues(); | 476 | ReadMouseValues(); |
| 473 | ReadTouchscreenValues(); | 477 | ReadTouchscreenValues(); |
| 478 | ReadMousePanningValues(); | ||
| 474 | ReadMotionTouchValues(); | 479 | ReadMotionTouchValues(); |
| 475 | ReadHidbusValues(); | 480 | ReadHidbusValues(); |
| 476 | ReadIrCameraValues(); | 481 | ReadIrCameraValues(); |
| @@ -481,8 +486,6 @@ void Config::ReadControlValues() { | |||
| 481 | Settings::values.enable_raw_input = false; | 486 | Settings::values.enable_raw_input = false; |
| 482 | #endif | 487 | #endif |
| 483 | ReadBasicSetting(Settings::values.emulate_analog_keyboard); | 488 | ReadBasicSetting(Settings::values.emulate_analog_keyboard); |
| 484 | Settings::values.mouse_panning = false; | ||
| 485 | ReadBasicSetting(Settings::values.mouse_panning_sensitivity); | ||
| 486 | ReadBasicSetting(Settings::values.enable_joycon_driver); | 489 | ReadBasicSetting(Settings::values.enable_joycon_driver); |
| 487 | ReadBasicSetting(Settings::values.enable_procon_driver); | 490 | ReadBasicSetting(Settings::values.enable_procon_driver); |
| 488 | ReadBasicSetting(Settings::values.random_amiibo_id); | 491 | ReadBasicSetting(Settings::values.random_amiibo_id); |
| @@ -496,6 +499,16 @@ void Config::ReadControlValues() { | |||
| 496 | qt_config->endGroup(); | 499 | qt_config->endGroup(); |
| 497 | } | 500 | } |
| 498 | 501 | ||
| 502 | void Config::ReadMousePanningValues() { | ||
| 503 | ReadBasicSetting(Settings::values.mouse_panning); | ||
| 504 | ReadBasicSetting(Settings::values.mouse_panning_x_sensitivity); | ||
| 505 | ReadBasicSetting(Settings::values.mouse_panning_y_sensitivity); | ||
| 506 | ReadBasicSetting(Settings::values.mouse_panning_deadzone_x_counterweight); | ||
| 507 | ReadBasicSetting(Settings::values.mouse_panning_deadzone_y_counterweight); | ||
| 508 | ReadBasicSetting(Settings::values.mouse_panning_decay_strength); | ||
| 509 | ReadBasicSetting(Settings::values.mouse_panning_min_decay); | ||
| 510 | } | ||
| 511 | |||
| 499 | void Config::ReadMotionTouchValues() { | 512 | void Config::ReadMotionTouchValues() { |
| 500 | int num_touch_from_button_maps = | 513 | int num_touch_from_button_maps = |
| 501 | qt_config->beginReadArray(QStringLiteral("touch_from_button_maps")); | 514 | qt_config->beginReadArray(QStringLiteral("touch_from_button_maps")); |
| @@ -761,6 +774,7 @@ void Config::ReadRendererValues() { | |||
| 761 | ReadGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); | 774 | ReadGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); |
| 762 | ReadGlobalSetting(Settings::values.enable_compute_pipelines); | 775 | ReadGlobalSetting(Settings::values.enable_compute_pipelines); |
| 763 | ReadGlobalSetting(Settings::values.use_video_framerate); | 776 | ReadGlobalSetting(Settings::values.use_video_framerate); |
| 777 | ReadGlobalSetting(Settings::values.barrier_feedback_loops); | ||
| 764 | ReadGlobalSetting(Settings::values.bg_red); | 778 | ReadGlobalSetting(Settings::values.bg_red); |
| 765 | ReadGlobalSetting(Settings::values.bg_green); | 779 | ReadGlobalSetting(Settings::values.bg_green); |
| 766 | ReadGlobalSetting(Settings::values.bg_blue); | 780 | ReadGlobalSetting(Settings::values.bg_blue); |
| @@ -890,6 +904,7 @@ void Config::ReadUIValues() { | |||
| 890 | ReadBasicSetting(UISettings::values.pause_when_in_background); | 904 | ReadBasicSetting(UISettings::values.pause_when_in_background); |
| 891 | ReadBasicSetting(UISettings::values.mute_when_in_background); | 905 | ReadBasicSetting(UISettings::values.mute_when_in_background); |
| 892 | ReadBasicSetting(UISettings::values.hide_mouse); | 906 | ReadBasicSetting(UISettings::values.hide_mouse); |
| 907 | ReadBasicSetting(UISettings::values.controller_applet_disabled); | ||
| 893 | ReadBasicSetting(UISettings::values.disable_web_applet); | 908 | ReadBasicSetting(UISettings::values.disable_web_applet); |
| 894 | 909 | ||
| 895 | qt_config->endGroup(); | 910 | qt_config->endGroup(); |
| @@ -1063,6 +1078,10 @@ void Config::SavePlayerValue(std::size_t player_index) { | |||
| 1063 | QString::fromStdString(player.motions[i]), | 1078 | QString::fromStdString(player.motions[i]), |
| 1064 | QString::fromStdString(default_param)); | 1079 | QString::fromStdString(default_param)); |
| 1065 | } | 1080 | } |
| 1081 | |||
| 1082 | if (player_index == 0) { | ||
| 1083 | SaveMousePanningValues(); | ||
| 1084 | } | ||
| 1066 | } | 1085 | } |
| 1067 | 1086 | ||
| 1068 | void Config::SaveDebugValues() { | 1087 | void Config::SaveDebugValues() { |
| @@ -1099,6 +1118,16 @@ void Config::SaveTouchscreenValues() { | |||
| 1099 | WriteSetting(QStringLiteral("touchscreen_diameter_y"), touchscreen.diameter_y, 15); | 1118 | WriteSetting(QStringLiteral("touchscreen_diameter_y"), touchscreen.diameter_y, 15); |
| 1100 | } | 1119 | } |
| 1101 | 1120 | ||
| 1121 | void Config::SaveMousePanningValues() { | ||
| 1122 | // Don't overwrite values.mouse_panning | ||
| 1123 | WriteBasicSetting(Settings::values.mouse_panning_x_sensitivity); | ||
| 1124 | WriteBasicSetting(Settings::values.mouse_panning_y_sensitivity); | ||
| 1125 | WriteBasicSetting(Settings::values.mouse_panning_deadzone_x_counterweight); | ||
| 1126 | WriteBasicSetting(Settings::values.mouse_panning_deadzone_y_counterweight); | ||
| 1127 | WriteBasicSetting(Settings::values.mouse_panning_decay_strength); | ||
| 1128 | WriteBasicSetting(Settings::values.mouse_panning_min_decay); | ||
| 1129 | } | ||
| 1130 | |||
| 1102 | void Config::SaveMotionTouchValues() { | 1131 | void Config::SaveMotionTouchValues() { |
| 1103 | WriteBasicSetting(Settings::values.touch_device); | 1132 | WriteBasicSetting(Settings::values.touch_device); |
| 1104 | WriteBasicSetting(Settings::values.touch_from_button_map_index); | 1133 | WriteBasicSetting(Settings::values.touch_from_button_map_index); |
| @@ -1185,6 +1214,7 @@ void Config::SaveControlValues() { | |||
| 1185 | SaveDebugValues(); | 1214 | SaveDebugValues(); |
| 1186 | SaveMouseValues(); | 1215 | SaveMouseValues(); |
| 1187 | SaveTouchscreenValues(); | 1216 | SaveTouchscreenValues(); |
| 1217 | SaveMousePanningValues(); | ||
| 1188 | SaveMotionTouchValues(); | 1218 | SaveMotionTouchValues(); |
| 1189 | SaveHidbusValues(); | 1219 | SaveHidbusValues(); |
| 1190 | SaveIrCameraValues(); | 1220 | SaveIrCameraValues(); |
| @@ -1199,7 +1229,6 @@ void Config::SaveControlValues() { | |||
| 1199 | WriteBasicSetting(Settings::values.random_amiibo_id); | 1229 | WriteBasicSetting(Settings::values.random_amiibo_id); |
| 1200 | WriteBasicSetting(Settings::values.keyboard_enabled); | 1230 | WriteBasicSetting(Settings::values.keyboard_enabled); |
| 1201 | WriteBasicSetting(Settings::values.emulate_analog_keyboard); | 1231 | WriteBasicSetting(Settings::values.emulate_analog_keyboard); |
| 1202 | WriteBasicSetting(Settings::values.mouse_panning_sensitivity); | ||
| 1203 | WriteBasicSetting(Settings::values.controller_navigation); | 1232 | WriteBasicSetting(Settings::values.controller_navigation); |
| 1204 | 1233 | ||
| 1205 | WriteBasicSetting(Settings::values.tas_enable); | 1234 | WriteBasicSetting(Settings::values.tas_enable); |
| @@ -1417,6 +1446,7 @@ void Config::SaveRendererValues() { | |||
| 1417 | WriteGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); | 1446 | WriteGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); |
| 1418 | WriteGlobalSetting(Settings::values.enable_compute_pipelines); | 1447 | WriteGlobalSetting(Settings::values.enable_compute_pipelines); |
| 1419 | WriteGlobalSetting(Settings::values.use_video_framerate); | 1448 | WriteGlobalSetting(Settings::values.use_video_framerate); |
| 1449 | WriteGlobalSetting(Settings::values.barrier_feedback_loops); | ||
| 1420 | WriteGlobalSetting(Settings::values.bg_red); | 1450 | WriteGlobalSetting(Settings::values.bg_red); |
| 1421 | WriteGlobalSetting(Settings::values.bg_green); | 1451 | WriteGlobalSetting(Settings::values.bg_green); |
| 1422 | WriteGlobalSetting(Settings::values.bg_blue); | 1452 | WriteGlobalSetting(Settings::values.bg_blue); |
| @@ -1522,6 +1552,7 @@ void Config::SaveUIValues() { | |||
| 1522 | WriteBasicSetting(UISettings::values.pause_when_in_background); | 1552 | WriteBasicSetting(UISettings::values.pause_when_in_background); |
| 1523 | WriteBasicSetting(UISettings::values.mute_when_in_background); | 1553 | WriteBasicSetting(UISettings::values.mute_when_in_background); |
| 1524 | WriteBasicSetting(UISettings::values.hide_mouse); | 1554 | WriteBasicSetting(UISettings::values.hide_mouse); |
| 1555 | WriteBasicSetting(UISettings::values.controller_applet_disabled); | ||
| 1525 | WriteBasicSetting(UISettings::values.disable_web_applet); | 1556 | WriteBasicSetting(UISettings::values.disable_web_applet); |
| 1526 | 1557 | ||
| 1527 | qt_config->endGroup(); | 1558 | qt_config->endGroup(); |
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index 0fd4baf6b..1211389d2 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h | |||
| @@ -74,6 +74,7 @@ private: | |||
| 74 | void ReadKeyboardValues(); | 74 | void ReadKeyboardValues(); |
| 75 | void ReadMouseValues(); | 75 | void ReadMouseValues(); |
| 76 | void ReadTouchscreenValues(); | 76 | void ReadTouchscreenValues(); |
| 77 | void ReadMousePanningValues(); | ||
| 77 | void ReadMotionTouchValues(); | 78 | void ReadMotionTouchValues(); |
| 78 | void ReadHidbusValues(); | 79 | void ReadHidbusValues(); |
| 79 | void ReadIrCameraValues(); | 80 | void ReadIrCameraValues(); |
| @@ -104,6 +105,7 @@ private: | |||
| 104 | void SaveDebugValues(); | 105 | void SaveDebugValues(); |
| 105 | void SaveMouseValues(); | 106 | void SaveMouseValues(); |
| 106 | void SaveTouchscreenValues(); | 107 | void SaveTouchscreenValues(); |
| 108 | void SaveMousePanningValues(); | ||
| 107 | void SaveMotionTouchValues(); | 109 | void SaveMotionTouchValues(); |
| 108 | void SaveHidbusValues(); | 110 | void SaveHidbusValues(); |
| 109 | void SaveIrCameraValues(); | 111 | void SaveIrCameraValues(); |
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 26258d744..2f55159f5 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp | |||
| @@ -40,6 +40,9 @@ void ConfigureGeneral::SetConfiguration() { | |||
| 40 | ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot.GetValue()); | 40 | ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot.GetValue()); |
| 41 | ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background.GetValue()); | 41 | ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background.GetValue()); |
| 42 | ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue()); | 42 | ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue()); |
| 43 | ui->toggle_controller_applet_disabled->setEnabled(runtime_lock); | ||
| 44 | ui->toggle_controller_applet_disabled->setChecked( | ||
| 45 | UISettings::values.controller_applet_disabled.GetValue()); | ||
| 43 | 46 | ||
| 44 | ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue()); | 47 | ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue()); |
| 45 | ui->speed_limit->setValue(Settings::values.speed_limit.GetValue()); | 48 | ui->speed_limit->setValue(Settings::values.speed_limit.GetValue()); |
| @@ -82,6 +85,8 @@ void ConfigureGeneral::ApplyConfiguration() { | |||
| 82 | UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked(); | 85 | UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked(); |
| 83 | UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked(); | 86 | UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked(); |
| 84 | UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked(); | 87 | UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked(); |
| 88 | UISettings::values.controller_applet_disabled = | ||
| 89 | ui->toggle_controller_applet_disabled->isChecked(); | ||
| 85 | 90 | ||
| 86 | // Guard if during game and set to game-specific value | 91 | // Guard if during game and set to game-specific value |
| 87 | if (Settings::values.use_speed_limit.UsingGlobal()) { | 92 | if (Settings::values.use_speed_limit.UsingGlobal()) { |
| @@ -128,6 +133,7 @@ void ConfigureGeneral::SetupPerGameUI() { | |||
| 128 | ui->toggle_user_on_boot->setVisible(false); | 133 | ui->toggle_user_on_boot->setVisible(false); |
| 129 | ui->toggle_background_pause->setVisible(false); | 134 | ui->toggle_background_pause->setVisible(false); |
| 130 | ui->toggle_hide_mouse->setVisible(false); | 135 | ui->toggle_hide_mouse->setVisible(false); |
| 136 | ui->toggle_controller_applet_disabled->setVisible(false); | ||
| 131 | 137 | ||
| 132 | ui->button_reset_defaults->setVisible(false); | 138 | ui->button_reset_defaults->setVisible(false); |
| 133 | 139 | ||
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui index 986a1625b..fe757d011 100644 --- a/src/yuzu/configuration/configure_general.ui +++ b/src/yuzu/configuration/configure_general.ui | |||
| @@ -89,6 +89,13 @@ | |||
| 89 | </property> | 89 | </property> |
| 90 | </widget> | 90 | </widget> |
| 91 | </item> | 91 | </item> |
| 92 | <item> | ||
| 93 | <widget class="QCheckBox" name="toggle_controller_applet_disabled"> | ||
| 94 | <property name="text"> | ||
| 95 | <string>Disable controller applet</string> | ||
| 96 | </property> | ||
| 97 | </widget> | ||
| 98 | </item> | ||
| 92 | </layout> | 99 | </layout> |
| 93 | </item> | 100 | </item> |
| 94 | </layout> | 101 | </layout> |
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 78b487494..a4965524a 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp | |||
| @@ -508,7 +508,7 @@ void ConfigureGraphics::RetrieveVulkanDevices() { | |||
| 508 | vulkan_devices.push_back(QString::fromStdString(record.name)); | 508 | vulkan_devices.push_back(QString::fromStdString(record.name)); |
| 509 | device_present_modes.push_back(record.vsync_support); | 509 | device_present_modes.push_back(record.vsync_support); |
| 510 | 510 | ||
| 511 | if (record.is_intel_proprietary) { | 511 | if (record.has_broken_compute) { |
| 512 | expose_compute_option(); | 512 | expose_compute_option(); |
| 513 | } | 513 | } |
| 514 | } | 514 | } |
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 0463ac8b9..c0a044767 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp | |||
| @@ -43,6 +43,8 @@ void ConfigureGraphicsAdvanced::SetConfiguration() { | |||
| 43 | ui->enable_compute_pipelines_checkbox->setChecked( | 43 | ui->enable_compute_pipelines_checkbox->setChecked( |
| 44 | Settings::values.enable_compute_pipelines.GetValue()); | 44 | Settings::values.enable_compute_pipelines.GetValue()); |
| 45 | ui->use_video_framerate_checkbox->setChecked(Settings::values.use_video_framerate.GetValue()); | 45 | ui->use_video_framerate_checkbox->setChecked(Settings::values.use_video_framerate.GetValue()); |
| 46 | ui->barrier_feedback_loops_checkbox->setChecked( | ||
| 47 | Settings::values.barrier_feedback_loops.GetValue()); | ||
| 46 | 48 | ||
| 47 | if (Settings::IsConfiguringGlobal()) { | 49 | if (Settings::IsConfiguringGlobal()) { |
| 48 | ui->gpu_accuracy->setCurrentIndex( | 50 | ui->gpu_accuracy->setCurrentIndex( |
| @@ -94,6 +96,9 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() { | |||
| 94 | enable_compute_pipelines); | 96 | enable_compute_pipelines); |
| 95 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_video_framerate, | 97 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_video_framerate, |
| 96 | ui->use_video_framerate_checkbox, use_video_framerate); | 98 | ui->use_video_framerate_checkbox, use_video_framerate); |
| 99 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.barrier_feedback_loops, | ||
| 100 | ui->barrier_feedback_loops_checkbox, | ||
| 101 | barrier_feedback_loops); | ||
| 97 | } | 102 | } |
| 98 | 103 | ||
| 99 | void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) { | 104 | void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) { |
| @@ -130,6 +135,8 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { | |||
| 130 | Settings::values.enable_compute_pipelines.UsingGlobal()); | 135 | Settings::values.enable_compute_pipelines.UsingGlobal()); |
| 131 | ui->use_video_framerate_checkbox->setEnabled( | 136 | ui->use_video_framerate_checkbox->setEnabled( |
| 132 | Settings::values.use_video_framerate.UsingGlobal()); | 137 | Settings::values.use_video_framerate.UsingGlobal()); |
| 138 | ui->barrier_feedback_loops_checkbox->setEnabled( | ||
| 139 | Settings::values.barrier_feedback_loops.UsingGlobal()); | ||
| 133 | 140 | ||
| 134 | return; | 141 | return; |
| 135 | } | 142 | } |
| @@ -157,6 +164,9 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { | |||
| 157 | ConfigurationShared::SetColoredTristate(ui->use_video_framerate_checkbox, | 164 | ConfigurationShared::SetColoredTristate(ui->use_video_framerate_checkbox, |
| 158 | Settings::values.use_video_framerate, | 165 | Settings::values.use_video_framerate, |
| 159 | use_video_framerate); | 166 | use_video_framerate); |
| 167 | ConfigurationShared::SetColoredTristate(ui->barrier_feedback_loops_checkbox, | ||
| 168 | Settings::values.barrier_feedback_loops, | ||
| 169 | barrier_feedback_loops); | ||
| 160 | ConfigurationShared::SetColoredComboBox( | 170 | ConfigurationShared::SetColoredComboBox( |
| 161 | ui->gpu_accuracy, ui->label_gpu_accuracy, | 171 | ui->gpu_accuracy, ui->label_gpu_accuracy, |
| 162 | static_cast<int>(Settings::values.gpu_accuracy.GetValue(true))); | 172 | static_cast<int>(Settings::values.gpu_accuracy.GetValue(true))); |
diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h index a4dc8ceb0..369a7c83e 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.h +++ b/src/yuzu/configuration/configure_graphics_advanced.h | |||
| @@ -48,6 +48,7 @@ private: | |||
| 48 | ConfigurationShared::CheckState use_vulkan_driver_pipeline_cache; | 48 | ConfigurationShared::CheckState use_vulkan_driver_pipeline_cache; |
| 49 | ConfigurationShared::CheckState enable_compute_pipelines; | 49 | ConfigurationShared::CheckState enable_compute_pipelines; |
| 50 | ConfigurationShared::CheckState use_video_framerate; | 50 | ConfigurationShared::CheckState use_video_framerate; |
| 51 | ConfigurationShared::CheckState barrier_feedback_loops; | ||
| 51 | 52 | ||
| 52 | const Core::System& system; | 53 | const Core::System& system; |
| 53 | }; | 54 | }; |
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui index e7f0ef6be..d527a6f38 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.ui +++ b/src/yuzu/configuration/configure_graphics_advanced.ui | |||
| @@ -202,6 +202,16 @@ Compute pipelines are always enabled on all other drivers.</string> | |||
| 202 | </widget> | 202 | </widget> |
| 203 | </item> | 203 | </item> |
| 204 | <item> | 204 | <item> |
| 205 | <widget class="QCheckBox" name="barrier_feedback_loops_checkbox"> | ||
| 206 | <property name="toolTip"> | ||
| 207 | <string>Improves rendering of transparency effects in specific games.</string> | ||
| 208 | </property> | ||
| 209 | <property name="text"> | ||
| 210 | <string>Barrier feedback loops</string> | ||
| 211 | </property> | ||
| 212 | </widget> | ||
| 213 | </item> | ||
| 214 | <item> | ||
| 205 | <widget class="QWidget" name="af_layout" native="true"> | 215 | <widget class="QWidget" name="af_layout" native="true"> |
| 206 | <layout class="QHBoxLayout" name="horizontalLayout_1"> | 216 | <layout class="QHBoxLayout" name="horizontalLayout_1"> |
| 207 | <property name="leftMargin"> | 217 | <property name="leftMargin"> |
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index f13156434..3cfd5d439 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp | |||
| @@ -129,9 +129,6 @@ void ConfigureInputAdvanced::ApplyConfiguration() { | |||
| 129 | Settings::values.mouse_enabled = ui->mouse_enabled->isChecked(); | 129 | Settings::values.mouse_enabled = ui->mouse_enabled->isChecked(); |
| 130 | Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked(); | 130 | Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked(); |
| 131 | Settings::values.emulate_analog_keyboard = ui->emulate_analog_keyboard->isChecked(); | 131 | Settings::values.emulate_analog_keyboard = ui->emulate_analog_keyboard->isChecked(); |
| 132 | Settings::values.mouse_panning = ui->mouse_panning->isChecked(); | ||
| 133 | Settings::values.mouse_panning_sensitivity = | ||
| 134 | static_cast<float>(ui->mouse_panning_sensitivity->value()); | ||
| 135 | Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked(); | 132 | Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked(); |
| 136 | Settings::values.enable_raw_input = ui->enable_raw_input->isChecked(); | 133 | Settings::values.enable_raw_input = ui->enable_raw_input->isChecked(); |
| 137 | Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked(); | 134 | Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked(); |
| @@ -167,8 +164,6 @@ void ConfigureInputAdvanced::LoadConfiguration() { | |||
| 167 | ui->mouse_enabled->setChecked(Settings::values.mouse_enabled.GetValue()); | 164 | ui->mouse_enabled->setChecked(Settings::values.mouse_enabled.GetValue()); |
| 168 | ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled.GetValue()); | 165 | ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled.GetValue()); |
| 169 | ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard.GetValue()); | 166 | ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard.GetValue()); |
| 170 | ui->mouse_panning->setChecked(Settings::values.mouse_panning.GetValue()); | ||
| 171 | ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity.GetValue()); | ||
| 172 | ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled); | 167 | ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled); |
| 173 | ui->enable_raw_input->setChecked(Settings::values.enable_raw_input.GetValue()); | 168 | ui->enable_raw_input->setChecked(Settings::values.enable_raw_input.GetValue()); |
| 174 | ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue()); | 169 | ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue()); |
| @@ -197,8 +192,6 @@ void ConfigureInputAdvanced::RetranslateUI() { | |||
| 197 | void ConfigureInputAdvanced::UpdateUIEnabled() { | 192 | void ConfigureInputAdvanced::UpdateUIEnabled() { |
| 198 | ui->debug_configure->setEnabled(ui->debug_enabled->isChecked()); | 193 | ui->debug_configure->setEnabled(ui->debug_enabled->isChecked()); |
| 199 | ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked()); | 194 | ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked()); |
| 200 | ui->mouse_panning->setEnabled(!ui->mouse_enabled->isChecked()); | ||
| 201 | ui->mouse_panning_sensitivity->setEnabled(!ui->mouse_enabled->isChecked()); | ||
| 202 | ui->ring_controller_configure->setEnabled(ui->enable_ring_controller->isChecked()); | 195 | ui->ring_controller_configure->setEnabled(ui->enable_ring_controller->isChecked()); |
| 203 | #if QT_VERSION > QT_VERSION_CHECK(6, 0, 0) || !defined(YUZU_USE_QT_MULTIMEDIA) | 196 | #if QT_VERSION > QT_VERSION_CHECK(6, 0, 0) || !defined(YUZU_USE_QT_MULTIMEDIA) |
| 204 | ui->enable_ir_sensor->setEnabled(false); | 197 | ui->enable_ir_sensor->setEnabled(false); |
diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui index 2e8b13660..2994d0ab4 100644 --- a/src/yuzu/configuration/configure_input_advanced.ui +++ b/src/yuzu/configuration/configure_input_advanced.ui | |||
| @@ -2744,48 +2744,13 @@ | |||
| 2744 | </widget> | 2744 | </widget> |
| 2745 | </item> | 2745 | </item> |
| 2746 | <item row="8" column="0"> | 2746 | <item row="8" column="0"> |
| 2747 | <widget class="QCheckBox" name="mouse_panning"> | ||
| 2748 | <property name="minimumSize"> | ||
| 2749 | <size> | ||
| 2750 | <width>0</width> | ||
| 2751 | <height>23</height> | ||
| 2752 | </size> | ||
| 2753 | </property> | ||
| 2754 | <property name="text"> | ||
| 2755 | <string>Enable mouse panning</string> | ||
| 2756 | </property> | ||
| 2757 | </widget> | ||
| 2758 | </item> | ||
| 2759 | <item row="8" column="2"> | ||
| 2760 | <widget class="QSpinBox" name="mouse_panning_sensitivity"> | ||
| 2761 | <property name="toolTip"> | ||
| 2762 | <string>Mouse sensitivity</string> | ||
| 2763 | </property> | ||
| 2764 | <property name="alignment"> | ||
| 2765 | <set>Qt::AlignCenter</set> | ||
| 2766 | </property> | ||
| 2767 | <property name="suffix"> | ||
| 2768 | <string>%</string> | ||
| 2769 | </property> | ||
| 2770 | <property name="minimum"> | ||
| 2771 | <number>1</number> | ||
| 2772 | </property> | ||
| 2773 | <property name="maximum"> | ||
| 2774 | <number>100</number> | ||
| 2775 | </property> | ||
| 2776 | <property name="value"> | ||
| 2777 | <number>100</number> | ||
| 2778 | </property> | ||
| 2779 | </widget> | ||
| 2780 | </item> | ||
| 2781 | <item row="9" column="0"> | ||
| 2782 | <widget class="QLabel" name="motion_touch"> | 2747 | <widget class="QLabel" name="motion_touch"> |
| 2783 | <property name="text"> | 2748 | <property name="text"> |
| 2784 | <string>Motion / Touch</string> | 2749 | <string>Motion / Touch</string> |
| 2785 | </property> | 2750 | </property> |
| 2786 | </widget> | 2751 | </widget> |
| 2787 | </item> | 2752 | </item> |
| 2788 | <item row="9" column="2"> | 2753 | <item row="8" column="2"> |
| 2789 | <widget class="QPushButton" name="buttonMotionTouch"> | 2754 | <widget class="QPushButton" name="buttonMotionTouch"> |
| 2790 | <property name="text"> | 2755 | <property name="text"> |
| 2791 | <string>Configure</string> | 2756 | <string>Configure</string> |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 2c2e7e47b..576f5b571 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include "yuzu/configuration/config.h" | 23 | #include "yuzu/configuration/config.h" |
| 24 | #include "yuzu/configuration/configure_input_player.h" | 24 | #include "yuzu/configuration/configure_input_player.h" |
| 25 | #include "yuzu/configuration/configure_input_player_widget.h" | 25 | #include "yuzu/configuration/configure_input_player_widget.h" |
| 26 | #include "yuzu/configuration/configure_mouse_panning.h" | ||
| 26 | #include "yuzu/configuration/input_profiles.h" | 27 | #include "yuzu/configuration/input_profiles.h" |
| 27 | #include "yuzu/util/limitable_input_dialog.h" | 28 | #include "yuzu/util/limitable_input_dialog.h" |
| 28 | 29 | ||
| @@ -711,6 +712,21 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 711 | }); | 712 | }); |
| 712 | } | 713 | } |
| 713 | 714 | ||
| 715 | if (player_index_ == 0) { | ||
| 716 | connect(ui->mousePanningButton, &QPushButton::clicked, [this, input_subsystem_] { | ||
| 717 | const auto right_stick_param = | ||
| 718 | emulated_controller->GetStickParam(Settings::NativeAnalog::RStick); | ||
| 719 | ConfigureMousePanning dialog(this, input_subsystem_, | ||
| 720 | right_stick_param.Get("deadzone", 0.0f), | ||
| 721 | right_stick_param.Get("range", 1.0f)); | ||
| 722 | if (dialog.exec() == QDialog::Accepted) { | ||
| 723 | dialog.ApplyConfiguration(); | ||
| 724 | } | ||
| 725 | }); | ||
| 726 | } else { | ||
| 727 | ui->mousePanningWidget->hide(); | ||
| 728 | } | ||
| 729 | |||
| 714 | // Player Connected checkbox | 730 | // Player Connected checkbox |
| 715 | connect(ui->groupConnectedController, &QGroupBox::toggled, | 731 | connect(ui->groupConnectedController, &QGroupBox::toggled, |
| 716 | [this](bool checked) { emit Connected(checked); }); | 732 | [this](bool checked) { emit Connected(checked); }); |
diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui index a9567c6ee..43f6c7b50 100644 --- a/src/yuzu/configuration/configure_input_player.ui +++ b/src/yuzu/configuration/configure_input_player.ui | |||
| @@ -3048,6 +3048,102 @@ | |||
| 3048 | </item> | 3048 | </item> |
| 3049 | </layout> | 3049 | </layout> |
| 3050 | </item> | 3050 | </item> |
| 3051 | <item> | ||
| 3052 | <widget class="QWidget" name="mousePanningWidget" native="true"> | ||
| 3053 | <layout class="QHBoxLayout" name="mousePanningHorizontalLayout"> | ||
| 3054 | <property name="spacing"> | ||
| 3055 | <number>0</number> | ||
| 3056 | </property> | ||
| 3057 | <property name="leftMargin"> | ||
| 3058 | <number>0</number> | ||
| 3059 | </property> | ||
| 3060 | <property name="topMargin"> | ||
| 3061 | <number>0</number> | ||
| 3062 | </property> | ||
| 3063 | <property name="rightMargin"> | ||
| 3064 | <number>0</number> | ||
| 3065 | </property> | ||
| 3066 | <property name="bottomMargin"> | ||
| 3067 | <number>3</number> | ||
| 3068 | </property> | ||
| 3069 | <item> | ||
| 3070 | <spacer name="mousePanningHorizontalSpacerLeft"> | ||
| 3071 | <property name="orientation"> | ||
| 3072 | <enum>Qt::Horizontal</enum> | ||
| 3073 | </property> | ||
| 3074 | <property name="sizeHint" stdset="0"> | ||
| 3075 | <size> | ||
| 3076 | <width>20</width> | ||
| 3077 | <height>20</height> | ||
| 3078 | </size> | ||
| 3079 | </property> | ||
| 3080 | </spacer> | ||
| 3081 | </item> | ||
| 3082 | <item> | ||
| 3083 | <widget class="QGroupBox" name="mousePanningGroup"> | ||
| 3084 | <property name="title"> | ||
| 3085 | <string>Mouse panning</string> | ||
| 3086 | </property> | ||
| 3087 | <property name="alignment"> | ||
| 3088 | <set>Qt::AlignCenter</set> | ||
| 3089 | </property> | ||
| 3090 | <layout class="QVBoxLayout" name="mousePanningVerticalLayout"> | ||
| 3091 | <property name="spacing"> | ||
| 3092 | <number>3</number> | ||
| 3093 | </property> | ||
| 3094 | <property name="leftMargin"> | ||
| 3095 | <number>3</number> | ||
| 3096 | </property> | ||
| 3097 | <property name="topMargin"> | ||
| 3098 | <number>3</number> | ||
| 3099 | </property> | ||
| 3100 | <property name="rightMargin"> | ||
| 3101 | <number>3</number> | ||
| 3102 | </property> | ||
| 3103 | <property name="bottomMargin"> | ||
| 3104 | <number>3</number> | ||
| 3105 | </property> | ||
| 3106 | <item> | ||
| 3107 | <widget class="QPushButton" name="mousePanningButton"> | ||
| 3108 | <property name="minimumSize"> | ||
| 3109 | <size> | ||
| 3110 | <width>68</width> | ||
| 3111 | <height>0</height> | ||
| 3112 | </size> | ||
| 3113 | </property> | ||
| 3114 | <property name="maximumSize"> | ||
| 3115 | <size> | ||
| 3116 | <width>68</width> | ||
| 3117 | <height>16777215</height> | ||
| 3118 | </size> | ||
| 3119 | </property> | ||
| 3120 | <property name="styleSheet"> | ||
| 3121 | <string notr="true">min-width: 68px;</string> | ||
| 3122 | </property> | ||
| 3123 | <property name="text"> | ||
| 3124 | <string>Configure</string> | ||
| 3125 | </property> | ||
| 3126 | </widget> | ||
| 3127 | </item> | ||
| 3128 | </layout> | ||
| 3129 | </widget> | ||
| 3130 | </item> | ||
| 3131 | <item> | ||
| 3132 | <spacer name="mousePanningHorizontalSpacerRight"> | ||
| 3133 | <property name="orientation"> | ||
| 3134 | <enum>Qt::Horizontal</enum> | ||
| 3135 | </property> | ||
| 3136 | <property name="sizeHint" stdset="0"> | ||
| 3137 | <size> | ||
| 3138 | <width>20</width> | ||
| 3139 | <height>20</height> | ||
| 3140 | </size> | ||
| 3141 | </property> | ||
| 3142 | </spacer> | ||
| 3143 | </item> | ||
| 3144 | </layout> | ||
| 3145 | </widget> | ||
| 3146 | </item> | ||
| 3051 | </layout> | 3147 | </layout> |
| 3052 | </widget> | 3148 | </widget> |
| 3053 | </item> | 3149 | </item> |
diff --git a/src/yuzu/configuration/configure_mouse_panning.cpp b/src/yuzu/configuration/configure_mouse_panning.cpp new file mode 100644 index 000000000..f183d2740 --- /dev/null +++ b/src/yuzu/configuration/configure_mouse_panning.cpp | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <QCloseEvent> | ||
| 5 | |||
| 6 | #include "common/settings.h" | ||
| 7 | #include "ui_configure_mouse_panning.h" | ||
| 8 | #include "yuzu/configuration/configure_mouse_panning.h" | ||
| 9 | |||
| 10 | ConfigureMousePanning::ConfigureMousePanning(QWidget* parent, | ||
| 11 | InputCommon::InputSubsystem* input_subsystem_, | ||
| 12 | float right_stick_deadzone, float right_stick_range) | ||
| 13 | : QDialog(parent), input_subsystem{input_subsystem_}, | ||
| 14 | ui(std::make_unique<Ui::ConfigureMousePanning>()) { | ||
| 15 | ui->setupUi(this); | ||
| 16 | SetConfiguration(right_stick_deadzone, right_stick_range); | ||
| 17 | ConnectEvents(); | ||
| 18 | } | ||
| 19 | |||
| 20 | ConfigureMousePanning::~ConfigureMousePanning() = default; | ||
| 21 | |||
| 22 | void ConfigureMousePanning::closeEvent(QCloseEvent* event) { | ||
| 23 | event->accept(); | ||
| 24 | } | ||
| 25 | |||
| 26 | void ConfigureMousePanning::SetConfiguration(float right_stick_deadzone, float right_stick_range) { | ||
| 27 | ui->enable->setChecked(Settings::values.mouse_panning.GetValue()); | ||
| 28 | ui->x_sensitivity->setValue(Settings::values.mouse_panning_x_sensitivity.GetValue()); | ||
| 29 | ui->y_sensitivity->setValue(Settings::values.mouse_panning_y_sensitivity.GetValue()); | ||
| 30 | ui->deadzone_x_counterweight->setValue( | ||
| 31 | Settings::values.mouse_panning_deadzone_x_counterweight.GetValue()); | ||
| 32 | ui->deadzone_y_counterweight->setValue( | ||
| 33 | Settings::values.mouse_panning_deadzone_y_counterweight.GetValue()); | ||
| 34 | ui->decay_strength->setValue(Settings::values.mouse_panning_decay_strength.GetValue()); | ||
| 35 | ui->min_decay->setValue(Settings::values.mouse_panning_min_decay.GetValue()); | ||
| 36 | |||
| 37 | if (right_stick_deadzone > 0.0f || right_stick_range != 1.0f) { | ||
| 38 | ui->warning_label->setText(QString::fromStdString( | ||
| 39 | "Mouse panning works better with a deadzone of 0% and a range of 100%.\n" | ||
| 40 | "Current values are " + | ||
| 41 | std::to_string(static_cast<int>(right_stick_deadzone * 100.0f)) + "% and " + | ||
| 42 | std::to_string(static_cast<int>(right_stick_range * 100.0f)) + "% respectively.")); | ||
| 43 | } else { | ||
| 44 | ui->warning_label->hide(); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | void ConfigureMousePanning::SetDefaultConfiguration() { | ||
| 49 | ui->x_sensitivity->setValue(Settings::values.mouse_panning_x_sensitivity.GetDefault()); | ||
| 50 | ui->y_sensitivity->setValue(Settings::values.mouse_panning_y_sensitivity.GetDefault()); | ||
| 51 | ui->deadzone_x_counterweight->setValue( | ||
| 52 | Settings::values.mouse_panning_deadzone_x_counterweight.GetDefault()); | ||
| 53 | ui->deadzone_y_counterweight->setValue( | ||
| 54 | Settings::values.mouse_panning_deadzone_y_counterweight.GetDefault()); | ||
| 55 | ui->decay_strength->setValue(Settings::values.mouse_panning_decay_strength.GetDefault()); | ||
| 56 | ui->min_decay->setValue(Settings::values.mouse_panning_min_decay.GetDefault()); | ||
| 57 | } | ||
| 58 | |||
| 59 | void ConfigureMousePanning::ConnectEvents() { | ||
| 60 | connect(ui->default_button, &QPushButton::clicked, this, | ||
| 61 | &ConfigureMousePanning::SetDefaultConfiguration); | ||
| 62 | connect(ui->button_box, &QDialogButtonBox::accepted, this, | ||
| 63 | &ConfigureMousePanning::ApplyConfiguration); | ||
| 64 | connect(ui->button_box, &QDialogButtonBox::rejected, this, [this] { reject(); }); | ||
| 65 | } | ||
| 66 | |||
| 67 | void ConfigureMousePanning::ApplyConfiguration() { | ||
| 68 | Settings::values.mouse_panning = ui->enable->isChecked(); | ||
| 69 | Settings::values.mouse_panning_x_sensitivity = static_cast<float>(ui->x_sensitivity->value()); | ||
| 70 | Settings::values.mouse_panning_y_sensitivity = static_cast<float>(ui->y_sensitivity->value()); | ||
| 71 | Settings::values.mouse_panning_deadzone_x_counterweight = | ||
| 72 | static_cast<float>(ui->deadzone_x_counterweight->value()); | ||
| 73 | Settings::values.mouse_panning_deadzone_y_counterweight = | ||
| 74 | static_cast<float>(ui->deadzone_y_counterweight->value()); | ||
| 75 | Settings::values.mouse_panning_decay_strength = static_cast<float>(ui->decay_strength->value()); | ||
| 76 | Settings::values.mouse_panning_min_decay = static_cast<float>(ui->min_decay->value()); | ||
| 77 | |||
| 78 | accept(); | ||
| 79 | } | ||
diff --git a/src/yuzu/configuration/configure_mouse_panning.h b/src/yuzu/configuration/configure_mouse_panning.h new file mode 100644 index 000000000..08c6e1f62 --- /dev/null +++ b/src/yuzu/configuration/configure_mouse_panning.h | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | #include <QDialog> | ||
| 8 | |||
| 9 | namespace InputCommon { | ||
| 10 | class InputSubsystem; | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace Ui { | ||
| 14 | class ConfigureMousePanning; | ||
| 15 | } | ||
| 16 | |||
| 17 | class ConfigureMousePanning : public QDialog { | ||
| 18 | Q_OBJECT | ||
| 19 | public: | ||
| 20 | explicit ConfigureMousePanning(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_, | ||
| 21 | float right_stick_deadzone, float right_stick_range); | ||
| 22 | ~ConfigureMousePanning() override; | ||
| 23 | |||
| 24 | public slots: | ||
| 25 | void ApplyConfiguration(); | ||
| 26 | |||
| 27 | private: | ||
| 28 | void closeEvent(QCloseEvent* event) override; | ||
| 29 | void SetConfiguration(float right_stick_deadzone, float right_stick_range); | ||
| 30 | void SetDefaultConfiguration(); | ||
| 31 | void ConnectEvents(); | ||
| 32 | |||
| 33 | InputCommon::InputSubsystem* input_subsystem; | ||
| 34 | std::unique_ptr<Ui::ConfigureMousePanning> ui; | ||
| 35 | }; | ||
diff --git a/src/yuzu/configuration/configure_mouse_panning.ui b/src/yuzu/configuration/configure_mouse_panning.ui new file mode 100644 index 000000000..75795b727 --- /dev/null +++ b/src/yuzu/configuration/configure_mouse_panning.ui | |||
| @@ -0,0 +1,238 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <ui version="4.0"> | ||
| 3 | <class>ConfigureMousePanning</class> | ||
| 4 | <widget class="QDialog" name="configure_mouse_panning"> | ||
| 5 | <property name="windowTitle"> | ||
| 6 | <string>Configure mouse panning</string> | ||
| 7 | </property> | ||
| 8 | <layout class="QVBoxLayout"> | ||
| 9 | <item> | ||
| 10 | <widget class="QCheckBox" name="enable"> | ||
| 11 | <property name="text"> | ||
| 12 | <string>Enable</string> | ||
| 13 | </property> | ||
| 14 | <property name="toolTip"> | ||
| 15 | <string>Can be toggled via a hotkey</string> | ||
| 16 | </property> | ||
| 17 | </widget> | ||
| 18 | </item> | ||
| 19 | <item> | ||
| 20 | <layout class="QHBoxLayout"> | ||
| 21 | <item> | ||
| 22 | <widget class="QGroupBox" name="sensitivity_box"> | ||
| 23 | <property name="title"> | ||
| 24 | <string>Sensitivity</string> | ||
| 25 | </property> | ||
| 26 | <layout class="QGridLayout"> | ||
| 27 | <item row="0" column="0"> | ||
| 28 | <widget class="QLabel" name="x_sensitivity_label"> | ||
| 29 | <property name="text"> | ||
| 30 | <string>Horizontal</string> | ||
| 31 | </property> | ||
| 32 | </widget> | ||
| 33 | </item> | ||
| 34 | <item row="0" column="1"> | ||
| 35 | <widget class="QSpinBox" name="x_sensitivity"> | ||
| 36 | <property name="alignment"> | ||
| 37 | <set>Qt::AlignCenter</set> | ||
| 38 | </property> | ||
| 39 | <property name="suffix"> | ||
| 40 | <string>%</string> | ||
| 41 | </property> | ||
| 42 | <property name="minimum"> | ||
| 43 | <number>1</number> | ||
| 44 | </property> | ||
| 45 | <property name="maximum"> | ||
| 46 | <number>100</number> | ||
| 47 | </property> | ||
| 48 | <property name="value"> | ||
| 49 | <number>50</number> | ||
| 50 | </property> | ||
| 51 | </widget> | ||
| 52 | </item> | ||
| 53 | <item row="1" column="0"> | ||
| 54 | <widget class="QLabel" name="y_sensitivity_label"> | ||
| 55 | <property name="text"> | ||
| 56 | <string>Vertical</string> | ||
| 57 | </property> | ||
| 58 | </widget> | ||
| 59 | </item> | ||
| 60 | <item row="1" column="1"> | ||
| 61 | <widget class="QSpinBox" name="y_sensitivity"> | ||
| 62 | <property name="alignment"> | ||
| 63 | <set>Qt::AlignCenter</set> | ||
| 64 | </property> | ||
| 65 | <property name="suffix"> | ||
| 66 | <string>%</string> | ||
| 67 | </property> | ||
| 68 | <property name="minimum"> | ||
| 69 | <number>1</number> | ||
| 70 | </property> | ||
| 71 | <property name="maximum"> | ||
| 72 | <number>100</number> | ||
| 73 | </property> | ||
| 74 | <property name="value"> | ||
| 75 | <number>50</number> | ||
| 76 | </property> | ||
| 77 | </widget> | ||
| 78 | </item> | ||
| 79 | </layout> | ||
| 80 | </widget> | ||
| 81 | </item> | ||
| 82 | <item> | ||
| 83 | <widget class="QGroupBox" name="deadzone_counterweight_box"> | ||
| 84 | <property name="title"> | ||
| 85 | <string>Deadzone counterweight</string> | ||
| 86 | </property> | ||
| 87 | <property name="toolTip"> | ||
| 88 | <string>Counteracts a game's built-in deadzone</string> | ||
| 89 | </property> | ||
| 90 | <layout class="QGridLayout"> | ||
| 91 | <item row="0" column="0"> | ||
| 92 | <widget class="QLabel" name="deadzone_x_counterweight_label"> | ||
| 93 | <property name="text"> | ||
| 94 | <string>Horizontal</string> | ||
| 95 | </property> | ||
| 96 | </widget> | ||
| 97 | </item> | ||
| 98 | <item row="0" column="1"> | ||
| 99 | <widget class="QSpinBox" name="deadzone_x_counterweight"> | ||
| 100 | <property name="alignment"> | ||
| 101 | <set>Qt::AlignCenter</set> | ||
| 102 | </property> | ||
| 103 | <property name="suffix"> | ||
| 104 | <string>%</string> | ||
| 105 | </property> | ||
| 106 | <property name="minimum"> | ||
| 107 | <number>0</number> | ||
| 108 | </property> | ||
| 109 | <property name="maximum"> | ||
| 110 | <number>100</number> | ||
| 111 | </property> | ||
| 112 | <property name="value"> | ||
| 113 | <number>0</number> | ||
| 114 | </property> | ||
| 115 | </widget> | ||
| 116 | </item> | ||
| 117 | <item row="1" column="0"> | ||
| 118 | <widget class="QLabel" name="deadzone_y_counterweight_label"> | ||
| 119 | <property name="text"> | ||
| 120 | <string>Vertical</string> | ||
| 121 | </property> | ||
| 122 | </widget> | ||
| 123 | </item> | ||
| 124 | <item row="1" column="1"> | ||
| 125 | <widget class="QSpinBox" name="deadzone_y_counterweight"> | ||
| 126 | <property name="alignment"> | ||
| 127 | <set>Qt::AlignCenter</set> | ||
| 128 | </property> | ||
| 129 | <property name="suffix"> | ||
| 130 | <string>%</string> | ||
| 131 | </property> | ||
| 132 | <property name="minimum"> | ||
| 133 | <number>0</number> | ||
| 134 | </property> | ||
| 135 | <property name="maximum"> | ||
| 136 | <number>100</number> | ||
| 137 | </property> | ||
| 138 | <property name="value"> | ||
| 139 | <number>0</number> | ||
| 140 | </property> | ||
| 141 | </widget> | ||
| 142 | </item> | ||
| 143 | </layout> | ||
| 144 | </widget> | ||
| 145 | </item> | ||
| 146 | <item> | ||
| 147 | <widget class="QGroupBox" name="decay_box"> | ||
| 148 | <property name="title"> | ||
| 149 | <string>Stick decay</string> | ||
| 150 | </property> | ||
| 151 | <layout class="QGridLayout"> | ||
| 152 | <item row="0" column="0"> | ||
| 153 | <widget class="QLabel" name="decay_strength_label"> | ||
| 154 | <property name="text"> | ||
| 155 | <string>Strength</string> | ||
| 156 | </property> | ||
| 157 | </widget> | ||
| 158 | </item> | ||
| 159 | <item row="0" column="1"> | ||
| 160 | <widget class="QSpinBox" name="decay_strength"> | ||
| 161 | <property name="alignment"> | ||
| 162 | <set>Qt::AlignCenter</set> | ||
| 163 | </property> | ||
| 164 | <property name="suffix"> | ||
| 165 | <string>%</string> | ||
| 166 | </property> | ||
| 167 | <property name="minimum"> | ||
| 168 | <number>0</number> | ||
| 169 | </property> | ||
| 170 | <property name="maximum"> | ||
| 171 | <number>100</number> | ||
| 172 | </property> | ||
| 173 | <property name="value"> | ||
| 174 | <number>22</number> | ||
| 175 | </property> | ||
| 176 | </widget> | ||
| 177 | </item> | ||
| 178 | <item row="1" column="0"> | ||
| 179 | <widget class="QLabel" name="min_decay_label"> | ||
| 180 | <property name="text"> | ||
| 181 | <string>Minimum</string> | ||
| 182 | </property> | ||
| 183 | </widget> | ||
| 184 | </item> | ||
| 185 | <item row="1" column="1"> | ||
| 186 | <widget class="QSpinBox" name="min_decay"> | ||
| 187 | <property name="alignment"> | ||
| 188 | <set>Qt::AlignCenter</set> | ||
| 189 | </property> | ||
| 190 | <property name="suffix"> | ||
| 191 | <string>%</string> | ||
| 192 | </property> | ||
| 193 | <property name="minimum"> | ||
| 194 | <number>0</number> | ||
| 195 | </property> | ||
| 196 | <property name="maximum"> | ||
| 197 | <number>100</number> | ||
| 198 | </property> | ||
| 199 | <property name="value"> | ||
| 200 | <number>5</number> | ||
| 201 | </property> | ||
| 202 | </widget> | ||
| 203 | </item> | ||
| 204 | </layout> | ||
| 205 | </widget> | ||
| 206 | </item> | ||
| 207 | </layout> | ||
| 208 | </item> | ||
| 209 | <item> | ||
| 210 | <widget class="QLabel" name="warning_label"> | ||
| 211 | <property name="text"> | ||
| 212 | <string/> | ||
| 213 | </property> | ||
| 214 | </widget> | ||
| 215 | </item> | ||
| 216 | <item> | ||
| 217 | <layout class="QHBoxLayout"> | ||
| 218 | <item> | ||
| 219 | <widget class="QPushButton" name="default_button"> | ||
| 220 | <property name="text"> | ||
| 221 | <string>Default</string> | ||
| 222 | </property> | ||
| 223 | </widget> | ||
| 224 | </item> | ||
| 225 | <item> | ||
| 226 | <widget class="QDialogButtonBox" name="button_box"> | ||
| 227 | <property name="standardButtons"> | ||
| 228 | <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> | ||
| 229 | </property> | ||
| 230 | </widget> | ||
| 231 | </item> | ||
| 232 | </layout> | ||
| 233 | </item> | ||
| 234 | </layout> | ||
| 235 | </widget> | ||
| 236 | <resources/> | ||
| 237 | <connections/> | ||
| 238 | </ui> | ||
diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp index 71afbc423..f83705544 100644 --- a/src/yuzu/configuration/configure_ringcon.cpp +++ b/src/yuzu/configuration/configure_ringcon.cpp | |||
| @@ -305,6 +305,9 @@ void ConfigureRingController::EnableRingController() { | |||
| 305 | QMessageBox::warning(this, dialog_title, | 305 | QMessageBox::warning(this, dialog_title, |
| 306 | tr("The current mapped device doesn't have a ring attached")); | 306 | tr("The current mapped device doesn't have a ring attached")); |
| 307 | break; | 307 | break; |
| 308 | case Common::Input::DriverResult::InvalidHandle: | ||
| 309 | QMessageBox::warning(this, dialog_title, tr("The current mapped device is not connected")); | ||
| 310 | break; | ||
| 308 | default: | 311 | default: |
| 309 | QMessageBox::warning(this, dialog_title, | 312 | QMessageBox::warning(this, dialog_title, |
| 310 | tr("Unexpected driver result %1").arg(static_cast<int>(result))); | 313 | tr("Unexpected driver result %1").arg(static_cast<int>(result))); |
diff --git a/src/yuzu/configuration/configure_ringcon.ui b/src/yuzu/configuration/configure_ringcon.ui index 514dff372..38ecccc3d 100644 --- a/src/yuzu/configuration/configure_ringcon.ui +++ b/src/yuzu/configuration/configure_ringcon.ui | |||
| @@ -23,7 +23,7 @@ | |||
| 23 | </size> | 23 | </size> |
| 24 | </property> | 24 | </property> |
| 25 | <property name="text"> | 25 | <property name="text"> |
| 26 | <string>If you want to use this controller configure player 1 as right controller and player 2 as dual joycon before starting the game to allow this controller to be detected properly.</string> | 26 | <string>To use Ring-Con, configure player 1 as right Joy-Con (both physical and emulated), and player 2 as left Joy-Con (left physical and dual emulated) before starting the game.</string> |
| 27 | </property> | 27 | </property> |
| 28 | <property name="wordWrap"> | 28 | <property name="wordWrap"> |
| 29 | <bool>true</bool> | 29 | <bool>true</bool> |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 8768a7c3c..e8418b302 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -447,6 +447,14 @@ GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan | |||
| 447 | 447 | ||
| 448 | #if defined(HAVE_SDL2) && !defined(_WIN32) | 448 | #if defined(HAVE_SDL2) && !defined(_WIN32) |
| 449 | SDL_InitSubSystem(SDL_INIT_VIDEO); | 449 | SDL_InitSubSystem(SDL_INIT_VIDEO); |
| 450 | |||
| 451 | // Set a screensaver inhibition reason string. Currently passed to DBus by SDL and visible to | ||
| 452 | // the user through their desktop environment. | ||
| 453 | //: TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the | ||
| 454 | //: computer from sleeping | ||
| 455 | QByteArray wakelock_reason = tr("Running a game").toLatin1(); | ||
| 456 | SDL_SetHint(SDL_HINT_SCREENSAVER_INHIBIT_ACTIVITY_NAME, wakelock_reason.data()); | ||
| 457 | |||
| 450 | // SDL disables the screen saver by default, and setting the hint | 458 | // SDL disables the screen saver by default, and setting the hint |
| 451 | // SDL_HINT_VIDEO_ALLOW_SCREENSAVER doesn't seem to work, so we just enable the screen saver | 459 | // SDL_HINT_VIDEO_ALLOW_SCREENSAVER doesn't seem to work, so we just enable the screen saver |
| 452 | // for now. | 460 | // for now. |
| @@ -1623,45 +1631,6 @@ void GMainWindow::OnPrepareForSleep(bool prepare_sleep) { | |||
| 1623 | } | 1631 | } |
| 1624 | 1632 | ||
| 1625 | #ifdef __unix__ | 1633 | #ifdef __unix__ |
| 1626 | static std::optional<QDBusObjectPath> HoldWakeLockLinux(u32 window_id = 0) { | ||
| 1627 | if (!QDBusConnection::sessionBus().isConnected()) { | ||
| 1628 | return {}; | ||
| 1629 | } | ||
| 1630 | // reference: https://flatpak.github.io/xdg-desktop-portal/#gdbus-org.freedesktop.portal.Inhibit | ||
| 1631 | QDBusInterface xdp(QString::fromLatin1("org.freedesktop.portal.Desktop"), | ||
| 1632 | QString::fromLatin1("/org/freedesktop/portal/desktop"), | ||
| 1633 | QString::fromLatin1("org.freedesktop.portal.Inhibit")); | ||
| 1634 | if (!xdp.isValid()) { | ||
| 1635 | LOG_WARNING(Frontend, "Couldn't connect to XDP D-Bus endpoint"); | ||
| 1636 | return {}; | ||
| 1637 | } | ||
| 1638 | QVariantMap options = {}; | ||
| 1639 | //: TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the | ||
| 1640 | //: computer from sleeping | ||
| 1641 | options.insert(QString::fromLatin1("reason"), | ||
| 1642 | QCoreApplication::translate("GMainWindow", "yuzu is running a game")); | ||
| 1643 | // 0x4: Suspend lock; 0x8: Idle lock | ||
| 1644 | QDBusReply<QDBusObjectPath> reply = | ||
| 1645 | xdp.call(QString::fromLatin1("Inhibit"), | ||
| 1646 | QString::fromLatin1("x11:") + QString::number(window_id, 16), 12U, options); | ||
| 1647 | |||
| 1648 | if (reply.isValid()) { | ||
| 1649 | return reply.value(); | ||
| 1650 | } | ||
| 1651 | LOG_WARNING(Frontend, "Couldn't read Inhibit reply from XDP: {}", | ||
| 1652 | reply.error().message().toStdString()); | ||
| 1653 | return {}; | ||
| 1654 | } | ||
| 1655 | |||
| 1656 | static void ReleaseWakeLockLinux(QDBusObjectPath lock) { | ||
| 1657 | if (!QDBusConnection::sessionBus().isConnected()) { | ||
| 1658 | return; | ||
| 1659 | } | ||
| 1660 | QDBusInterface unlocker(QString::fromLatin1("org.freedesktop.portal.Desktop"), lock.path(), | ||
| 1661 | QString::fromLatin1("org.freedesktop.portal.Request")); | ||
| 1662 | unlocker.call(QString::fromLatin1("Close")); | ||
| 1663 | } | ||
| 1664 | |||
| 1665 | std::array<int, 3> GMainWindow::sig_interrupt_fds{0, 0, 0}; | 1634 | std::array<int, 3> GMainWindow::sig_interrupt_fds{0, 0, 0}; |
| 1666 | 1635 | ||
| 1667 | void GMainWindow::SetupSigInterrupts() { | 1636 | void GMainWindow::SetupSigInterrupts() { |
| @@ -1714,12 +1683,6 @@ void GMainWindow::PreventOSSleep() { | |||
| 1714 | SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); | 1683 | SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); |
| 1715 | #elif defined(HAVE_SDL2) | 1684 | #elif defined(HAVE_SDL2) |
| 1716 | SDL_DisableScreenSaver(); | 1685 | SDL_DisableScreenSaver(); |
| 1717 | #ifdef __unix__ | ||
| 1718 | auto reply = HoldWakeLockLinux(winId()); | ||
| 1719 | if (reply) { | ||
| 1720 | wake_lock = std::move(reply.value()); | ||
| 1721 | } | ||
| 1722 | #endif | ||
| 1723 | #endif | 1686 | #endif |
| 1724 | } | 1687 | } |
| 1725 | 1688 | ||
| @@ -1728,11 +1691,6 @@ void GMainWindow::AllowOSSleep() { | |||
| 1728 | SetThreadExecutionState(ES_CONTINUOUS); | 1691 | SetThreadExecutionState(ES_CONTINUOUS); |
| 1729 | #elif defined(HAVE_SDL2) | 1692 | #elif defined(HAVE_SDL2) |
| 1730 | SDL_EnableScreenSaver(); | 1693 | SDL_EnableScreenSaver(); |
| 1731 | #ifdef __unix__ | ||
| 1732 | if (!wake_lock.path().isEmpty()) { | ||
| 1733 | ReleaseWakeLockLinux(wake_lock); | ||
| 1734 | } | ||
| 1735 | #endif | ||
| 1736 | #endif | 1694 | #endif |
| 1737 | } | 1695 | } |
| 1738 | 1696 | ||
| @@ -1749,15 +1707,17 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p | |||
| 1749 | system->SetFilesystem(vfs); | 1707 | system->SetFilesystem(vfs); |
| 1750 | 1708 | ||
| 1751 | system->SetAppletFrontendSet({ | 1709 | system->SetAppletFrontendSet({ |
| 1752 | std::make_unique<QtAmiiboSettings>(*this), // Amiibo Settings | 1710 | std::make_unique<QtAmiiboSettings>(*this), // Amiibo Settings |
| 1753 | std::make_unique<QtControllerSelector>(*this), // Controller Selector | 1711 | (UISettings::values.controller_applet_disabled.GetValue() == true) |
| 1754 | std::make_unique<QtErrorDisplay>(*this), // Error Display | 1712 | ? nullptr |
| 1755 | nullptr, // Mii Editor | 1713 | : std::make_unique<QtControllerSelector>(*this), // Controller Selector |
| 1756 | nullptr, // Parental Controls | 1714 | std::make_unique<QtErrorDisplay>(*this), // Error Display |
| 1757 | nullptr, // Photo Viewer | 1715 | nullptr, // Mii Editor |
| 1758 | std::make_unique<QtProfileSelector>(*this), // Profile Selector | 1716 | nullptr, // Parental Controls |
| 1759 | std::make_unique<QtSoftwareKeyboard>(*this), // Software Keyboard | 1717 | nullptr, // Photo Viewer |
| 1760 | std::make_unique<QtWebBrowser>(*this), // Web Browser | 1718 | std::make_unique<QtProfileSelector>(*this), // Profile Selector |
| 1719 | std::make_unique<QtSoftwareKeyboard>(*this), // Software Keyboard | ||
| 1720 | std::make_unique<QtWebBrowser>(*this), // Web Browser | ||
| 1761 | }); | 1721 | }); |
| 1762 | 1722 | ||
| 1763 | const Core::SystemResultStatus result{ | 1723 | const Core::SystemResultStatus result{ |
| @@ -3840,7 +3800,7 @@ void GMainWindow::OnLoadAmiibo() { | |||
| 3840 | auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo(); | 3800 | auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo(); |
| 3841 | 3801 | ||
| 3842 | // Remove amiibo if one is connected | 3802 | // Remove amiibo if one is connected |
| 3843 | if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::AmiiboIsOpen) { | 3803 | if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::TagNearby) { |
| 3844 | virtual_amiibo->CloseAmiibo(); | 3804 | virtual_amiibo->CloseAmiibo(); |
| 3845 | QMessageBox::warning(this, tr("Amiibo"), tr("The current amiibo has been removed")); | 3805 | QMessageBox::warning(this, tr("Amiibo"), tr("The current amiibo has been removed")); |
| 3846 | return; | 3806 | return; |
| @@ -3868,7 +3828,7 @@ void GMainWindow::LoadAmiibo(const QString& filename) { | |||
| 3868 | auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo(); | 3828 | auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo(); |
| 3869 | const QString title = tr("Error loading Amiibo data"); | 3829 | const QString title = tr("Error loading Amiibo data"); |
| 3870 | // Remove amiibo if one is connected | 3830 | // Remove amiibo if one is connected |
| 3871 | if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::AmiiboIsOpen) { | 3831 | if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::TagNearby) { |
| 3872 | virtual_amiibo->CloseAmiibo(); | 3832 | virtual_amiibo->CloseAmiibo(); |
| 3873 | QMessageBox::warning(this, tr("Amiibo"), tr("The current amiibo has been removed")); | 3833 | QMessageBox::warning(this, tr("Amiibo"), tr("The current amiibo has been removed")); |
| 3874 | return; | 3834 | return; |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index e0e775d87..2cfb96257 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -504,8 +504,6 @@ private: | |||
| 504 | #ifdef __unix__ | 504 | #ifdef __unix__ |
| 505 | QSocketNotifier* sig_interrupt_notifier; | 505 | QSocketNotifier* sig_interrupt_notifier; |
| 506 | static std::array<int, 3> sig_interrupt_fds; | 506 | static std::array<int, 3> sig_interrupt_fds; |
| 507 | |||
| 508 | QDBusObjectPath wake_lock{}; | ||
| 509 | #endif | 507 | #endif |
| 510 | 508 | ||
| 511 | protected: | 509 | protected: |
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index db43b7033..20a517d34 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h | |||
| @@ -77,6 +77,8 @@ struct Values { | |||
| 77 | Settings::Setting<bool> pause_when_in_background{false, "pauseWhenInBackground"}; | 77 | Settings::Setting<bool> pause_when_in_background{false, "pauseWhenInBackground"}; |
| 78 | Settings::Setting<bool> mute_when_in_background{false, "muteWhenInBackground"}; | 78 | Settings::Setting<bool> mute_when_in_background{false, "muteWhenInBackground"}; |
| 79 | Settings::Setting<bool> hide_mouse{true, "hideInactiveMouse"}; | 79 | Settings::Setting<bool> hide_mouse{true, "hideInactiveMouse"}; |
| 80 | Settings::Setting<bool> controller_applet_disabled{false, "disableControllerApplet"}; | ||
| 81 | |||
| 80 | // Set when Vulkan is known to crash the application | 82 | // Set when Vulkan is known to crash the application |
| 81 | bool has_broken_vulkan = false; | 83 | bool has_broken_vulkan = false; |
| 82 | 84 | ||
diff --git a/src/yuzu/vk_device_info.cpp b/src/yuzu/vk_device_info.cpp index 9bd1ec686..7c26a3dc7 100644 --- a/src/yuzu/vk_device_info.cpp +++ b/src/yuzu/vk_device_info.cpp | |||
| @@ -5,10 +5,12 @@ | |||
| 5 | #include <vector> | 5 | #include <vector> |
| 6 | #include "common/dynamic_library.h" | 6 | #include "common/dynamic_library.h" |
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "video_core/vulkan_common/vulkan_device.h" | ||
| 8 | #include "video_core/vulkan_common/vulkan_instance.h" | 9 | #include "video_core/vulkan_common/vulkan_instance.h" |
| 9 | #include "video_core/vulkan_common/vulkan_library.h" | 10 | #include "video_core/vulkan_common/vulkan_library.h" |
| 10 | #include "video_core/vulkan_common/vulkan_surface.h" | 11 | #include "video_core/vulkan_common/vulkan_surface.h" |
| 11 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 13 | #include "vulkan/vulkan_core.h" | ||
| 12 | #include "yuzu/qt_common.h" | 14 | #include "yuzu/qt_common.h" |
| 13 | #include "yuzu/vk_device_info.h" | 15 | #include "yuzu/vk_device_info.h" |
| 14 | 16 | ||
| @@ -16,8 +18,8 @@ class QWindow; | |||
| 16 | 18 | ||
| 17 | namespace VkDeviceInfo { | 19 | namespace VkDeviceInfo { |
| 18 | Record::Record(std::string_view name_, const std::vector<VkPresentModeKHR>& vsync_modes_, | 20 | Record::Record(std::string_view name_, const std::vector<VkPresentModeKHR>& vsync_modes_, |
| 19 | bool is_intel_proprietary_) | 21 | bool has_broken_compute_) |
| 20 | : name{name_}, vsync_support{vsync_modes_}, is_intel_proprietary{is_intel_proprietary_} {} | 22 | : name{name_}, vsync_support{vsync_modes_}, has_broken_compute{has_broken_compute_} {} |
| 21 | 23 | ||
| 22 | Record::~Record() = default; | 24 | Record::~Record() = default; |
| 23 | 25 | ||
| @@ -48,9 +50,10 @@ void PopulateRecords(std::vector<Record>& records, QWindow* window) try { | |||
| 48 | properties.pNext = &driver_properties; | 50 | properties.pNext = &driver_properties; |
| 49 | dld.vkGetPhysicalDeviceProperties2(physical_device, &properties); | 51 | dld.vkGetPhysicalDeviceProperties2(physical_device, &properties); |
| 50 | 52 | ||
| 51 | records.push_back(VkDeviceInfo::Record(name, present_modes, | 53 | bool has_broken_compute{Vulkan::Device::CheckBrokenCompute( |
| 52 | driver_properties.driverID == | 54 | driver_properties.driverID, properties.properties.driverVersion)}; |
| 53 | VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS)); | 55 | |
| 56 | records.push_back(VkDeviceInfo::Record(name, present_modes, has_broken_compute)); | ||
| 54 | } | 57 | } |
| 55 | } catch (const Vulkan::vk::Exception& exception) { | 58 | } catch (const Vulkan::vk::Exception& exception) { |
| 56 | LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what()); | 59 | LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what()); |
diff --git a/src/yuzu/vk_device_info.h b/src/yuzu/vk_device_info.h index 5a6c64416..bda8262f4 100644 --- a/src/yuzu/vk_device_info.h +++ b/src/yuzu/vk_device_info.h | |||
| @@ -24,12 +24,12 @@ namespace VkDeviceInfo { | |||
| 24 | class Record { | 24 | class Record { |
| 25 | public: | 25 | public: |
| 26 | explicit Record(std::string_view name, const std::vector<VkPresentModeKHR>& vsync_modes, | 26 | explicit Record(std::string_view name, const std::vector<VkPresentModeKHR>& vsync_modes, |
| 27 | bool is_intel_proprietary); | 27 | bool has_broken_compute); |
| 28 | ~Record(); | 28 | ~Record(); |
| 29 | 29 | ||
| 30 | const std::string name; | 30 | const std::string name; |
| 31 | const std::vector<VkPresentModeKHR> vsync_support; | 31 | const std::vector<VkPresentModeKHR> vsync_support; |
| 32 | const bool is_intel_proprietary; | 32 | const bool has_broken_compute; |
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | void PopulateRecords(std::vector<Record>& records, QWindow* window); | 35 | void PopulateRecords(std::vector<Record>& records, QWindow* window); |
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index 911d461e4..119e22183 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h | |||
| @@ -140,9 +140,29 @@ udp_input_servers = | |||
| 140 | # 0 (default): Off, 1: On | 140 | # 0 (default): Off, 1: On |
| 141 | mouse_panning = | 141 | mouse_panning = |
| 142 | 142 | ||
| 143 | # Set mouse sensitivity. | 143 | # Set mouse panning horizontal sensitivity. |
| 144 | # Default: 1.0 | 144 | # Default: 50.0 |
| 145 | mouse_panning_sensitivity = | 145 | mouse_panning_x_sensitivity = |
| 146 | |||
| 147 | # Set mouse panning vertical sensitivity. | ||
| 148 | # Default: 50.0 | ||
| 149 | mouse_panning_y_sensitivity = | ||
| 150 | |||
| 151 | # Set mouse panning deadzone horizontal counterweight. | ||
| 152 | # Default: 0.0 | ||
| 153 | mouse_panning_deadzone_x_counterweight = | ||
| 154 | |||
| 155 | # Set mouse panning deadzone vertical counterweight. | ||
| 156 | # Default: 0.0 | ||
| 157 | mouse_panning_deadzone_y_counterweight = | ||
| 158 | |||
| 159 | # Set mouse panning stick decay strength. | ||
| 160 | # Default: 22.0 | ||
| 161 | mouse_panning_decay_strength = | ||
| 162 | |||
| 163 | # Set mouse panning stick minimum decay. | ||
| 164 | # Default: 5.0 | ||
| 165 | mouse_panning_minimum_decay = | ||
| 146 | 166 | ||
| 147 | # Emulate an analog control stick from keyboard inputs. | 167 | # Emulate an analog control stick from keyboard inputs. |
| 148 | # 0 (default): Disabled, 1: Enabled | 168 | # 0 (default): Disabled, 1: Enabled |