diff options
166 files changed, 2348 insertions, 1221 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d3146c9e..f5ef0ef50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -489,7 +489,7 @@ if (ENABLE_SDL2) | |||
| 489 | if (YUZU_USE_BUNDLED_SDL2) | 489 | if (YUZU_USE_BUNDLED_SDL2) |
| 490 | # Detect toolchain and platform | 490 | # Detect toolchain and platform |
| 491 | if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64) | 491 | if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64) |
| 492 | set(SDL2_VER "SDL2-2.0.18") | 492 | set(SDL2_VER "SDL2-2.28.0") |
| 493 | else() | 493 | else() |
| 494 | message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.") | 494 | message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.") |
| 495 | endif() | 495 | endif() |
| @@ -509,7 +509,7 @@ if (ENABLE_SDL2) | |||
| 509 | elseif (YUZU_USE_EXTERNAL_SDL2) | 509 | elseif (YUZU_USE_EXTERNAL_SDL2) |
| 510 | message(STATUS "Using SDL2 from externals.") | 510 | message(STATUS "Using SDL2 from externals.") |
| 511 | else() | 511 | else() |
| 512 | find_package(SDL2 2.0.18 REQUIRED) | 512 | find_package(SDL2 2.26.4 REQUIRED) |
| 513 | endif() | 513 | endif() |
| 514 | endif() | 514 | endif() |
| 515 | 515 | ||
diff --git a/externals/SDL b/externals/SDL | |||
| Subproject f17058b562c8a1090c0c996b42982721ace9090 | Subproject ffa78e6bead23e2ba3adf8ec2367ff2218d4343 | ||
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 2b63388cc..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 |
| @@ -104,6 +106,19 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 104 | inputHandler = InputHandler() | 106 | inputHandler = InputHandler() |
| 105 | inputHandler.initialize() | 107 | inputHandler.initialize() |
| 106 | 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 | |||
| 107 | // 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 |
| 108 | val startIntent = Intent(this, ForegroundService::class.java) | 123 | val startIntent = Intent(this, ForegroundService::class.java) |
| 109 | startForegroundService(startIntent) | 124 | startForegroundService(startIntent) |
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/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index cc1d87f1b..3086cfad3 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 |
| @@ -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/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/native.cpp b/src/android/app/src/main/jni/native.cpp index 6688416d6..d576aac50 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp | |||
| @@ -238,6 +238,7 @@ public: | |||
| 238 | m_software_keyboard = android_keyboard.get(); | 238 | m_software_keyboard = android_keyboard.get(); |
| 239 | m_system.SetShuttingDown(false); | 239 | m_system.SetShuttingDown(false); |
| 240 | m_system.ApplySettings(); | 240 | m_system.ApplySettings(); |
| 241 | Settings::LogSettings(); | ||
| 241 | m_system.HIDCore().ReloadInputDevices(); | 242 | m_system.HIDCore().ReloadInputDevices(); |
| 242 | m_system.SetAppletFrontendSet({ | 243 | m_system.SetAppletFrontendSet({ |
| 243 | nullptr, // Amiibo Settings | 244 | nullptr, // Amiibo Settings |
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 381dfbc3b..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> |
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..1baf6d746 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 | } |
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..ea30770ae 100644 --- a/src/common/input.h +++ b/src/common/input.h | |||
| @@ -86,7 +86,7 @@ enum class NfcState { | |||
| 86 | NewAmiibo, | 86 | NewAmiibo, |
| 87 | WaitingForAmiibo, | 87 | WaitingForAmiibo, |
| 88 | AmiiboRemoved, | 88 | AmiiboRemoved, |
| 89 | NotAnAmiibo, | 89 | InvalidTagType, |
| 90 | NotSupported, | 90 | NotSupported, |
| 91 | WrongDeviceState, | 91 | WrongDeviceState, |
| 92 | WriteFailed, | 92 | WriteFailed, |
| @@ -218,8 +218,22 @@ struct CameraStatus { | |||
| 218 | }; | 218 | }; |
| 219 | 219 | ||
| 220 | struct NfcStatus { | 220 | struct NfcStatus { |
| 221 | NfcState state{}; | 221 | NfcState state{NfcState::Unknown}; |
| 222 | std::vector<u8> data{}; | 222 | u8 uuid_length; |
| 223 | u8 protocol; | ||
| 224 | u8 tag_type; | ||
| 225 | std::array<u8, 10> uuid; | ||
| 226 | }; | ||
| 227 | |||
| 228 | struct MifareData { | ||
| 229 | u8 command; | ||
| 230 | u8 sector; | ||
| 231 | std::array<u8, 0x6> key; | ||
| 232 | std::array<u8, 0x10> data; | ||
| 233 | }; | ||
| 234 | |||
| 235 | struct MifareRequest { | ||
| 236 | std::array<MifareData, 0x10> data; | ||
| 223 | }; | 237 | }; |
| 224 | 238 | ||
| 225 | // List of buttons to be passed to Qt that can be translated | 239 | // List of buttons to be passed to Qt that can be translated |
| @@ -294,7 +308,7 @@ struct CallbackStatus { | |||
| 294 | BatteryStatus battery_status{}; | 308 | BatteryStatus battery_status{}; |
| 295 | VibrationStatus vibration_status{}; | 309 | VibrationStatus vibration_status{}; |
| 296 | CameraFormat camera_status{CameraFormat::None}; | 310 | CameraFormat camera_status{CameraFormat::None}; |
| 297 | NfcState nfc_status{NfcState::Unknown}; | 311 | NfcStatus nfc_status{}; |
| 298 | std::vector<u8> raw_data{}; | 312 | std::vector<u8> raw_data{}; |
| 299 | }; | 313 | }; |
| 300 | 314 | ||
| @@ -356,9 +370,30 @@ public: | |||
| 356 | return NfcState::NotSupported; | 370 | return NfcState::NotSupported; |
| 357 | } | 371 | } |
| 358 | 372 | ||
| 373 | virtual NfcState StartNfcPolling() { | ||
| 374 | return NfcState::NotSupported; | ||
| 375 | } | ||
| 376 | |||
| 377 | virtual NfcState StopNfcPolling() { | ||
| 378 | return NfcState::NotSupported; | ||
| 379 | } | ||
| 380 | |||
| 381 | virtual NfcState ReadAmiiboData([[maybe_unused]] std::vector<u8>& out_data) { | ||
| 382 | return NfcState::NotSupported; | ||
| 383 | } | ||
| 384 | |||
| 359 | virtual NfcState WriteNfcData([[maybe_unused]] const std::vector<u8>& data) { | 385 | virtual NfcState WriteNfcData([[maybe_unused]] const std::vector<u8>& data) { |
| 360 | return NfcState::NotSupported; | 386 | return NfcState::NotSupported; |
| 361 | } | 387 | } |
| 388 | |||
| 389 | virtual NfcState ReadMifareData([[maybe_unused]] const MifareRequest& request, | ||
| 390 | [[maybe_unused]] MifareRequest& out_data) { | ||
| 391 | return NfcState::NotSupported; | ||
| 392 | } | ||
| 393 | |||
| 394 | virtual NfcState WriteMifareData([[maybe_unused]] const MifareRequest& request) { | ||
| 395 | return NfcState::NotSupported; | ||
| 396 | } | ||
| 362 | }; | 397 | }; |
| 363 | 398 | ||
| 364 | /// An abstract class template for a factory that can create input devices. | 399 | /// 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.h b/src/common/settings.h index 9682281b0..3aedf3850 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"}; |
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/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..c998b1197 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> |
| @@ -187,6 +188,8 @@ static CPUCaps Detect() { | |||
| 187 | caps.tsc_frequency = static_cast<u64>(caps.crystal_frequency) * | 188 | caps.tsc_frequency = static_cast<u64>(caps.crystal_frequency) * |
| 188 | caps.tsc_crystal_ratio_numerator / | 189 | caps.tsc_crystal_ratio_numerator / |
| 189 | caps.tsc_crystal_ratio_denominator; | 190 | caps.tsc_crystal_ratio_denominator; |
| 191 | } else { | ||
| 192 | caps.tsc_frequency = X64::EstimateRDTSCFrequency(); | ||
| 190 | } | 193 | } |
| 191 | } | 194 | } |
| 192 | 195 | ||
diff --git a/src/common/x64/cpu_wait.cpp b/src/common/x64/cpu_wait.cpp index cfeef6a3d..c53dd4945 100644 --- a/src/common/x64/cpu_wait.cpp +++ b/src/common/x64/cpu_wait.cpp | |||
| @@ -9,19 +9,11 @@ | |||
| 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 | ||
| 15 | #ifdef _MSC_VER | 16 | #ifdef _MSC_VER |
| 16 | __forceinline static u64 FencedRDTSC() { | ||
| 17 | _mm_lfence(); | ||
| 18 | _ReadWriteBarrier(); | ||
| 19 | const u64 result = __rdtsc(); | ||
| 20 | _mm_lfence(); | ||
| 21 | _ReadWriteBarrier(); | ||
| 22 | return result; | ||
| 23 | } | ||
| 24 | |||
| 25 | __forceinline static void TPAUSE() { | 17 | __forceinline static void TPAUSE() { |
| 26 | // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. | 18 | // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. |
| 27 | // For reference: | 19 | // For reference: |
| @@ -32,16 +24,6 @@ __forceinline static void TPAUSE() { | |||
| 32 | _tpause(0, FencedRDTSC() + PauseCycles); | 24 | _tpause(0, FencedRDTSC() + PauseCycles); |
| 33 | } | 25 | } |
| 34 | #else | 26 | #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() { | 27 | static void TPAUSE() { |
| 46 | // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. | 28 | // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. |
| 47 | // For reference: | 29 | // For reference: |
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 227c431bc..3655b8478 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/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..c937495f9 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) { |
| @@ -1308,6 +1309,73 @@ bool EmulatedController::HasNfc() const { | |||
| 1308 | return is_connected && (has_virtual_nfc && is_virtual_nfc_supported); | 1309 | return is_connected && (has_virtual_nfc && is_virtual_nfc_supported); |
| 1309 | } | 1310 | } |
| 1310 | 1311 | ||
| 1312 | bool EmulatedController::AddNfcHandle() { | ||
| 1313 | nfc_handles++; | ||
| 1314 | return SetPollingMode(EmulatedDeviceIndex::RightIndex, Common::Input::PollingMode::NFC) == | ||
| 1315 | Common::Input::DriverResult::Success; | ||
| 1316 | } | ||
| 1317 | |||
| 1318 | bool EmulatedController::RemoveNfcHandle() { | ||
| 1319 | nfc_handles--; | ||
| 1320 | if (nfc_handles <= 0) { | ||
| 1321 | return SetPollingMode(EmulatedDeviceIndex::RightIndex, | ||
| 1322 | Common::Input::PollingMode::Active) == | ||
| 1323 | Common::Input::DriverResult::Success; | ||
| 1324 | } | ||
| 1325 | return true; | ||
| 1326 | } | ||
| 1327 | |||
| 1328 | bool EmulatedController::StartNfcPolling() { | ||
| 1329 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | ||
| 1330 | auto& nfc_virtual_output_device = output_devices[3]; | ||
| 1331 | |||
| 1332 | return nfc_output_device->StartNfcPolling() == Common::Input::NfcState::Success || | ||
| 1333 | nfc_virtual_output_device->StartNfcPolling() == Common::Input::NfcState::Success; | ||
| 1334 | } | ||
| 1335 | |||
| 1336 | bool EmulatedController::StopNfcPolling() { | ||
| 1337 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | ||
| 1338 | auto& nfc_virtual_output_device = output_devices[3]; | ||
| 1339 | |||
| 1340 | return nfc_output_device->StopNfcPolling() == Common::Input::NfcState::Success || | ||
| 1341 | nfc_virtual_output_device->StopNfcPolling() == Common::Input::NfcState::Success; | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) { | ||
| 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 | if (nfc_output_device->ReadAmiiboData(data) == Common::Input::NfcState::Success) { | ||
| 1349 | return true; | ||
| 1350 | } | ||
| 1351 | |||
| 1352 | return nfc_virtual_output_device->ReadAmiiboData(data) == Common::Input::NfcState::Success; | ||
| 1353 | } | ||
| 1354 | |||
| 1355 | bool EmulatedController::ReadMifareData(const Common::Input::MifareRequest& request, | ||
| 1356 | Common::Input::MifareRequest& out_data) { | ||
| 1357 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | ||
| 1358 | auto& nfc_virtual_output_device = output_devices[3]; | ||
| 1359 | |||
| 1360 | if (nfc_output_device->ReadMifareData(request, out_data) == Common::Input::NfcState::Success) { | ||
| 1361 | return true; | ||
| 1362 | } | ||
| 1363 | |||
| 1364 | return nfc_virtual_output_device->ReadMifareData(request, out_data) == | ||
| 1365 | Common::Input::NfcState::Success; | ||
| 1366 | } | ||
| 1367 | |||
| 1368 | bool EmulatedController::WriteMifareData(const Common::Input::MifareRequest& request) { | ||
| 1369 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | ||
| 1370 | auto& nfc_virtual_output_device = output_devices[3]; | ||
| 1371 | |||
| 1372 | if (nfc_output_device->WriteMifareData(request) == Common::Input::NfcState::Success) { | ||
| 1373 | return true; | ||
| 1374 | } | ||
| 1375 | |||
| 1376 | return nfc_virtual_output_device->WriteMifareData(request) == Common::Input::NfcState::Success; | ||
| 1377 | } | ||
| 1378 | |||
| 1311 | bool EmulatedController::WriteNfc(const std::vector<u8>& data) { | 1379 | bool EmulatedController::WriteNfc(const std::vector<u8>& data) { |
| 1312 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | 1380 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; |
| 1313 | auto& nfc_virtual_output_device = output_devices[3]; | 1381 | 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..52494e0d9 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp | |||
| @@ -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) { |
| @@ -291,13 +291,105 @@ Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) c | |||
| 291 | return Common::Input::NfcState::Success; | 291 | return Common::Input::NfcState::Success; |
| 292 | }; | 292 | }; |
| 293 | 293 | ||
| 294 | Common::Input::NfcState Joycons::StartNfcPolling(const PadIdentifier& identifier) { | ||
| 295 | auto handle = GetHandle(identifier); | ||
| 296 | if (handle == nullptr) { | ||
| 297 | return Common::Input::NfcState::Unknown; | ||
| 298 | } | ||
| 299 | return TranslateDriverResult(handle->StartNfcPolling()); | ||
| 300 | }; | ||
| 301 | |||
| 302 | Common::Input::NfcState Joycons::StopNfcPolling(const PadIdentifier& identifier) { | ||
| 303 | auto handle = GetHandle(identifier); | ||
| 304 | if (handle == nullptr) { | ||
| 305 | return Common::Input::NfcState::Unknown; | ||
| 306 | } | ||
| 307 | return TranslateDriverResult(handle->StopNfcPolling()); | ||
| 308 | }; | ||
| 309 | |||
| 310 | Common::Input::NfcState Joycons::ReadAmiiboData(const PadIdentifier& identifier, | ||
| 311 | std::vector<u8>& out_data) { | ||
| 312 | auto handle = GetHandle(identifier); | ||
| 313 | if (handle == nullptr) { | ||
| 314 | return Common::Input::NfcState::Unknown; | ||
| 315 | } | ||
| 316 | return TranslateDriverResult(handle->ReadAmiiboData(out_data)); | ||
| 317 | } | ||
| 318 | |||
| 294 | Common::Input::NfcState Joycons::WriteNfcData(const PadIdentifier& identifier, | 319 | Common::Input::NfcState Joycons::WriteNfcData(const PadIdentifier& identifier, |
| 295 | const std::vector<u8>& data) { | 320 | const std::vector<u8>& data) { |
| 296 | auto handle = GetHandle(identifier); | 321 | auto handle = GetHandle(identifier); |
| 297 | if (handle->WriteNfcData(data) != Joycon::DriverResult::Success) { | 322 | if (handle == nullptr) { |
| 298 | return Common::Input::NfcState::WriteFailed; | 323 | return Common::Input::NfcState::Unknown; |
| 299 | } | 324 | } |
| 300 | return Common::Input::NfcState::Success; | 325 | return TranslateDriverResult(handle->WriteNfcData(data)); |
| 326 | }; | ||
| 327 | |||
| 328 | Common::Input::NfcState Joycons::ReadMifareData(const PadIdentifier& identifier, | ||
| 329 | const Common::Input::MifareRequest& request, | ||
| 330 | Common::Input::MifareRequest& data) { | ||
| 331 | auto handle = GetHandle(identifier); | ||
| 332 | if (handle == nullptr) { | ||
| 333 | return Common::Input::NfcState::Unknown; | ||
| 334 | } | ||
| 335 | |||
| 336 | const auto command = static_cast<Joycon::MifareCmd>(request.data[0].command); | ||
| 337 | std::vector<Joycon::MifareReadChunk> read_request{}; | ||
| 338 | for (const auto& request_data : request.data) { | ||
| 339 | if (request_data.command == 0) { | ||
| 340 | continue; | ||
| 341 | } | ||
| 342 | Joycon::MifareReadChunk chunk = { | ||
| 343 | .command = command, | ||
| 344 | .sector_key = {}, | ||
| 345 | .sector = request_data.sector, | ||
| 346 | }; | ||
| 347 | memcpy(chunk.sector_key.data(), request_data.key.data(), | ||
| 348 | sizeof(Joycon::MifareReadChunk::sector_key)); | ||
| 349 | read_request.emplace_back(chunk); | ||
| 350 | } | ||
| 351 | |||
| 352 | std::vector<Joycon::MifareReadData> read_data(read_request.size()); | ||
| 353 | const auto result = handle->ReadMifareData(read_request, read_data); | ||
| 354 | if (result == Joycon::DriverResult::Success) { | ||
| 355 | for (std::size_t i = 0; i < read_request.size(); i++) { | ||
| 356 | data.data[i] = { | ||
| 357 | .command = static_cast<u8>(command), | ||
| 358 | .sector = read_data[i].sector, | ||
| 359 | .key = {}, | ||
| 360 | .data = read_data[i].data, | ||
| 361 | }; | ||
| 362 | } | ||
| 363 | } | ||
| 364 | return TranslateDriverResult(result); | ||
| 365 | }; | ||
| 366 | |||
| 367 | Common::Input::NfcState Joycons::WriteMifareData(const PadIdentifier& identifier, | ||
| 368 | const Common::Input::MifareRequest& request) { | ||
| 369 | auto handle = GetHandle(identifier); | ||
| 370 | if (handle == nullptr) { | ||
| 371 | return Common::Input::NfcState::Unknown; | ||
| 372 | } | ||
| 373 | |||
| 374 | const auto command = static_cast<Joycon::MifareCmd>(request.data[0].command); | ||
| 375 | std::vector<Joycon::MifareWriteChunk> write_request{}; | ||
| 376 | for (const auto& request_data : request.data) { | ||
| 377 | if (request_data.command == 0) { | ||
| 378 | continue; | ||
| 379 | } | ||
| 380 | Joycon::MifareWriteChunk chunk = { | ||
| 381 | .command = command, | ||
| 382 | .sector_key = {}, | ||
| 383 | .sector = request_data.sector, | ||
| 384 | .data = {}, | ||
| 385 | }; | ||
| 386 | memcpy(chunk.sector_key.data(), request_data.key.data(), | ||
| 387 | sizeof(Joycon::MifareReadChunk::sector_key)); | ||
| 388 | memcpy(chunk.data.data(), request_data.data.data(), sizeof(Joycon::MifareWriteChunk::data)); | ||
| 389 | write_request.emplace_back(chunk); | ||
| 390 | } | ||
| 391 | |||
| 392 | return TranslateDriverResult(handle->WriteMifareData(write_request)); | ||
| 301 | }; | 393 | }; |
| 302 | 394 | ||
| 303 | Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identifier, | 395 | Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identifier, |
| @@ -403,11 +495,20 @@ void Joycons::OnRingConUpdate(f32 ring_data) { | |||
| 403 | } | 495 | } |
| 404 | 496 | ||
| 405 | void Joycons::OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, | 497 | void Joycons::OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, |
| 406 | const std::vector<u8>& amiibo_data) { | 498 | const Joycon::TagInfo& tag_info) { |
| 407 | const auto identifier = GetIdentifier(port, type); | 499 | const auto identifier = GetIdentifier(port, type); |
| 408 | const auto nfc_state = amiibo_data.empty() ? Common::Input::NfcState::AmiiboRemoved | 500 | const auto nfc_state = tag_info.uuid_length == 0 ? Common::Input::NfcState::AmiiboRemoved |
| 409 | : Common::Input::NfcState::NewAmiibo; | 501 | : Common::Input::NfcState::NewAmiibo; |
| 410 | SetNfc(identifier, {nfc_state, amiibo_data}); | 502 | |
| 503 | const Common::Input::NfcStatus nfc_status{ | ||
| 504 | .state = nfc_state, | ||
| 505 | .uuid_length = tag_info.uuid_length, | ||
| 506 | .protocol = tag_info.protocol, | ||
| 507 | .tag_type = tag_info.tag_type, | ||
| 508 | .uuid = tag_info.uuid, | ||
| 509 | }; | ||
| 510 | |||
| 511 | SetNfc(identifier, nfc_status); | ||
| 411 | } | 512 | } |
| 412 | 513 | ||
| 413 | void Joycons::OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, | 514 | void Joycons::OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, |
| @@ -726,4 +827,18 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const { | |||
| 726 | return "Unknown Switch Controller"; | 827 | return "Unknown Switch Controller"; |
| 727 | } | 828 | } |
| 728 | } | 829 | } |
| 830 | |||
| 831 | Common::Input::NfcState Joycons::TranslateDriverResult(Joycon::DriverResult result) const { | ||
| 832 | switch (result) { | ||
| 833 | case Joycon::DriverResult::Success: | ||
| 834 | return Common::Input::NfcState::Success; | ||
| 835 | case Joycon::DriverResult::Disabled: | ||
| 836 | return Common::Input::NfcState::WrongDeviceState; | ||
| 837 | case Joycon::DriverResult::NotSupported: | ||
| 838 | return Common::Input::NfcState::NotSupported; | ||
| 839 | default: | ||
| 840 | return Common::Input::NfcState::Unknown; | ||
| 841 | } | ||
| 842 | } | ||
| 843 | |||
| 729 | } // namespace InputCommon | 844 | } // namespace InputCommon |
diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h index e3f0ad78f..4c323d7d6 100644 --- a/src/input_common/drivers/joycon.h +++ b/src/input_common/drivers/joycon.h | |||
| @@ -15,6 +15,7 @@ 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 DriverResult; |
| 20 | enum class IrsResolution; | 21 | enum class IrsResolution; |
| @@ -39,9 +40,18 @@ public: | |||
| 39 | Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier, | 40 | Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier, |
| 40 | Common::Input::CameraFormat camera_format) override; | 41 | Common::Input::CameraFormat camera_format) override; |
| 41 | 42 | ||
| 42 | Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; | 43 | Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier) const override; |
| 43 | Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_, | 44 | Common::Input::NfcState StartNfcPolling(const PadIdentifier& identifier) override; |
| 45 | Common::Input::NfcState StopNfcPolling(const PadIdentifier& identifier) override; | ||
| 46 | Common::Input::NfcState ReadAmiiboData(const PadIdentifier& identifier, | ||
| 47 | std::vector<u8>& out_data) override; | ||
| 48 | Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier, | ||
| 44 | const std::vector<u8>& data) override; | 49 | const std::vector<u8>& data) override; |
| 50 | Common::Input::NfcState ReadMifareData(const PadIdentifier& identifier, | ||
| 51 | const Common::Input::MifareRequest& request, | ||
| 52 | Common::Input::MifareRequest& out_data) override; | ||
| 53 | Common::Input::NfcState WriteMifareData(const PadIdentifier& identifier, | ||
| 54 | const Common::Input::MifareRequest& request) override; | ||
| 45 | 55 | ||
| 46 | Common::Input::DriverResult SetPollingMode( | 56 | Common::Input::DriverResult SetPollingMode( |
| 47 | const PadIdentifier& identifier, const Common::Input::PollingMode polling_mode) override; | 57 | const PadIdentifier& identifier, const Common::Input::PollingMode polling_mode) override; |
| @@ -82,7 +92,7 @@ private: | |||
| 82 | const Joycon::MotionData& value); | 92 | const Joycon::MotionData& value); |
| 83 | void OnRingConUpdate(f32 ring_data); | 93 | void OnRingConUpdate(f32 ring_data); |
| 84 | void OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, | 94 | void OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, |
| 85 | const std::vector<u8>& amiibo_data); | 95 | const Joycon::TagInfo& amiibo_data); |
| 86 | void OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, | 96 | void OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, |
| 87 | Joycon::IrsResolution format); | 97 | Joycon::IrsResolution format); |
| 88 | 98 | ||
| @@ -102,6 +112,8 @@ private: | |||
| 102 | /// Returns the name of the device in text format | 112 | /// Returns the name of the device in text format |
| 103 | std::string JoyconName(Joycon::ControllerType type) const; | 113 | std::string JoyconName(Joycon::ControllerType type) const; |
| 104 | 114 | ||
| 115 | Common::Input::NfcState TranslateDriverResult(Joycon::DriverResult result) const; | ||
| 116 | |||
| 105 | std::jthread scan_thread; | 117 | std::jthread scan_thread; |
| 106 | 118 | ||
| 107 | // Joycon types are split by type to ease supporting dualjoycon configurations | 119 | // Joycon types are split by type to ease supporting dualjoycon configurations |
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..2c8c66951 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.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/logging/log.h" | 4 | #include "common/logging/log.h" |
| 5 | #include "common/scope_exit.h" | ||
| 5 | #include "common/swap.h" | 6 | #include "common/swap.h" |
| 6 | #include "common/thread.h" | 7 | #include "common/thread.h" |
| 7 | #include "input_common/helpers/joycon_driver.h" | 8 | #include "input_common/helpers/joycon_driver.h" |
| @@ -112,7 +113,7 @@ DriverResult JoyconDriver::InitializeDevice() { | |||
| 112 | joycon_poller = std::make_unique<JoyconPoller>(device_type, left_stick_calibration, | 113 | joycon_poller = std::make_unique<JoyconPoller>(device_type, left_stick_calibration, |
| 113 | right_stick_calibration, motion_calibration); | 114 | right_stick_calibration, motion_calibration); |
| 114 | 115 | ||
| 115 | // Start pooling for data | 116 | // Start polling for data |
| 116 | is_connected = true; | 117 | is_connected = true; |
| 117 | if (!input_thread_running) { | 118 | if (!input_thread_running) { |
| 118 | input_thread = | 119 | input_thread = |
| @@ -208,7 +209,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { | |||
| 208 | joycon_poller->UpdateCamera(irs_protocol->GetImage(), irs_protocol->GetIrsFormat()); | 209 | joycon_poller->UpdateCamera(irs_protocol->GetImage(), irs_protocol->GetIrsFormat()); |
| 209 | } | 210 | } |
| 210 | 211 | ||
| 211 | if (nfc_protocol->IsEnabled()) { | 212 | if (nfc_protocol->IsPolling()) { |
| 212 | if (amiibo_detected) { | 213 | if (amiibo_detected) { |
| 213 | if (!nfc_protocol->HasAmiibo()) { | 214 | if (!nfc_protocol->HasAmiibo()) { |
| 214 | joycon_poller->UpdateAmiibo({}); | 215 | joycon_poller->UpdateAmiibo({}); |
| @@ -218,10 +219,10 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { | |||
| 218 | } | 219 | } |
| 219 | 220 | ||
| 220 | if (!amiibo_detected) { | 221 | if (!amiibo_detected) { |
| 221 | std::vector<u8> data(0x21C); | 222 | Joycon::TagInfo tag_info; |
| 222 | const auto result = nfc_protocol->ScanAmiibo(data); | 223 | const auto result = nfc_protocol->GetTagInfo(tag_info); |
| 223 | if (result == DriverResult::Success) { | 224 | if (result == DriverResult::Success) { |
| 224 | joycon_poller->UpdateAmiibo(data); | 225 | joycon_poller->UpdateAmiibo(tag_info); |
| 225 | amiibo_detected = true; | 226 | amiibo_detected = true; |
| 226 | } | 227 | } |
| 227 | } | 228 | } |
| @@ -247,6 +248,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { | |||
| 247 | } | 248 | } |
| 248 | 249 | ||
| 249 | DriverResult JoyconDriver::SetPollingMode() { | 250 | DriverResult JoyconDriver::SetPollingMode() { |
| 251 | SCOPE_EXIT({ disable_input_thread = false; }); | ||
| 250 | disable_input_thread = true; | 252 | disable_input_thread = true; |
| 251 | 253 | ||
| 252 | rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); | 254 | rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); |
| @@ -276,7 +278,6 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 276 | if (irs_enabled && supported_features.irs) { | 278 | if (irs_enabled && supported_features.irs) { |
| 277 | auto result = irs_protocol->EnableIrs(); | 279 | auto result = irs_protocol->EnableIrs(); |
| 278 | if (result == DriverResult::Success) { | 280 | if (result == DriverResult::Success) { |
| 279 | disable_input_thread = false; | ||
| 280 | return result; | 281 | return result; |
| 281 | } | 282 | } |
| 282 | irs_protocol->DisableIrs(); | 283 | irs_protocol->DisableIrs(); |
| @@ -286,10 +287,6 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 286 | if (nfc_enabled && supported_features.nfc) { | 287 | if (nfc_enabled && supported_features.nfc) { |
| 287 | auto result = nfc_protocol->EnableNfc(); | 288 | auto result = nfc_protocol->EnableNfc(); |
| 288 | if (result == DriverResult::Success) { | 289 | if (result == DriverResult::Success) { |
| 289 | result = nfc_protocol->StartNFCPollingMode(); | ||
| 290 | } | ||
| 291 | if (result == DriverResult::Success) { | ||
| 292 | disable_input_thread = false; | ||
| 293 | return result; | 290 | return result; |
| 294 | } | 291 | } |
| 295 | nfc_protocol->DisableNfc(); | 292 | nfc_protocol->DisableNfc(); |
| @@ -303,7 +300,6 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 303 | } | 300 | } |
| 304 | if (result == DriverResult::Success) { | 301 | if (result == DriverResult::Success) { |
| 305 | ring_connected = true; | 302 | ring_connected = true; |
| 306 | disable_input_thread = false; | ||
| 307 | return result; | 303 | return result; |
| 308 | } | 304 | } |
| 309 | ring_connected = false; | 305 | ring_connected = false; |
| @@ -314,7 +310,6 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 314 | if (passive_enabled && supported_features.passive) { | 310 | if (passive_enabled && supported_features.passive) { |
| 315 | const auto result = generic_protocol->EnablePassiveMode(); | 311 | const auto result = generic_protocol->EnablePassiveMode(); |
| 316 | if (result == DriverResult::Success) { | 312 | if (result == DriverResult::Success) { |
| 317 | disable_input_thread = false; | ||
| 318 | return result; | 313 | return result; |
| 319 | } | 314 | } |
| 320 | LOG_ERROR(Input, "Error enabling passive mode"); | 315 | LOG_ERROR(Input, "Error enabling passive mode"); |
| @@ -328,7 +323,6 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 328 | // Switch calls this function after enabling active mode | 323 | // Switch calls this function after enabling active mode |
| 329 | generic_protocol->TriggersElapsed(); | 324 | generic_protocol->TriggersElapsed(); |
| 330 | 325 | ||
| 331 | disable_input_thread = false; | ||
| 332 | return result; | 326 | return result; |
| 333 | } | 327 | } |
| 334 | 328 | ||
| @@ -492,9 +486,63 @@ DriverResult JoyconDriver::SetRingConMode() { | |||
| 492 | return result; | 486 | return result; |
| 493 | } | 487 | } |
| 494 | 488 | ||
| 495 | DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) { | 489 | DriverResult JoyconDriver::StartNfcPolling() { |
| 496 | std::scoped_lock lock{mutex}; | 490 | std::scoped_lock lock{mutex}; |
| 491 | |||
| 492 | if (!supported_features.nfc) { | ||
| 493 | return DriverResult::NotSupported; | ||
| 494 | } | ||
| 495 | if (!nfc_protocol->IsEnabled()) { | ||
| 496 | return DriverResult::Disabled; | ||
| 497 | } | ||
| 498 | |||
| 499 | disable_input_thread = true; | ||
| 500 | const auto result = nfc_protocol->StartNFCPollingMode(); | ||
| 501 | disable_input_thread = false; | ||
| 502 | |||
| 503 | return result; | ||
| 504 | } | ||
| 505 | |||
| 506 | DriverResult JoyconDriver::StopNfcPolling() { | ||
| 507 | std::scoped_lock lock{mutex}; | ||
| 508 | |||
| 509 | if (!supported_features.nfc) { | ||
| 510 | return DriverResult::NotSupported; | ||
| 511 | } | ||
| 512 | if (!nfc_protocol->IsEnabled()) { | ||
| 513 | return DriverResult::Disabled; | ||
| 514 | } | ||
| 515 | |||
| 516 | disable_input_thread = true; | ||
| 517 | const auto result = nfc_protocol->StopNFCPollingMode(); | ||
| 518 | disable_input_thread = false; | ||
| 519 | |||
| 520 | return result; | ||
| 521 | } | ||
| 522 | |||
| 523 | DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) { | ||
| 524 | std::scoped_lock lock{mutex}; | ||
| 525 | |||
| 526 | if (!supported_features.nfc) { | ||
| 527 | return DriverResult::NotSupported; | ||
| 528 | } | ||
| 529 | if (!nfc_protocol->IsEnabled()) { | ||
| 530 | return DriverResult::Disabled; | ||
| 531 | } | ||
| 532 | if (!amiibo_detected) { | ||
| 533 | return DriverResult::ErrorWritingData; | ||
| 534 | } | ||
| 535 | |||
| 536 | out_data.resize(0x21C); | ||
| 497 | disable_input_thread = true; | 537 | disable_input_thread = true; |
| 538 | const auto result = nfc_protocol->ReadAmiibo(out_data); | ||
| 539 | disable_input_thread = false; | ||
| 540 | |||
| 541 | return result; | ||
| 542 | } | ||
| 543 | |||
| 544 | DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) { | ||
| 545 | std::scoped_lock lock{mutex}; | ||
| 498 | 546 | ||
| 499 | if (!supported_features.nfc) { | 547 | if (!supported_features.nfc) { |
| 500 | return DriverResult::NotSupported; | 548 | return DriverResult::NotSupported; |
| @@ -506,9 +554,51 @@ DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) { | |||
| 506 | return DriverResult::ErrorWritingData; | 554 | return DriverResult::ErrorWritingData; |
| 507 | } | 555 | } |
| 508 | 556 | ||
| 557 | disable_input_thread = true; | ||
| 509 | const auto result = nfc_protocol->WriteAmiibo(data); | 558 | const auto result = nfc_protocol->WriteAmiibo(data); |
| 559 | disable_input_thread = false; | ||
| 510 | 560 | ||
| 561 | return result; | ||
| 562 | } | ||
| 563 | |||
| 564 | DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data, | ||
| 565 | std::span<MifareReadData> out_data) { | ||
| 566 | std::scoped_lock lock{mutex}; | ||
| 567 | |||
| 568 | if (!supported_features.nfc) { | ||
| 569 | return DriverResult::NotSupported; | ||
| 570 | } | ||
| 571 | if (!nfc_protocol->IsEnabled()) { | ||
| 572 | return DriverResult::Disabled; | ||
| 573 | } | ||
| 574 | if (!amiibo_detected) { | ||
| 575 | return DriverResult::ErrorWritingData; | ||
| 576 | } | ||
| 577 | |||
| 578 | disable_input_thread = true; | ||
| 579 | const auto result = nfc_protocol->ReadMifare(data, out_data); | ||
| 580 | disable_input_thread = false; | ||
| 581 | |||
| 582 | return result; | ||
| 583 | } | ||
| 584 | |||
| 585 | DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) { | ||
| 586 | std::scoped_lock lock{mutex}; | ||
| 587 | |||
| 588 | if (!supported_features.nfc) { | ||
| 589 | return DriverResult::NotSupported; | ||
| 590 | } | ||
| 591 | if (!nfc_protocol->IsEnabled()) { | ||
| 592 | return DriverResult::Disabled; | ||
| 593 | } | ||
| 594 | if (!amiibo_detected) { | ||
| 595 | return DriverResult::ErrorWritingData; | ||
| 596 | } | ||
| 597 | |||
| 598 | disable_input_thread = true; | ||
| 599 | const auto result = nfc_protocol->WriteMifare(data); | ||
| 511 | disable_input_thread = false; | 600 | disable_input_thread = false; |
| 601 | |||
| 512 | return result; | 602 | return result; |
| 513 | } | 603 | } |
| 514 | 604 | ||
diff --git a/src/input_common/helpers/joycon_driver.h b/src/input_common/helpers/joycon_driver.h index e9b2fccbb..bc7025a21 100644 --- a/src/input_common/helpers/joycon_driver.h +++ b/src/input_common/helpers/joycon_driver.h | |||
| @@ -49,7 +49,13 @@ public: | |||
| 49 | DriverResult SetIrMode(); | 49 | DriverResult SetIrMode(); |
| 50 | DriverResult SetNfcMode(); | 50 | DriverResult SetNfcMode(); |
| 51 | DriverResult SetRingConMode(); | 51 | DriverResult SetRingConMode(); |
| 52 | DriverResult StartNfcPolling(); | ||
| 53 | DriverResult StopNfcPolling(); | ||
| 54 | DriverResult ReadAmiiboData(std::vector<u8>& out_data); | ||
| 52 | DriverResult WriteNfcData(std::span<const u8> data); | 55 | DriverResult WriteNfcData(std::span<const u8> data); |
| 56 | DriverResult ReadMifareData(std::span<const MifareReadChunk> request, | ||
| 57 | std::span<MifareReadData> out_data); | ||
| 58 | DriverResult WriteMifareData(std::span<const MifareWriteChunk> request); | ||
| 53 | 59 | ||
| 54 | void SetCallbacks(const JoyconCallbacks& callbacks); | 60 | void SetCallbacks(const JoyconCallbacks& callbacks); |
| 55 | 61 | ||
diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h index 5007b0e18..e0e431156 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 { |
| @@ -592,6 +606,14 @@ struct NFCWriteCommandData { | |||
| 592 | static_assert(sizeof(NFCWriteCommandData) == 0x15, "NFCWriteCommandData is an invalid size"); | 606 | static_assert(sizeof(NFCWriteCommandData) == 0x15, "NFCWriteCommandData is an invalid size"); |
| 593 | #pragma pack(pop) | 607 | #pragma pack(pop) |
| 594 | 608 | ||
| 609 | struct MifareCommandData { | ||
| 610 | u8 unknown1; | ||
| 611 | u8 unknown2; | ||
| 612 | u8 number_of_short_bytes; | ||
| 613 | MifareUUID uid; | ||
| 614 | }; | ||
| 615 | static_assert(sizeof(MifareCommandData) == 0x7, "MifareCommandData is an invalid size"); | ||
| 616 | |||
| 595 | struct NFCPollingCommandData { | 617 | struct NFCPollingCommandData { |
| 596 | u8 enable_mifare; | 618 | u8 enable_mifare; |
| 597 | u8 unknown_1; | 619 | u8 unknown_1; |
| @@ -629,6 +651,41 @@ struct NFCWritePackage { | |||
| 629 | std::array<NFCDataChunk, 4> data_chunks; | 651 | std::array<NFCDataChunk, 4> data_chunks; |
| 630 | }; | 652 | }; |
| 631 | 653 | ||
| 654 | struct MifareReadChunk { | ||
| 655 | MifareCmd command; | ||
| 656 | std::array<u8, 0x6> sector_key; | ||
| 657 | u8 sector; | ||
| 658 | }; | ||
| 659 | |||
| 660 | struct MifareWriteChunk { | ||
| 661 | MifareCmd command; | ||
| 662 | std::array<u8, 0x6> sector_key; | ||
| 663 | u8 sector; | ||
| 664 | std::array<u8, 0x10> data; | ||
| 665 | }; | ||
| 666 | |||
| 667 | struct MifareReadData { | ||
| 668 | u8 sector; | ||
| 669 | std::array<u8, 0x10> data; | ||
| 670 | }; | ||
| 671 | |||
| 672 | struct MifareReadPackage { | ||
| 673 | MifareCommandData command_data; | ||
| 674 | std::array<MifareReadChunk, 0x10> data_chunks; | ||
| 675 | }; | ||
| 676 | |||
| 677 | struct MifareWritePackage { | ||
| 678 | MifareCommandData command_data; | ||
| 679 | std::array<MifareWriteChunk, 0x10> data_chunks; | ||
| 680 | }; | ||
| 681 | |||
| 682 | struct TagInfo { | ||
| 683 | u8 uuid_length; | ||
| 684 | u8 protocol; | ||
| 685 | u8 tag_type; | ||
| 686 | std::array<u8, 10> uuid; | ||
| 687 | }; | ||
| 688 | |||
| 632 | struct IrsConfigure { | 689 | struct IrsConfigure { |
| 633 | MCUCommand command; | 690 | MCUCommand command; |
| 634 | MCUSubCommand sub_command; | 691 | MCUSubCommand sub_command; |
| @@ -744,7 +801,7 @@ struct JoyconCallbacks { | |||
| 744 | std::function<void(int, f32)> on_stick_data; | 801 | std::function<void(int, f32)> on_stick_data; |
| 745 | std::function<void(int, const MotionData&)> on_motion_data; | 802 | std::function<void(int, const MotionData&)> on_motion_data; |
| 746 | std::function<void(f32)> on_ring_data; | 803 | std::function<void(f32)> on_ring_data; |
| 747 | std::function<void(const std::vector<u8>&)> on_amiibo_data; | 804 | std::function<void(const Joycon::TagInfo&)> on_amiibo_data; |
| 748 | std::function<void(const std::vector<u8>&, IrsResolution)> on_camera_data; | 805 | std::function<void(const std::vector<u8>&, IrsResolution)> on_camera_data; |
| 749 | }; | 806 | }; |
| 750 | 807 | ||
diff --git a/src/input_common/helpers/joycon_protocol/nfc.cpp b/src/input_common/helpers/joycon_protocol/nfc.cpp index f7058c4a7..261f46255 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.cpp +++ b/src/input_common/helpers/joycon_protocol/nfc.cpp | |||
| @@ -40,6 +40,16 @@ DriverResult NfcProtocol::EnableNfc() { | |||
| 40 | if (result == DriverResult::Success) { | 40 | if (result == DriverResult::Success) { |
| 41 | result = WaitUntilNfcIs(NFCStatus::Ready); | 41 | result = WaitUntilNfcIs(NFCStatus::Ready); |
| 42 | } | 42 | } |
| 43 | if (result == DriverResult::Success) { | ||
| 44 | MCUCommandResponse output{}; | ||
| 45 | result = SendStopPollingRequest(output); | ||
| 46 | } | ||
| 47 | if (result == DriverResult::Success) { | ||
| 48 | result = WaitUntilNfcIs(NFCStatus::Ready); | ||
| 49 | } | ||
| 50 | if (result == DriverResult::Success) { | ||
| 51 | is_enabled = true; | ||
| 52 | } | ||
| 43 | 53 | ||
| 44 | return result; | 54 | return result; |
| 45 | } | 55 | } |
| @@ -54,37 +64,50 @@ DriverResult NfcProtocol::DisableNfc() { | |||
| 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 | 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 | DriverResult result{DriverResult::Success}; |
| 65 | 76 | ||
| 66 | if (result == DriverResult::Success) { | 77 | if (result == 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 == DriverResult::Success) { |
| 71 | result = WaitUntilNfcIs(NFCStatus::Ready); | 82 | result = WaitUntilNfcIs(NFCStatus::Polling); |
| 72 | } | 83 | } |
| 73 | if (result == DriverResult::Success) { | 84 | if (result == DriverResult::Success) { |
| 85 | is_polling = true; | ||
| 86 | } | ||
| 87 | |||
| 88 | return result; | ||
| 89 | } | ||
| 90 | |||
| 91 | DriverResult NfcProtocol::StopNFCPollingMode() { | ||
| 92 | LOG_DEBUG(Input, "Stop NFC polling Mode"); | ||
| 93 | ScopedSetBlocking sb(this); | ||
| 94 | DriverResult result{DriverResult::Success}; | ||
| 95 | |||
| 96 | if (result == 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 == DriverResult::Success) { |
| 78 | result = WaitUntilNfcIs(NFCStatus::Polling); | 101 | result = WaitUntilNfcIs(NFCStatus::WriteReady); |
| 79 | } | 102 | } |
| 80 | if (result == DriverResult::Success) { | 103 | if (result == 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 | 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 DriverResult::Delayed; |
| 90 | } | 113 | } |
| @@ -100,11 +123,41 @@ DriverResult NfcProtocol::ScanAmiibo(std::vector<u8>& data) { | |||
| 100 | } | 123 | } |
| 101 | 124 | ||
| 102 | if (result == DriverResult::Success) { | 125 | if (result == 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 | DriverResult NfcProtocol::ReadAmiibo(std::vector<u8>& data) { | ||
| 151 | LOG_DEBUG(Input, "Scan for amiibos"); | ||
| 152 | ScopedSetBlocking sb(this); | ||
| 153 | DriverResult result{DriverResult::Success}; | ||
| 154 | TagFoundData tag_data{}; | ||
| 155 | |||
| 156 | if (result == DriverResult::Success) { | ||
| 157 | result = IsTagInRange(tag_data, 7); | ||
| 158 | } | ||
| 159 | |||
| 160 | if (result == DriverResult::Success) { | ||
| 108 | result = GetAmiiboData(data); | 161 | result = GetAmiiboData(data); |
| 109 | } | 162 | } |
| 110 | 163 | ||
| @@ -154,6 +207,69 @@ DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) { | |||
| 154 | return result; | 207 | return result; |
| 155 | } | 208 | } |
| 156 | 209 | ||
| 210 | 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 | DriverResult result{DriverResult::Success}; | ||
| 215 | TagFoundData tag_data{}; | ||
| 216 | MifareUUID tag_uuid{}; | ||
| 217 | |||
| 218 | if (result == DriverResult::Success) { | ||
| 219 | result = IsTagInRange(tag_data, 7); | ||
| 220 | } | ||
| 221 | if (result == 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 == DriverResult::Success) { | ||
| 226 | MCUCommandResponse output{}; | ||
| 227 | result = SendStopPollingRequest(output); | ||
| 228 | } | ||
| 229 | if (result == DriverResult::Success) { | ||
| 230 | result = WaitUntilNfcIs(NFCStatus::Ready); | ||
| 231 | } | ||
| 232 | if (result == DriverResult::Success) { | ||
| 233 | MCUCommandResponse output{}; | ||
| 234 | result = SendStartPollingRequest(output, true); | ||
| 235 | } | ||
| 236 | if (result == DriverResult::Success) { | ||
| 237 | result = WaitUntilNfcIs(NFCStatus::WriteReady); | ||
| 238 | } | ||
| 239 | return result; | ||
| 240 | } | ||
| 241 | |||
| 242 | DriverResult NfcProtocol::WriteMifare(std::span<const MifareWriteChunk> write_request) { | ||
| 243 | LOG_DEBUG(Input, "Write mifare"); | ||
| 244 | ScopedSetBlocking sb(this); | ||
| 245 | DriverResult result{DriverResult::Success}; | ||
| 246 | TagFoundData tag_data{}; | ||
| 247 | MifareUUID tag_uuid{}; | ||
| 248 | |||
| 249 | if (result == DriverResult::Success) { | ||
| 250 | result = IsTagInRange(tag_data, 7); | ||
| 251 | } | ||
| 252 | if (result == DriverResult::Success) { | ||
| 253 | memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID)); | ||
| 254 | result = WriteMifareData(tag_uuid, write_request); | ||
| 255 | } | ||
| 256 | if (result == DriverResult::Success) { | ||
| 257 | MCUCommandResponse output{}; | ||
| 258 | result = SendStopPollingRequest(output); | ||
| 259 | } | ||
| 260 | if (result == DriverResult::Success) { | ||
| 261 | result = WaitUntilNfcIs(NFCStatus::Ready); | ||
| 262 | } | ||
| 263 | if (result == DriverResult::Success) { | ||
| 264 | MCUCommandResponse output{}; | ||
| 265 | result = SendStartPollingRequest(output, true); | ||
| 266 | } | ||
| 267 | if (result == DriverResult::Success) { | ||
| 268 | result = WaitUntilNfcIs(NFCStatus::WriteReady); | ||
| 269 | } | ||
| 270 | return result; | ||
| 271 | } | ||
| 272 | |||
| 157 | bool NfcProtocol::HasAmiibo() { | 273 | bool NfcProtocol::HasAmiibo() { |
| 158 | if (update_counter++ < AMIIBO_UPDATE_DELAY) { | 274 | if (update_counter++ < AMIIBO_UPDATE_DELAY) { |
| 159 | return true; | 275 | return true; |
| @@ -341,6 +457,158 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con | |||
| 341 | return result; | 457 | return result; |
| 342 | } | 458 | } |
| 343 | 459 | ||
| 460 | DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid, | ||
| 461 | std::span<const MifareReadChunk> read_request, | ||
| 462 | std::span<MifareReadData> out_data) { | ||
| 463 | constexpr std::size_t timeout_limit = 60; | ||
| 464 | const auto nfc_data = MakeMifareReadPackage(tag_uuid, read_request); | ||
| 465 | const std::vector<u8> nfc_buffer_data = SerializeMifareReadPackage(nfc_data); | ||
| 466 | std::span<const u8> buffer(nfc_buffer_data); | ||
| 467 | DriverResult result = DriverResult::Success; | ||
| 468 | MCUCommandResponse output{}; | ||
| 469 | u8 block_id = 1; | ||
| 470 | u8 package_index = 0; | ||
| 471 | std::size_t tries = 0; | ||
| 472 | std::size_t current_position = 0; | ||
| 473 | |||
| 474 | LOG_INFO(Input, "Reading Mifare data"); | ||
| 475 | |||
| 476 | // Send data request. Nfc buffer size is 31, Send the data in smaller packages | ||
| 477 | while (current_position < buffer.size() && tries++ < timeout_limit) { | ||
| 478 | const std::size_t next_position = | ||
| 479 | std::min(current_position + sizeof(NFCRequestState::raw_data), buffer.size()); | ||
| 480 | const std::size_t block_size = next_position - current_position; | ||
| 481 | const bool is_last_packet = block_size < sizeof(NFCRequestState::raw_data); | ||
| 482 | |||
| 483 | SendReadDataMifareRequest(output, block_id, is_last_packet, | ||
| 484 | buffer.subspan(current_position, block_size)); | ||
| 485 | |||
| 486 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); | ||
| 487 | |||
| 488 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { | ||
| 489 | return DriverResult::ErrorReadingData; | ||
| 490 | } | ||
| 491 | |||
| 492 | // Increase position when data is confirmed by the joycon | ||
| 493 | if (output.mcu_report == MCUReport::NFCState && | ||
| 494 | (output.mcu_data[1] << 8) + output.mcu_data[0] == 0x0500 && | ||
| 495 | output.mcu_data[3] == block_id) { | ||
| 496 | block_id++; | ||
| 497 | current_position = next_position; | ||
| 498 | } | ||
| 499 | } | ||
| 500 | |||
| 501 | if (result != DriverResult::Success) { | ||
| 502 | return result; | ||
| 503 | } | ||
| 504 | |||
| 505 | // Wait for reply and save the output data | ||
| 506 | while (tries++ < timeout_limit) { | ||
| 507 | result = SendNextPackageRequest(output, package_index); | ||
| 508 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); | ||
| 509 | |||
| 510 | if (result != DriverResult::Success) { | ||
| 511 | return result; | ||
| 512 | } | ||
| 513 | |||
| 514 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { | ||
| 515 | return DriverResult::ErrorReadingData; | ||
| 516 | } | ||
| 517 | |||
| 518 | if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { | ||
| 519 | constexpr std::size_t DATA_LENGHT = 0x10 + 1; | ||
| 520 | constexpr std::size_t DATA_START = 11; | ||
| 521 | const u8 number_of_elements = output.mcu_data[10]; | ||
| 522 | for (std::size_t i = 0; i < number_of_elements; i++) { | ||
| 523 | out_data[i].sector = output.mcu_data[DATA_START + (i * DATA_LENGHT)]; | ||
| 524 | memcpy(out_data[i].data.data(), | ||
| 525 | output.mcu_data.data() + DATA_START + 1 + (i * DATA_LENGHT), | ||
| 526 | sizeof(MifareReadData::data)); | ||
| 527 | } | ||
| 528 | package_index++; | ||
| 529 | continue; | ||
| 530 | } | ||
| 531 | |||
| 532 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::MifareDone) { | ||
| 533 | LOG_INFO(Input, "Finished reading mifare"); | ||
| 534 | break; | ||
| 535 | } | ||
| 536 | } | ||
| 537 | |||
| 538 | return result; | ||
| 539 | } | ||
| 540 | |||
| 541 | DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid, | ||
| 542 | std::span<const MifareWriteChunk> write_request) { | ||
| 543 | constexpr std::size_t timeout_limit = 60; | ||
| 544 | const auto nfc_data = MakeMifareWritePackage(tag_uuid, write_request); | ||
| 545 | const std::vector<u8> nfc_buffer_data = SerializeMifareWritePackage(nfc_data); | ||
| 546 | std::span<const u8> buffer(nfc_buffer_data); | ||
| 547 | DriverResult result = DriverResult::Success; | ||
| 548 | MCUCommandResponse output{}; | ||
| 549 | u8 block_id = 1; | ||
| 550 | u8 package_index = 0; | ||
| 551 | std::size_t tries = 0; | ||
| 552 | std::size_t current_position = 0; | ||
| 553 | |||
| 554 | LOG_INFO(Input, "Writing Mifare data"); | ||
| 555 | |||
| 556 | // Send data request. Nfc buffer size is 31, Send the data in smaller packages | ||
| 557 | while (current_position < buffer.size() && tries++ < timeout_limit) { | ||
| 558 | const std::size_t next_position = | ||
| 559 | std::min(current_position + sizeof(NFCRequestState::raw_data), buffer.size()); | ||
| 560 | const std::size_t block_size = next_position - current_position; | ||
| 561 | const bool is_last_packet = block_size < sizeof(NFCRequestState::raw_data); | ||
| 562 | |||
| 563 | SendReadDataMifareRequest(output, block_id, is_last_packet, | ||
| 564 | buffer.subspan(current_position, block_size)); | ||
| 565 | |||
| 566 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); | ||
| 567 | |||
| 568 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { | ||
| 569 | return DriverResult::ErrorReadingData; | ||
| 570 | } | ||
| 571 | |||
| 572 | // Increase position when data is confirmed by the joycon | ||
| 573 | if (output.mcu_report == MCUReport::NFCState && | ||
| 574 | (output.mcu_data[1] << 8) + output.mcu_data[0] == 0x0500 && | ||
| 575 | output.mcu_data[3] == block_id) { | ||
| 576 | block_id++; | ||
| 577 | current_position = next_position; | ||
| 578 | } | ||
| 579 | } | ||
| 580 | |||
| 581 | if (result != DriverResult::Success) { | ||
| 582 | return result; | ||
| 583 | } | ||
| 584 | |||
| 585 | // Wait for reply and ignore the output data | ||
| 586 | while (tries++ < timeout_limit) { | ||
| 587 | result = SendNextPackageRequest(output, package_index); | ||
| 588 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); | ||
| 589 | |||
| 590 | if (result != DriverResult::Success) { | ||
| 591 | return result; | ||
| 592 | } | ||
| 593 | |||
| 594 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { | ||
| 595 | return DriverResult::ErrorReadingData; | ||
| 596 | } | ||
| 597 | |||
| 598 | if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { | ||
| 599 | package_index++; | ||
| 600 | continue; | ||
| 601 | } | ||
| 602 | |||
| 603 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::MifareDone) { | ||
| 604 | LOG_INFO(Input, "Finished writing mifare"); | ||
| 605 | break; | ||
| 606 | } | ||
| 607 | } | ||
| 608 | |||
| 609 | return result; | ||
| 610 | } | ||
| 611 | |||
| 344 | DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output, | 612 | DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output, |
| 345 | bool is_second_attempt) { | 613 | bool is_second_attempt) { |
| 346 | NFCRequestState request{ | 614 | NFCRequestState request{ |
| @@ -477,6 +745,28 @@ DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output, | |||
| 477 | output); | 745 | output); |
| 478 | } | 746 | } |
| 479 | 747 | ||
| 748 | DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id, | ||
| 749 | bool is_last_packet, std::span<const u8> data) { | ||
| 750 | const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data)); | ||
| 751 | NFCRequestState request{ | ||
| 752 | .command_argument = NFCCommand::Mifare, | ||
| 753 | .block_id = block_id, | ||
| 754 | .packet_id = {}, | ||
| 755 | .packet_flag = | ||
| 756 | is_last_packet ? MCUPacketFlag::LastCommandPacket : MCUPacketFlag::MorePacketsRemaining, | ||
| 757 | .data_length = static_cast<u8>(data_size), | ||
| 758 | .raw_data = {}, | ||
| 759 | .crc = {}, | ||
| 760 | }; | ||
| 761 | memcpy(request.raw_data.data(), data.data(), data_size); | ||
| 762 | |||
| 763 | std::array<u8, sizeof(NFCRequestState)> request_data{}; | ||
| 764 | memcpy(request_data.data(), &request, sizeof(NFCRequestState)); | ||
| 765 | request_data[36] = CalculateMCU_CRC8(request_data.data(), 36); | ||
| 766 | return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, MCUSubCommand::ReadDeviceMode, request_data, | ||
| 767 | output); | ||
| 768 | } | ||
| 769 | |||
| 480 | std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& package) const { | 770 | std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& package) const { |
| 481 | const std::size_t header_size = | 771 | const std::size_t header_size = |
| 482 | sizeof(NFCWriteCommandData) + sizeof(NFCWritePackage::number_of_chunks); | 772 | sizeof(NFCWriteCommandData) + sizeof(NFCWritePackage::number_of_chunks); |
| @@ -498,6 +788,48 @@ std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& packag | |||
| 498 | return serialized_data; | 788 | return serialized_data; |
| 499 | } | 789 | } |
| 500 | 790 | ||
| 791 | std::vector<u8> NfcProtocol::SerializeMifareReadPackage(const MifareReadPackage& package) const { | ||
| 792 | const std::size_t header_size = sizeof(MifareCommandData); | ||
| 793 | std::vector<u8> serialized_data(header_size); | ||
| 794 | std::size_t start_index = 0; | ||
| 795 | |||
| 796 | memcpy(serialized_data.data(), &package, header_size); | ||
| 797 | start_index += header_size; | ||
| 798 | |||
| 799 | for (const auto& data_chunk : package.data_chunks) { | ||
| 800 | const std::size_t chunk_size = sizeof(MifareReadChunk); | ||
| 801 | if (data_chunk.command == MifareCmd::None) { | ||
| 802 | continue; | ||
| 803 | } | ||
| 804 | serialized_data.resize(start_index + chunk_size); | ||
| 805 | memcpy(serialized_data.data() + start_index, &data_chunk, chunk_size); | ||
| 806 | start_index += chunk_size; | ||
| 807 | } | ||
| 808 | |||
| 809 | return serialized_data; | ||
| 810 | } | ||
| 811 | |||
| 812 | std::vector<u8> NfcProtocol::SerializeMifareWritePackage(const MifareWritePackage& package) const { | ||
| 813 | const std::size_t header_size = sizeof(MifareCommandData); | ||
| 814 | std::vector<u8> serialized_data(header_size); | ||
| 815 | std::size_t start_index = 0; | ||
| 816 | |||
| 817 | memcpy(serialized_data.data(), &package, header_size); | ||
| 818 | start_index += header_size; | ||
| 819 | |||
| 820 | for (const auto& data_chunk : package.data_chunks) { | ||
| 821 | const std::size_t chunk_size = sizeof(MifareWriteChunk); | ||
| 822 | if (data_chunk.command == MifareCmd::None) { | ||
| 823 | continue; | ||
| 824 | } | ||
| 825 | serialized_data.resize(start_index + chunk_size); | ||
| 826 | memcpy(serialized_data.data() + start_index, &data_chunk, chunk_size); | ||
| 827 | start_index += chunk_size; | ||
| 828 | } | ||
| 829 | |||
| 830 | return serialized_data; | ||
| 831 | } | ||
| 832 | |||
| 501 | NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid, | 833 | NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid, |
| 502 | std::span<const u8> data) const { | 834 | std::span<const u8> data) const { |
| 503 | return { | 835 | return { |
| @@ -527,6 +859,46 @@ NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid, | |||
| 527 | }; | 859 | }; |
| 528 | } | 860 | } |
| 529 | 861 | ||
| 862 | MifareReadPackage NfcProtocol::MakeMifareReadPackage( | ||
| 863 | const MifareUUID& tag_uuid, std::span<const MifareReadChunk> read_request) const { | ||
| 864 | MifareReadPackage package{ | ||
| 865 | .command_data{ | ||
| 866 | .unknown1 = 0xd0, | ||
| 867 | .unknown2 = 0x07, | ||
| 868 | .number_of_short_bytes = static_cast<u8>( | ||
| 869 | ((read_request.size() * sizeof(MifareReadChunk)) + sizeof(MifareUUID)) / 2), | ||
| 870 | .uid = tag_uuid, | ||
| 871 | }, | ||
| 872 | .data_chunks = {}, | ||
| 873 | }; | ||
| 874 | |||
| 875 | for (std::size_t i = 0; i < read_request.size() && i < package.data_chunks.size(); ++i) { | ||
| 876 | package.data_chunks[i] = read_request[i]; | ||
| 877 | } | ||
| 878 | |||
| 879 | return package; | ||
| 880 | } | ||
| 881 | |||
| 882 | MifareWritePackage NfcProtocol::MakeMifareWritePackage( | ||
| 883 | const MifareUUID& tag_uuid, std::span<const MifareWriteChunk> read_request) const { | ||
| 884 | MifareWritePackage package{ | ||
| 885 | .command_data{ | ||
| 886 | .unknown1 = 0xd0, | ||
| 887 | .unknown2 = 0x07, | ||
| 888 | .number_of_short_bytes = static_cast<u8>( | ||
| 889 | ((read_request.size() * sizeof(MifareReadChunk)) + sizeof(MifareUUID) + 2) / 2), | ||
| 890 | .uid = tag_uuid, | ||
| 891 | }, | ||
| 892 | .data_chunks = {}, | ||
| 893 | }; | ||
| 894 | |||
| 895 | for (std::size_t i = 0; i < read_request.size() && i < package.data_chunks.size(); ++i) { | ||
| 896 | package.data_chunks[i] = read_request[i]; | ||
| 897 | } | ||
| 898 | |||
| 899 | return package; | ||
| 900 | } | ||
| 901 | |||
| 530 | NFCDataChunk NfcProtocol::MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const { | 902 | NFCDataChunk NfcProtocol::MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const { |
| 531 | constexpr u8 NFC_PAGE_SIZE = 4; | 903 | constexpr u8 NFC_PAGE_SIZE = 4; |
| 532 | 904 | ||
| @@ -606,4 +978,8 @@ bool NfcProtocol::IsEnabled() const { | |||
| 606 | return is_enabled; | 978 | return is_enabled; |
| 607 | } | 979 | } |
| 608 | 980 | ||
| 981 | bool NfcProtocol::IsPolling() const { | ||
| 982 | return is_polling; | ||
| 983 | } | ||
| 984 | |||
| 609 | } // namespace InputCommon::Joycon | 985 | } // 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..0be95e40e 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.h +++ b/src/input_common/helpers/joycon_protocol/nfc.h | |||
| @@ -25,14 +25,25 @@ public: | |||
| 25 | 25 | ||
| 26 | DriverResult StartNFCPollingMode(); | 26 | DriverResult StartNFCPollingMode(); |
| 27 | 27 | ||
| 28 | DriverResult ScanAmiibo(std::vector<u8>& data); | 28 | DriverResult StopNFCPollingMode(); |
| 29 | |||
| 30 | DriverResult GetTagInfo(Joycon::TagInfo& tag_info); | ||
| 31 | |||
| 32 | DriverResult ReadAmiibo(std::vector<u8>& data); | ||
| 29 | 33 | ||
| 30 | DriverResult WriteAmiibo(std::span<const u8> data); | 34 | DriverResult WriteAmiibo(std::span<const u8> data); |
| 31 | 35 | ||
| 36 | DriverResult ReadMifare(std::span<const MifareReadChunk> read_request, | ||
| 37 | std::span<MifareReadData> out_data); | ||
| 38 | |||
| 39 | DriverResult WriteMifare(std::span<const MifareWriteChunk> write_request); | ||
| 40 | |||
| 32 | bool HasAmiibo(); | 41 | bool HasAmiibo(); |
| 33 | 42 | ||
| 34 | bool IsEnabled() const; | 43 | bool IsEnabled() const; |
| 35 | 44 | ||
| 45 | bool IsPolling() const; | ||
| 46 | |||
| 36 | private: | 47 | private: |
| 37 | // Number of times the function will be delayed until it outputs valid data | 48 | // Number of times the function will be delayed until it outputs valid data |
| 38 | static constexpr std::size_t AMIIBO_UPDATE_DELAY = 15; | 49 | static constexpr std::size_t AMIIBO_UPDATE_DELAY = 15; |
| @@ -51,6 +62,13 @@ private: | |||
| 51 | 62 | ||
| 52 | DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data); | 63 | DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data); |
| 53 | 64 | ||
| 65 | DriverResult GetMifareData(const MifareUUID& tag_uuid, | ||
| 66 | std::span<const MifareReadChunk> read_request, | ||
| 67 | std::span<MifareReadData> out_data); | ||
| 68 | |||
| 69 | DriverResult WriteMifareData(const MifareUUID& tag_uuid, | ||
| 70 | std::span<const MifareWriteChunk> write_request); | ||
| 71 | |||
| 54 | DriverResult SendStartPollingRequest(MCUCommandResponse& output, | 72 | DriverResult SendStartPollingRequest(MCUCommandResponse& output, |
| 55 | bool is_second_attempt = false); | 73 | bool is_second_attempt = false); |
| 56 | 74 | ||
| @@ -65,17 +83,31 @@ private: | |||
| 65 | DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, | 83 | DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, |
| 66 | bool is_last_packet, std::span<const u8> data); | 84 | bool is_last_packet, std::span<const u8> data); |
| 67 | 85 | ||
| 86 | DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id, | ||
| 87 | bool is_last_packet, std::span<const u8> data); | ||
| 88 | |||
| 68 | std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const; | 89 | std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const; |
| 69 | 90 | ||
| 91 | std::vector<u8> SerializeMifareReadPackage(const MifareReadPackage& package) const; | ||
| 92 | |||
| 93 | std::vector<u8> SerializeMifareWritePackage(const MifareWritePackage& package) const; | ||
| 94 | |||
| 70 | NFCWritePackage MakeAmiiboWritePackage(const TagUUID& tag_uuid, std::span<const u8> data) const; | 95 | NFCWritePackage MakeAmiiboWritePackage(const TagUUID& tag_uuid, std::span<const u8> data) const; |
| 71 | 96 | ||
| 72 | NFCDataChunk MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const; | 97 | NFCDataChunk MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const; |
| 73 | 98 | ||
| 99 | MifareReadPackage MakeMifareReadPackage(const MifareUUID& tag_uuid, | ||
| 100 | std::span<const MifareReadChunk> read_request) const; | ||
| 101 | |||
| 102 | MifareWritePackage MakeMifareWritePackage(const MifareUUID& tag_uuid, | ||
| 103 | std::span<const MifareWriteChunk> read_request) const; | ||
| 104 | |||
| 74 | NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const; | 105 | NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const; |
| 75 | 106 | ||
| 76 | TagUUID GetTagUUID(std::span<const u8> data) const; | 107 | TagUUID GetTagUUID(std::span<const u8> data) const; |
| 77 | 108 | ||
| 78 | bool is_enabled{}; | 109 | bool is_enabled{}; |
| 110 | bool is_polling{}; | ||
| 79 | std::size_t update_counter{}; | 111 | std::size_t update_counter{}; |
| 80 | }; | 112 | }; |
| 81 | 113 | ||
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/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/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/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/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..bc1eb41e7 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,32 @@ 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.ReadBlockUnsafe( |
| 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.ReadBlockUnsafe(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.ReadBlockUnsafe(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 | memory_manager.WriteBlockCached(regs.offset_out, read_buffer.data(), |
| 155 | regs.line_length_in); | 157 | regs.line_length_in); |
| 156 | } | 158 | } |
| 157 | } | 159 | } |
| @@ -171,7 +173,8 @@ void MaxwellDMA::CopyBlockLinearToPitch() { | |||
| 171 | src_operand.address = regs.offset_in; | 173 | src_operand.address = regs.offset_in; |
| 172 | 174 | ||
| 173 | DMA::BufferOperand dst_operand; | 175 | DMA::BufferOperand dst_operand; |
| 174 | dst_operand.pitch = regs.pitch_out; | 176 | u32 abs_pitch_out = std::abs(static_cast<s32>(regs.pitch_out)); |
| 177 | dst_operand.pitch = abs_pitch_out; | ||
| 175 | dst_operand.width = regs.line_length_in; | 178 | dst_operand.width = regs.line_length_in; |
| 176 | dst_operand.height = regs.line_count; | 179 | dst_operand.height = regs.line_count; |
| 177 | dst_operand.address = regs.offset_out; | 180 | dst_operand.address = regs.offset_out; |
| @@ -218,7 +221,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() { | |||
| 218 | const size_t src_size = | 221 | const size_t src_size = |
| 219 | CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth); | 222 | CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth); |
| 220 | 223 | ||
| 221 | const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count; | 224 | const size_t dst_size = static_cast<size_t>(abs_pitch_out) * regs.line_count; |
| 222 | read_buffer.resize_destructive(src_size); | 225 | read_buffer.resize_destructive(src_size); |
| 223 | write_buffer.resize_destructive(dst_size); | 226 | write_buffer.resize_destructive(dst_size); |
| 224 | 227 | ||
| @@ -227,7 +230,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() { | |||
| 227 | 230 | ||
| 228 | UnswizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset, | 231 | 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, | 232 | src_params.origin.y, x_elements, regs.line_count, block_height, block_depth, |
| 230 | regs.pitch_out); | 233 | abs_pitch_out); |
| 231 | 234 | ||
| 232 | memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size); | 235 | memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size); |
| 233 | } | 236 | } |
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/memory_manager.cpp b/src/video_core/memory_manager.cpp index b2f7e160a..45141e488 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp | |||
| @@ -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_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_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index e30fcb1ed..f47301ad5 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp | |||
| @@ -361,7 +361,7 @@ void BufferCacheRuntime::CopyBuffer(VkBuffer dst_buffer, VkBuffer src_buffer, | |||
| 361 | .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, | 361 | .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, |
| 362 | }; | 362 | }; |
| 363 | // Measuring a popular game, this number never exceeds the specified size once data is warmed up | 363 | // 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()); | 364 | boost::container::small_vector<VkBufferCopy, 8> vk_copies(copies.size()); |
| 365 | std::ranges::transform(copies, vk_copies.begin(), MakeBufferCopy); | 365 | std::ranges::transform(copies, vk_copies.begin(), MakeBufferCopy); |
| 366 | scheduler.RequestOutsideRenderPassOperationContext(); | 366 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 367 | scheduler.Record([src_buffer, dst_buffer, vk_copies, barrier](vk::CommandBuffer cmdbuf) { | 367 | scheduler.Record([src_buffer, dst_buffer, vk_copies, barrier](vk::CommandBuffer cmdbuf) { |
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 a2cfb2105..9f316113c 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; |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index f025f618b..f3cef09dd 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -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 | } |
| @@ -867,8 +867,8 @@ void TextureCacheRuntime::BarrierFeedbackLoop() { | |||
| 867 | 867 | ||
| 868 | void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src, | 868 | void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src, |
| 869 | std::span<const VideoCommon::ImageCopy> copies) { | 869 | std::span<const VideoCommon::ImageCopy> copies) { |
| 870 | std::vector<VkBufferImageCopy> vk_in_copies(copies.size()); | 870 | boost::container::small_vector<VkBufferImageCopy, 16> vk_in_copies(copies.size()); |
| 871 | std::vector<VkBufferImageCopy> vk_out_copies(copies.size()); | 871 | boost::container::small_vector<VkBufferImageCopy, 16> vk_out_copies(copies.size()); |
| 872 | const VkImageAspectFlags src_aspect_mask = src.AspectMask(); | 872 | const VkImageAspectFlags src_aspect_mask = src.AspectMask(); |
| 873 | const VkImageAspectFlags dst_aspect_mask = dst.AspectMask(); | 873 | const VkImageAspectFlags dst_aspect_mask = dst.AspectMask(); |
| 874 | 874 | ||
| @@ -1157,7 +1157,7 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im | |||
| 1157 | 1157 | ||
| 1158 | void TextureCacheRuntime::CopyImage(Image& dst, Image& src, | 1158 | void TextureCacheRuntime::CopyImage(Image& dst, Image& src, |
| 1159 | std::span<const VideoCommon::ImageCopy> copies) { | 1159 | std::span<const VideoCommon::ImageCopy> copies) { |
| 1160 | std::vector<VkImageCopy> vk_copies(copies.size()); | 1160 | boost::container::small_vector<VkImageCopy, 16> vk_copies(copies.size()); |
| 1161 | const VkImageAspectFlags aspect_mask = dst.AspectMask(); | 1161 | const VkImageAspectFlags aspect_mask = dst.AspectMask(); |
| 1162 | ASSERT(aspect_mask == src.AspectMask()); | 1162 | ASSERT(aspect_mask == src.AspectMask()); |
| 1163 | 1163 | ||
| @@ -1332,7 +1332,7 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset, | |||
| 1332 | ScaleDown(true); | 1332 | ScaleDown(true); |
| 1333 | } | 1333 | } |
| 1334 | scheduler->RequestOutsideRenderPassOperationContext(); | 1334 | scheduler->RequestOutsideRenderPassOperationContext(); |
| 1335 | std::vector vk_copies = TransformBufferImageCopies(copies, offset, aspect_mask); | 1335 | auto vk_copies = TransformBufferImageCopies(copies, offset, aspect_mask); |
| 1336 | const VkBuffer src_buffer = buffer; | 1336 | const VkBuffer src_buffer = buffer; |
| 1337 | const VkImage vk_image = *original_image; | 1337 | const VkImage vk_image = *original_image; |
| 1338 | const VkImageAspectFlags vk_aspect_mask = aspect_mask; | 1338 | const VkImageAspectFlags vk_aspect_mask = aspect_mask; |
| @@ -1367,8 +1367,9 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<VkDeviceS | |||
| 1367 | if (is_rescaled) { | 1367 | if (is_rescaled) { |
| 1368 | ScaleDown(); | 1368 | ScaleDown(); |
| 1369 | } | 1369 | } |
| 1370 | boost::container::small_vector<VkBuffer, 1> buffers_vector{}; | 1370 | boost::container::small_vector<VkBuffer, 8> buffers_vector{}; |
| 1371 | boost::container::small_vector<std::vector<VkBufferImageCopy>, 1> vk_copies; | 1371 | boost::container::small_vector<boost::container::small_vector<VkBufferImageCopy, 16>, 8> |
| 1372 | vk_copies; | ||
| 1372 | for (size_t index = 0; index < buffers_span.size(); index++) { | 1373 | for (size_t index = 0; index < buffers_span.size(); index++) { |
| 1373 | buffers_vector.emplace_back(buffers_span[index]); | 1374 | buffers_vector.emplace_back(buffers_span[index]); |
| 1374 | vk_copies.emplace_back( | 1375 | vk_copies.emplace_back( |
| @@ -1858,7 +1859,7 @@ Framebuffer::~Framebuffer() = default; | |||
| 1858 | void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, | 1859 | void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, |
| 1859 | std::span<ImageView*, NUM_RT> color_buffers, | 1860 | std::span<ImageView*, NUM_RT> color_buffers, |
| 1860 | ImageView* depth_buffer, bool is_rescaled) { | 1861 | ImageView* depth_buffer, bool is_rescaled) { |
| 1861 | std::vector<VkImageView> attachments; | 1862 | boost::container::small_vector<VkImageView, NUM_RT + 1> attachments; |
| 1862 | RenderPassKey renderpass_key{}; | 1863 | RenderPassKey renderpass_key{}; |
| 1863 | s32 num_layers = 1; | 1864 | s32 num_layers = 1; |
| 1864 | 1865 | ||
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/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 d25339c8c..d3f03a995 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) { |
| @@ -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,7 +593,7 @@ 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) { |
| @@ -1097,7 +1101,7 @@ ImageId TextureCache<P>::FindImage(const ImageInfo& info, GPUVAddr gpu_addr, | |||
| 1097 | const bool native_bgr = runtime.HasNativeBgr(); | 1101 | const bool native_bgr = runtime.HasNativeBgr(); |
| 1098 | const bool flexible_formats = True(options & RelaxedOptions::Format); | 1102 | const bool flexible_formats = True(options & RelaxedOptions::Format); |
| 1099 | ImageId image_id{}; | 1103 | ImageId image_id{}; |
| 1100 | boost::container::small_vector<ImageId, 1> image_ids; | 1104 | boost::container::small_vector<ImageId, 8> image_ids; |
| 1101 | const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) { | 1105 | const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) { |
| 1102 | if (True(existing_image.flags & ImageFlagBits::Remapped)) { | 1106 | if (True(existing_image.flags & ImageFlagBits::Remapped)) { |
| 1103 | return false; | 1107 | return false; |
| @@ -1618,7 +1622,7 @@ ImageId TextureCache<P>::FindDMAImage(const ImageInfo& info, GPUVAddr gpu_addr) | |||
| 1618 | } | 1622 | } |
| 1619 | } | 1623 | } |
| 1620 | ImageId image_id{}; | 1624 | ImageId image_id{}; |
| 1621 | boost::container::small_vector<ImageId, 1> image_ids; | 1625 | boost::container::small_vector<ImageId, 8> image_ids; |
| 1622 | const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) { | 1626 | const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) { |
| 1623 | if (True(existing_image.flags & ImageFlagBits::Remapped)) { | 1627 | if (True(existing_image.flags & ImageFlagBits::Remapped)) { |
| 1624 | return false; | 1628 | return false; |
| @@ -1938,7 +1942,7 @@ void TextureCache<P>::RegisterImage(ImageId image_id) { | |||
| 1938 | image.map_view_id = map_id; | 1942 | image.map_view_id = map_id; |
| 1939 | return; | 1943 | return; |
| 1940 | } | 1944 | } |
| 1941 | std::vector<ImageViewId> sparse_maps{}; | 1945 | boost::container::small_vector<ImageViewId, 16> sparse_maps; |
| 1942 | ForEachSparseSegment( | 1946 | ForEachSparseSegment( |
| 1943 | image, [this, image_id, &sparse_maps](GPUVAddr gpu_addr, VAddr cpu_addr, size_t size) { | 1947 | image, [this, image_id, &sparse_maps](GPUVAddr gpu_addr, VAddr cpu_addr, size_t size) { |
| 1944 | auto map_id = slot_map_views.insert(gpu_addr, cpu_addr, size, image_id); | 1948 | auto map_id = slot_map_views.insert(gpu_addr, cpu_addr, size, image_id); |
| @@ -2213,7 +2217,7 @@ void TextureCache<P>::MarkModification(ImageBase& image) noexcept { | |||
| 2213 | 2217 | ||
| 2214 | template <class P> | 2218 | template <class P> |
| 2215 | void TextureCache<P>::SynchronizeAliases(ImageId image_id) { | 2219 | void TextureCache<P>::SynchronizeAliases(ImageId image_id) { |
| 2216 | boost::container::small_vector<const AliasedImage*, 1> aliased_images; | 2220 | boost::container::small_vector<const AliasedImage*, 8> aliased_images; |
| 2217 | Image& image = slot_images[image_id]; | 2221 | Image& image = slot_images[image_id]; |
| 2218 | bool any_rescaled = True(image.flags & ImageFlagBits::Rescaled); | 2222 | bool any_rescaled = True(image.flags & ImageFlagBits::Rescaled); |
| 2219 | bool any_modified = True(image.flags & ImageFlagBits::GpuModified); | 2223 | 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 44232b961..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 | }; |
| @@ -429,7 +429,7 @@ private: | |||
| 429 | 429 | ||
| 430 | 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; |
| 431 | 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; |
| 432 | std::unordered_map<ImageId, std::vector<ImageViewId>> sparse_views; | 432 | std::unordered_map<ImageId, boost::container::small_vector<ImageViewId, 16>> sparse_views; |
| 433 | 433 | ||
| 434 | VAddr virtual_invalid_space{}; | 434 | VAddr virtual_invalid_space{}; |
| 435 | 435 | ||
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index 95a5b47d8..f781cb7a0 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp | |||
| @@ -329,13 +329,13 @@ template <u32 GOB_EXTENT> | |||
| 329 | 329 | ||
| 330 | [[nodiscard]] std::optional<SubresourceExtent> ResolveOverlapRightAddress3D( | 330 | [[nodiscard]] std::optional<SubresourceExtent> ResolveOverlapRightAddress3D( |
| 331 | const ImageInfo& new_info, GPUVAddr gpu_addr, const ImageBase& overlap, bool strict_size) { | 331 | const ImageInfo& new_info, GPUVAddr gpu_addr, const ImageBase& overlap, bool strict_size) { |
| 332 | const std::vector<u32> slice_offsets = CalculateSliceOffsets(new_info); | 332 | const auto slice_offsets = CalculateSliceOffsets(new_info); |
| 333 | const u32 diff = static_cast<u32>(overlap.gpu_addr - gpu_addr); | 333 | const u32 diff = static_cast<u32>(overlap.gpu_addr - gpu_addr); |
| 334 | const auto it = std::ranges::find(slice_offsets, diff); | 334 | const auto it = std::ranges::find(slice_offsets, diff); |
| 335 | if (it == slice_offsets.end()) { | 335 | if (it == slice_offsets.end()) { |
| 336 | return std::nullopt; | 336 | return std::nullopt; |
| 337 | } | 337 | } |
| 338 | const std::vector subresources = CalculateSliceSubresources(new_info); | 338 | const auto subresources = CalculateSliceSubresources(new_info); |
| 339 | const SubresourceBase base = subresources[std::distance(slice_offsets.begin(), it)]; | 339 | const SubresourceBase base = subresources[std::distance(slice_offsets.begin(), it)]; |
| 340 | const ImageInfo& info = overlap.info; | 340 | const ImageInfo& info = overlap.info; |
| 341 | if (!IsBlockLinearSizeCompatible(new_info, info, base.level, 0, strict_size)) { | 341 | if (!IsBlockLinearSizeCompatible(new_info, info, base.level, 0, strict_size)) { |
| @@ -655,9 +655,9 @@ LevelArray CalculateMipLevelSizes(const ImageInfo& info) noexcept { | |||
| 655 | return sizes; | 655 | return sizes; |
| 656 | } | 656 | } |
| 657 | 657 | ||
| 658 | std::vector<u32> CalculateSliceOffsets(const ImageInfo& info) { | 658 | boost::container::small_vector<u32, 16> CalculateSliceOffsets(const ImageInfo& info) { |
| 659 | ASSERT(info.type == ImageType::e3D); | 659 | ASSERT(info.type == ImageType::e3D); |
| 660 | std::vector<u32> offsets; | 660 | boost::container::small_vector<u32, 16> offsets; |
| 661 | offsets.reserve(NumSlices(info)); | 661 | offsets.reserve(NumSlices(info)); |
| 662 | 662 | ||
| 663 | const LevelInfo level_info = MakeLevelInfo(info); | 663 | const LevelInfo level_info = MakeLevelInfo(info); |
| @@ -679,9 +679,10 @@ std::vector<u32> CalculateSliceOffsets(const ImageInfo& info) { | |||
| 679 | return offsets; | 679 | return offsets; |
| 680 | } | 680 | } |
| 681 | 681 | ||
| 682 | std::vector<SubresourceBase> CalculateSliceSubresources(const ImageInfo& info) { | 682 | boost::container::small_vector<SubresourceBase, 16> CalculateSliceSubresources( |
| 683 | const ImageInfo& info) { | ||
| 683 | ASSERT(info.type == ImageType::e3D); | 684 | ASSERT(info.type == ImageType::e3D); |
| 684 | std::vector<SubresourceBase> subresources; | 685 | boost::container::small_vector<SubresourceBase, 16> subresources; |
| 685 | subresources.reserve(NumSlices(info)); | 686 | subresources.reserve(NumSlices(info)); |
| 686 | for (s32 level = 0; level < info.resources.levels; ++level) { | 687 | for (s32 level = 0; level < info.resources.levels; ++level) { |
| 687 | const s32 depth = AdjustMipSize(info.size.depth, level); | 688 | const s32 depth = AdjustMipSize(info.size.depth, level); |
| @@ -723,8 +724,10 @@ ImageViewType RenderTargetImageViewType(const ImageInfo& info) noexcept { | |||
| 723 | } | 724 | } |
| 724 | } | 725 | } |
| 725 | 726 | ||
| 726 | std::vector<ImageCopy> MakeShrinkImageCopies(const ImageInfo& dst, const ImageInfo& src, | 727 | boost::container::small_vector<ImageCopy, 16> MakeShrinkImageCopies(const ImageInfo& dst, |
| 727 | SubresourceBase base, u32 up_scale, u32 down_shift) { | 728 | const ImageInfo& src, |
| 729 | SubresourceBase base, | ||
| 730 | u32 up_scale, u32 down_shift) { | ||
| 728 | ASSERT(dst.resources.levels >= src.resources.levels); | 731 | ASSERT(dst.resources.levels >= src.resources.levels); |
| 729 | 732 | ||
| 730 | const bool is_dst_3d = dst.type == ImageType::e3D; | 733 | const bool is_dst_3d = dst.type == ImageType::e3D; |
| @@ -733,7 +736,7 @@ std::vector<ImageCopy> MakeShrinkImageCopies(const ImageInfo& dst, const ImageIn | |||
| 733 | ASSERT(src.resources.levels == 1); | 736 | ASSERT(src.resources.levels == 1); |
| 734 | } | 737 | } |
| 735 | const bool both_2d{src.type == ImageType::e2D && dst.type == ImageType::e2D}; | 738 | const bool both_2d{src.type == ImageType::e2D && dst.type == ImageType::e2D}; |
| 736 | std::vector<ImageCopy> copies; | 739 | boost::container::small_vector<ImageCopy, 16> copies; |
| 737 | copies.reserve(src.resources.levels); | 740 | copies.reserve(src.resources.levels); |
| 738 | for (s32 level = 0; level < src.resources.levels; ++level) { | 741 | for (s32 level = 0; level < src.resources.levels; ++level) { |
| 739 | ImageCopy& copy = copies.emplace_back(); | 742 | ImageCopy& copy = copies.emplace_back(); |
| @@ -770,9 +773,10 @@ std::vector<ImageCopy> MakeShrinkImageCopies(const ImageInfo& dst, const ImageIn | |||
| 770 | return copies; | 773 | return copies; |
| 771 | } | 774 | } |
| 772 | 775 | ||
| 773 | std::vector<ImageCopy> MakeReinterpretImageCopies(const ImageInfo& src, u32 up_scale, | 776 | boost::container::small_vector<ImageCopy, 16> MakeReinterpretImageCopies(const ImageInfo& src, |
| 774 | u32 down_shift) { | 777 | u32 up_scale, |
| 775 | std::vector<ImageCopy> copies; | 778 | u32 down_shift) { |
| 779 | boost::container::small_vector<ImageCopy, 16> copies; | ||
| 776 | copies.reserve(src.resources.levels); | 780 | copies.reserve(src.resources.levels); |
| 777 | const bool is_3d = src.type == ImageType::e3D; | 781 | const bool is_3d = src.type == ImageType::e3D; |
| 778 | for (s32 level = 0; level < src.resources.levels; ++level) { | 782 | for (s32 level = 0; level < src.resources.levels; ++level) { |
| @@ -824,9 +828,11 @@ bool IsValidEntry(const Tegra::MemoryManager& gpu_memory, const TICEntry& config | |||
| 824 | return gpu_memory.GpuToCpuAddress(address, guest_size_bytes).has_value(); | 828 | return gpu_memory.GpuToCpuAddress(address, guest_size_bytes).has_value(); |
| 825 | } | 829 | } |
| 826 | 830 | ||
| 827 | std::vector<BufferImageCopy> UnswizzleImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, | 831 | boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::MemoryManager& gpu_memory, |
| 828 | const ImageInfo& info, std::span<const u8> input, | 832 | GPUVAddr gpu_addr, |
| 829 | std::span<u8> output) { | 833 | const ImageInfo& info, |
| 834 | std::span<const u8> input, | ||
| 835 | std::span<u8> output) { | ||
| 830 | const size_t guest_size_bytes = input.size_bytes(); | 836 | const size_t guest_size_bytes = input.size_bytes(); |
| 831 | const u32 bpp_log2 = BytesPerBlockLog2(info.format); | 837 | const u32 bpp_log2 = BytesPerBlockLog2(info.format); |
| 832 | const Extent3D size = info.size; | 838 | const Extent3D size = info.size; |
| @@ -861,7 +867,7 @@ std::vector<BufferImageCopy> UnswizzleImage(Tegra::MemoryManager& gpu_memory, GP | |||
| 861 | info.tile_width_spacing); | 867 | info.tile_width_spacing); |
| 862 | size_t guest_offset = 0; | 868 | size_t guest_offset = 0; |
| 863 | u32 host_offset = 0; | 869 | u32 host_offset = 0; |
| 864 | std::vector<BufferImageCopy> copies(num_levels); | 870 | boost::container::small_vector<BufferImageCopy, 16> copies(num_levels); |
| 865 | 871 | ||
| 866 | for (s32 level = 0; level < num_levels; ++level) { | 872 | for (s32 level = 0; level < num_levels; ++level) { |
| 867 | const Extent3D level_size = AdjustMipSize(size, level); | 873 | const Extent3D level_size = AdjustMipSize(size, level); |
| @@ -978,7 +984,7 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8 | |||
| 978 | } | 984 | } |
| 979 | } | 985 | } |
| 980 | 986 | ||
| 981 | std::vector<BufferImageCopy> FullDownloadCopies(const ImageInfo& info) { | 987 | boost::container::small_vector<BufferImageCopy, 16> FullDownloadCopies(const ImageInfo& info) { |
| 982 | const Extent3D size = info.size; | 988 | const Extent3D size = info.size; |
| 983 | const u32 bytes_per_block = BytesPerBlock(info.format); | 989 | const u32 bytes_per_block = BytesPerBlock(info.format); |
| 984 | if (info.type == ImageType::Linear) { | 990 | if (info.type == ImageType::Linear) { |
| @@ -1006,7 +1012,7 @@ std::vector<BufferImageCopy> FullDownloadCopies(const ImageInfo& info) { | |||
| 1006 | 1012 | ||
| 1007 | u32 host_offset = 0; | 1013 | u32 host_offset = 0; |
| 1008 | 1014 | ||
| 1009 | std::vector<BufferImageCopy> copies(num_levels); | 1015 | boost::container::small_vector<BufferImageCopy, 16> copies(num_levels); |
| 1010 | for (s32 level = 0; level < num_levels; ++level) { | 1016 | for (s32 level = 0; level < num_levels; ++level) { |
| 1011 | const Extent3D level_size = AdjustMipSize(size, level); | 1017 | const Extent3D level_size = AdjustMipSize(size, level); |
| 1012 | const u32 num_blocks_per_layer = NumBlocks(level_size, tile_size); | 1018 | const u32 num_blocks_per_layer = NumBlocks(level_size, tile_size); |
| @@ -1042,10 +1048,10 @@ Extent3D MipBlockSize(const ImageInfo& info, u32 level) { | |||
| 1042 | return AdjustMipBlockSize(num_tiles, level_info.block, level); | 1048 | return AdjustMipBlockSize(num_tiles, level_info.block, level); |
| 1043 | } | 1049 | } |
| 1044 | 1050 | ||
| 1045 | std::vector<SwizzleParameters> FullUploadSwizzles(const ImageInfo& info) { | 1051 | boost::container::small_vector<SwizzleParameters, 16> FullUploadSwizzles(const ImageInfo& info) { |
| 1046 | const Extent2D tile_size = DefaultBlockSize(info.format); | 1052 | const Extent2D tile_size = DefaultBlockSize(info.format); |
| 1047 | if (info.type == ImageType::Linear) { | 1053 | if (info.type == ImageType::Linear) { |
| 1048 | return std::vector{SwizzleParameters{ | 1054 | return {SwizzleParameters{ |
| 1049 | .num_tiles = AdjustTileSize(info.size, tile_size), | 1055 | .num_tiles = AdjustTileSize(info.size, tile_size), |
| 1050 | .block = {}, | 1056 | .block = {}, |
| 1051 | .buffer_offset = 0, | 1057 | .buffer_offset = 0, |
| @@ -1057,7 +1063,7 @@ std::vector<SwizzleParameters> FullUploadSwizzles(const ImageInfo& info) { | |||
| 1057 | const s32 num_levels = info.resources.levels; | 1063 | const s32 num_levels = info.resources.levels; |
| 1058 | 1064 | ||
| 1059 | u32 guest_offset = 0; | 1065 | u32 guest_offset = 0; |
| 1060 | std::vector<SwizzleParameters> params(num_levels); | 1066 | boost::container::small_vector<SwizzleParameters, 16> params(num_levels); |
| 1061 | for (s32 level = 0; level < num_levels; ++level) { | 1067 | for (s32 level = 0; level < num_levels; ++level) { |
| 1062 | const Extent3D level_size = AdjustMipSize(size, level); | 1068 | const Extent3D level_size = AdjustMipSize(size, level); |
| 1063 | const Extent3D num_tiles = AdjustTileSize(level_size, tile_size); | 1069 | 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/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_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index fa9cde75b..b11abe311 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp | |||
| @@ -316,6 +316,7 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical, | |||
| 316 | std::vector<const char*> ExtensionListForVulkan( | 316 | std::vector<const char*> ExtensionListForVulkan( |
| 317 | const std::set<std::string, std::less<>>& extensions) { | 317 | const std::set<std::string, std::less<>>& extensions) { |
| 318 | std::vector<const char*> output; | 318 | std::vector<const char*> output; |
| 319 | output.reserve(extensions.size()); | ||
| 319 | for (const auto& extension : extensions) { | 320 | for (const auto& extension : extensions) { |
| 320 | output.push_back(extension.c_str()); | 321 | output.push_back(extension.c_str()); |
| 321 | } | 322 | } |
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..edc206a25 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -761,6 +761,7 @@ void Config::ReadRendererValues() { | |||
| 761 | ReadGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); | 761 | ReadGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); |
| 762 | ReadGlobalSetting(Settings::values.enable_compute_pipelines); | 762 | ReadGlobalSetting(Settings::values.enable_compute_pipelines); |
| 763 | ReadGlobalSetting(Settings::values.use_video_framerate); | 763 | ReadGlobalSetting(Settings::values.use_video_framerate); |
| 764 | ReadGlobalSetting(Settings::values.barrier_feedback_loops); | ||
| 764 | ReadGlobalSetting(Settings::values.bg_red); | 765 | ReadGlobalSetting(Settings::values.bg_red); |
| 765 | ReadGlobalSetting(Settings::values.bg_green); | 766 | ReadGlobalSetting(Settings::values.bg_green); |
| 766 | ReadGlobalSetting(Settings::values.bg_blue); | 767 | ReadGlobalSetting(Settings::values.bg_blue); |
| @@ -1417,6 +1418,7 @@ void Config::SaveRendererValues() { | |||
| 1417 | WriteGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); | 1418 | WriteGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); |
| 1418 | WriteGlobalSetting(Settings::values.enable_compute_pipelines); | 1419 | WriteGlobalSetting(Settings::values.enable_compute_pipelines); |
| 1419 | WriteGlobalSetting(Settings::values.use_video_framerate); | 1420 | WriteGlobalSetting(Settings::values.use_video_framerate); |
| 1421 | WriteGlobalSetting(Settings::values.barrier_feedback_loops); | ||
| 1420 | WriteGlobalSetting(Settings::values.bg_red); | 1422 | WriteGlobalSetting(Settings::values.bg_red); |
| 1421 | WriteGlobalSetting(Settings::values.bg_green); | 1423 | WriteGlobalSetting(Settings::values.bg_green); |
| 1422 | WriteGlobalSetting(Settings::values.bg_blue); | 1424 | WriteGlobalSetting(Settings::values.bg_blue); |
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/main.cpp b/src/yuzu/main.cpp index 8768a7c3c..45a39451d 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -3840,7 +3840,7 @@ void GMainWindow::OnLoadAmiibo() { | |||
| 3840 | auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo(); | 3840 | auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo(); |
| 3841 | 3841 | ||
| 3842 | // Remove amiibo if one is connected | 3842 | // Remove amiibo if one is connected |
| 3843 | if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::AmiiboIsOpen) { | 3843 | if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::TagNearby) { |
| 3844 | virtual_amiibo->CloseAmiibo(); | 3844 | virtual_amiibo->CloseAmiibo(); |
| 3845 | QMessageBox::warning(this, tr("Amiibo"), tr("The current amiibo has been removed")); | 3845 | QMessageBox::warning(this, tr("Amiibo"), tr("The current amiibo has been removed")); |
| 3846 | return; | 3846 | return; |
| @@ -3868,7 +3868,7 @@ void GMainWindow::LoadAmiibo(const QString& filename) { | |||
| 3868 | auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo(); | 3868 | auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo(); |
| 3869 | const QString title = tr("Error loading Amiibo data"); | 3869 | const QString title = tr("Error loading Amiibo data"); |
| 3870 | // Remove amiibo if one is connected | 3870 | // Remove amiibo if one is connected |
| 3871 | if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::AmiiboIsOpen) { | 3871 | if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::TagNearby) { |
| 3872 | virtual_amiibo->CloseAmiibo(); | 3872 | virtual_amiibo->CloseAmiibo(); |
| 3873 | QMessageBox::warning(this, tr("Amiibo"), tr("The current amiibo has been removed")); | 3873 | QMessageBox::warning(this, tr("Amiibo"), tr("The current amiibo has been removed")); |
| 3874 | return; | 3874 | return; |